slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
16.91k stars 562 forks source link

Improve `Path` API #1742

Open tronical opened 1 year ago

tronical commented 1 year ago

The current Path API has two "modes":

  1. Path elements can be described using an SVG command string.
  2. Path elements can be described using sub-elements such as MoveTo { ... }, LineTo { ... } or ArcTo { ... }.

In both cases the coordinate used in the elements are in their own path coordinate system and operate relative to the configurable viewbox.

While this works, it turns out that the second mode is inconvenient to use. This becomes apparent when looking at the UsageDiagram code in the iot dashboard: Values from the data points need to be mapped into the view box manually.

Similarly, it has come up in discussions with users that for example drawing lines that connect boxes on an arbitrary "canvas" is hard to implement with the Path element.

The objective of this issue is to explore making this API more convenient to use.

One idea that might such an improvement is to unify the coordinate systems for this second mode: The Path has x, y, width and height properties that define the position of the Path in the overall Slint canvas, and they also define the view box. Sub-elements such as MoveTo or LineTo could use regular logical lengths as units for their coordinate properties and they would be defined to be relative to their parent like always in Slint - the parent is the Path element. To complete the view box concept, the Path could be defined to clip its children by default to its own geometry.

ogoffart commented 1 year ago

Path could be defined to clip its children by default to its own geometry.

That'd be great. But Path currently can't have children. Only MoveTo, LineTo, ... "elements". Maybe we should revisit this syntax and use something like a custom @path(....) grammar Something like https://developer.mozilla.org/en-US/docs/Web/CSS/path (but this uses a string, while we could accept path(M 0 0 L foo bar)

tronical commented 1 year ago

Yes, it can't have children at run-time. But I was solely thinking in terms of syntax (and I used the wrong term, oops :).

What I mean is that I think it would be nice if this worked and draw a line from (0, 0) to (100, 100) (and clip). We could also have a clip: false;.

Path {
    width: 100px;
    height: 100px;

    MoveTo {
        x: -10px;
        y: -10px;
    }
    LineTo {
        x: 110px;
        y: 110px;
    }
}

I think this would be nice and it doesn't mean that we have to allow Text elements as children in the syntax there. Or am I missing something perhaps?

ogoffart commented 1 year ago

There is also a need to be able to clip with custom Path

Path {
    width: 100px;
    height: 100px;
    commands: "...";
    clip: true;

    Image { ... }
    Text { ... }
}

In slint, currently, each element is having a geometry and stuff, and the special commands from Path are the only odds ones. Maybe that's ok to mix commands and elements, but i still find it strange.

tronical commented 1 year ago

You're right, it's strange that Path doesn't allow Image and Text and the allowed "children" don't have the usual geometry but a LineTo's x and y has a very different meaning than x and y in an Image. That adds up to a good argument in favor of different syntax.

And the example you made the other day with proper binding expressions for the stops inside the @radial-gradient was actually quite good and readable.

Be-ing commented 1 year ago

Maybe this is tangential, but it would be great if Path's commands could be generated from models like with for: #754.

ogoffart commented 1 year ago

it would be great if Path's commands could be generated from models like with for

Workaround is to have for aa in bb: Path { ... }

Be-ing commented 1 year ago

Workaround is to have for aa in bb: Path { ... }

I don't understand how MoveTo/LineTo/ArcTo would be useful if the path gets reset with each iteration.

tronical commented 1 year ago

Currently the width and height of a Path is zero by default. We should consider revisiting this and applying perhaps 100% like we do for Rectangle.

tronical commented 1 year ago

related cleanup: https://github.com/slint-ui/slint/pull/2087

tronical commented 1 year ago

The discussion at https://github.com/slint-ui/slint/issues/1742 also yields an aspect we should improve on: The properties in the path elements don't behave like properties, i.e. they can't be animated directly, only via an intermediate property.

Vadoola commented 1 year ago

The discussion at #1742

Small correction, I believe you meant to link the Discussion at #2722

tronical commented 1 year ago

Yes, thank you :)