Hi there! Is anybody able to help with this: <http...
# compose-desktop
j
Hi there! Is anybody able to help with this: https://stackoverflow.com/questions/67383457/jetpack-compose-how-to-draw-lines-between-composables-after-the-layout-phase I want to draw lines between composables that have an unknown size until they have been laid out. Is this even possible with the single-pass architecture of Compose?
j
Usually when you have a node editor like this, you typically aren't using Compose layout constructs (like row+column) and are instead doing your own layout based on something like absolute positions of the layout nodes. This means the work doesn't need to be done within the Compose layout pass. In such a case, you do your own layout/calculations typically as part of your data layer (or maybe in your composable functions, but probably better in your data layer) and then you have a composable function that iterates over the nodes from your data layer and emits composable functions for each node/line. The nodes and lines are each their own composable function call and already have already been passed all the information they need about size and layout, so they know how to draw themselves.
j
Okay, but if I want my nodes to contain other UI elements, such as Text Fields, Sliders, etc. I would have to constrain the node's body to a defined width and height?
o
I would do it as following: • have a data structure you can iterate by index (e.g. List), which holds your “GraphNode” elements. • Each GraphNode element has composable function that produces content for the node, and it also contains placement information like IntOffset for the top left corner • You use
Layout
to place your nodes, and inside the
content
parameter generate `Box`es with the GraphNode content, so that index of children is the same as index in your nodes list • Inside Layout placement, just iterate over
measurables
which will be in order of Boxes, and place them according to respective data in GraphNode. Calculate min/max positions and set layout size accordingly, so that you can use scrollable to navigate the graph when it’s bigger than view port. • Use
drawBehind
modifier to use same data to draw lines and other adornments on a Canvas. You can basically pass information back to this modifier by having a mutable structure that you initially fill with just offsets, and then in measuring phase add sizes. Since drawing always happens after layout, you’re guaranteed to have this data when drawing lines.
👀 3
👆 1
Now, if you want lines to be composable nodes as well, like have some content there (something more complex than you can do with canvas), you can use the same index-based magic to generate boxes for nodes, and then boxes for connectors. Then, in layout, knowing indices, first measure boxes for nodes (not all measurables!) using layout constraints. Then iterate through measurables for connectors, associate it with node link data via index, and pass custom constraints that specifies width and height it should occupy to properly connect two boxes. Then place all things according to the data.
👆 1
j
Thanks Ilya, I have implemented your idea and it's working :)
👍 1
o
I was thinking about how to improve the process, and discovered there is already
layoutId
modifier, you can set on boxes, and it is available via
Measurable.layoutId
extension property, so even better, you can just set it to
GraphNode
on children boxes, and retrieve them in Layout. This avoids relying on indicies
❤️ 2