slint icon indicating copy to clipboard operation
slint copied to clipboard

Improve `Path` API

Open tronical opened this issue 3 years ago • 15 comments

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.

tronical avatar Oct 19 '22 08:10 tronical

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)

ogoffart avatar Oct 19 '22 08:10 ogoffart

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?

tronical avatar Oct 19 '22 09:10 tronical

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.

ogoffart avatar Oct 19 '22 09:10 ogoffart

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.

tronical avatar Oct 19 '22 10:10 tronical

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

Be-ing avatar Nov 19 '22 06:11 Be-ing

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 { ... }

ogoffart avatar Nov 19 '22 06:11 ogoffart

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.

Be-ing avatar Nov 19 '22 06:11 Be-ing

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 avatar Nov 30 '22 11:11 tronical

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

tronical avatar Jan 21 '23 12:01 tronical

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.

tronical avatar May 17 '23 10:05 tronical

The discussion at #1742

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

Vadoola avatar May 24 '23 20:05 Vadoola

Yes, thank you :)

tronical avatar May 25 '23 07:05 tronical

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.

jturcotte avatar Feb 01 '25 18:02 jturcotte

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.

tronical avatar Jun 17 '25 09:06 tronical

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 clip property that defaults to false. Path elements can render outside of the geometry (width/height/x/y) of the PathShape.
  • 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-rect or view box for advanced use-cases.

tronical avatar Jun 17 '25 09:06 tronical