slint
slint copied to clipboard
Improve `Path` API
The current Path API has two "modes":
- Path elements can be described using an SVG command string.
- Path elements can be described using sub-elements such as
MoveTo { ... },LineTo { ... }orArcTo { ... }.
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.
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)
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?
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.
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.
Maybe this is tangential, but it would be great if Path's commands could be generated from models like with for: #754.
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 { ... }
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.
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.
related cleanup: https://github.com/slint-ui/slint/pull/2087
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.
The discussion at #1742
Small correction, I believe you meant to link the Discussion at #2722
Yes, thank you :)
One idea that might such an improvement is to unify the coordinate systems for this second mode
I think that it would be nice to be able to create a path from a model, in which case both the first and second modes would be very similar to a model of structs with the same or almost the same commands. So maybe the distinction of which coordinate system to use should be more explicit, for example with a boolean or enum property.
Another thing that would be nice to have is a way to disable the aspect ratio preserving of the viewbox, possibly like it's currently possible using the Image's image-fit.
See this example where it's an issue when attempting to draw a chart, and the only possible workaround I see is to set the viewbox to use the containing coordinate system and scale the generated SVG commands with the Path's and viewbox's size if I want the chart to fill the Path.
edit: OK I thought about this and any decent chart would require text and some kind of aspect ratio preserving through a re-layout when the component size changes. So that would also be accomplished by having path commands generated by the application taking the logical size as input, and aspect ratio won't matter if the viewbox size matches the viewport's size.
Originating from #8276 comes a suggestion that in a new Path API, for the computation of the bounding box, it is something desirable to include/exclude aspects such as the stroke. See also corresponding JS API.
To summarize my current feeling about what an improved Path - let's call it PathShape - should be like:
- Shares coordinate system and units with the rest of the elements - so no
viewbox. - Has a
clipproperty that defaults to false. Path elements can render outside of the geometry (width/height/x/y) of thePathShape. - I think this also kind of eliminates the need to define a view box, but it would probably still make sense to offer a read-only
bounding-rectorview boxfor advanced use-cases.