Open nicoburns opened 1 year ago
Wow, that's a very comprehensive summary of Morphorm! So I think there's some things I should point out that might be helpful.
child_space
is closer to padding than it is to margin, but the way it actuall works is to override the spacing
properties on the children if those properties are set to Auto
.PositionType::SelfDirected
don't count towards being the first/last in a stack, and child_spacing
will apply to those nodes regardless (if their spacing is auto).border
don't use all the variants of Units
. Probably when you port you can use LengthPercentage
, I just used Units
to keep things simple.content_size
and how it's used in morphorm. There are two methods on node for content size, primary_content_size
and secondary_content_size
. The first is used when you want the node to 'hug' its content in the same axis, e.g. you want a label to be the width of its text content. The second one is used when you want the node to 'hug' its content in the off-axis, e.g. you want a multiline label/textbox to be the height of its text content. I suspect these can be conbined somehow.I'm very curious to understand what you mean by 'lazily sizing children'?
For the actual algorithm there are some bugs that you should be aware of. Mainly 2 things:
secondary_content_size
is only handled in phase 3 and is thus not properly propagated up the tree in phase 2, which results in things like containers not correctly sizing to accomodate a multiline textbox.So, now should mention that for a little while I've been working on a new and improved version of morphorm. It's not finished, but it already solves some of the problems you've identified. The code is on this branch: https://github.com/vizia/morphorm/tree/new-layout-no-wrap. The 'new' versions are files ending with a '2', e.g. layout2.rs. Sorry about the mess in the actual code, it's WIP.
The main difference in this branch is that the layout algorithm is now recursive instead of iterative. This means that phases 2 and 3 from before are combined into a single function. This eliminates the need for a Hierarchy
trait and instead allows for a children
method on the Node
trait, which makes use of GATs to allow getting its children from an external tree (Tree
associated type). Every method on Node
, like before, has a parameter for an external store (Store
associated type), which allows for both nodes that are just keys, and for nodes which contain their style properties.
The Cache
is now also greatly simplified. Many interediate values are calculated on the fly (including first/last child now) so the cache only contains the size and position of a node, which are used as intermediates but are also the outputs of the algorithm. Also, the properties have changed to be direction agnostic. Instead of chld_left
or child_top
it's now child_main_before
and child_cross_before
and depends on the layout type of the parent. Not yet implemented but planned is RowReverse
and ColumnReverse
layout types.
As you'll see, the new algorithm isn't finished yet. I'd say it's about 80% there and even already fixes the content-size bug I mentioned before, but is still missing the min/max size handling, grid, and extensive testing. I'm also not sure I'm handling content_size correctly as I can imagine situations where circular dependencies pop up and I can't yet think of an ideal solution (other than to hope users don't do that). I do think though that this new version will be easier to port to taffy. I will of course help with the porting effort, and let me know if you've got any questions.
@geom3trik Thanks for pointing me to the new-layout-no-wrap
branch. That definitely looks like a much better starting point for porting to Taffy (esp. the iterative -> recursive change and the simplified caching).
Having said that, it does concern me somewhat that this version has slightly different behaviour and user-facing API (e.g. renamed styles) to the existing version. I was under the impression that there was more of a standard being followed, but it seems that it's more of a case of "the implementation is the specification"? In which case I think we'll need really nail down exactly how the algorithm ought to behave in corner cases, and try to be careful not to introduce discrepancies between the implementation in the morphorm
crate and the Taffy implementation.
I think that ideally we should:
morphorm
crate in tandem with the Taffy release including morphorm
, such that the behaviour and API are the same.morphorm
crate in favour of Taffy once a version of Taffy with Morphorm support has been released.Also, the properties have changed to be direction agnostic. Instead of chld_left or child_top it's now child_main_before and child_cross_before and depends on the layout type of the parent. Not yet implemented but planned is RowReverse and ColumnReverse layout types.
I wonder how you'd feel about reverting this for the time being? My reasons being:
morphorm
crate, such that there is no tradeoff to be made between features in the morphorm
and features in Taffy. If you switch to Taffy then you get the full Morphorm functionality (+ extra algorithms). I feel like having different styles is going to muddy the waters, and make the upgrade path more difficult. child_main_before
and child_cross_before
are going to be very confusing to end users (whereas child_left
and child_top
are much more intuitive). I mean, even for someone like me who's been knee deep in CSS specifications for last few months, I still have to think about which axis is which. Note also that CSS doesn't provide flex-direction relative margin or padding properties. Although I suppose spacing is kind of Morphorm's answer to alignment too, which does come in flex-direction relative variants.A note on terminology: also like to use "content size". But you find it useful to know that CSS tends to call this "intrinsic size" https://developer.mozilla.org/en-US/docs/Glossary/Intrinsic_Size
I'm very curious to understand what you mean by 'lazily sizing children'? The main difference in this branch is that the layout algorithm is now recursive instead of iterative.
I think these two things are broadly the same. By lazily sizing children I mean that the content sizes of nodes aren't computed in advance. Instead we start layout computation at the top of the tree, and parent node query the size of their children (passing in any relevant constraints) as required. These children can in turn query the sizes of their children, recursing down the tree as necessary.
In Taffy 0.3, it's a mutually recursive algorithm rather than a simple recursion, as a child node may be sized using a different algorithm. #326 introduces a nice innovation in this model by adding a measure_child_size
function to the LayoutTree
trait, which means that embedders of Taffy can intercept any queries for child size and run arbitrary code with full access to their own state to determine the correct size (this could call straight back into Taffy, it could implement something like text layout, it could forward the call through some internal interface (and/or implement some other layout algorithm), perhaps later calling back into Taffy to size descendent nodes further down the tree).
There are two methods on node for content size, primary_content_size and secondary_content_size. The first is used when you want the node to 'hug' its content in the same axis, e.g. you want a label to be the width of its text content. The second one is used when you want the node to 'hug' its content in the off-axis, e.g. you want a multiline label/textbox to be the height of its text content. I suspect these can be conbined somehow.
Yes, Taffy simply has a single measure_child_size
method that returns the size in both axes. It will generally only use the result in one axis at a time, but it simplifies the API.
Node
traitInspired by your Node
trait (and also Druid's and Iced's Widget
traits), I've started making a similar change to Taffy's LayoutTree
trait (hasn't been renamed yet) over in https://github.com/DioxusLabs/taffy/pull/326.
It's slightly different to the Node
trait in Morphorm in that you can't directly access a Node
instance of a child. Instead you can access styles of direct children, and if you want to recurse down the tree you have to call either the measure_child_size
or perform_child_layout
methods. The reference implementations of these (if you don't implement LayoutTree
yourself) simply create a new instance of LayoutTree
representing the child and call back into the layout algorithm computation function with this instance, but it gives embedders of Taffy a lot of freedom as explained in the content sizing section above.
I'd love to get your thoughts / review on the design of this interface.
I think you might be right that the grid feature isn't worth porting. My reasoning is slightly different, which is that it just seems much more similar to CSS Grid than the Morphorm Row/Column are to Flexbox. Notably, CSS Grid already has stretch-like units in the form of the fr
unit. I think the only thing CSS Grid doesn't have is stretch units for gaps between columns, but that seems like an uncommon use case to me.
Also, in terms of current state, the CSS Grid implementation is a lot more robust in edge cases and does things like automatically generate extra rows/columns if you place an item out of bounds. This could of course be implemented for Morphorm Grid, but I'm not sure if it's worth the effort given how similar they are.
You're right that some properties like border don't use all the variants of
Units
. Probably when you port you can useLengthPercentage
, I just used Units to keep things simple.
Excellent. Taffy used to do the same, but we've recently switched to being strict. And I think we would indeed want to continue that for new algorithms. Higher level libraries would of course be free to provide a simpler interface if they wanted.
child_space
is closer to padding than it is to margin, but the way it actually works is to override thespacing
properties on the children if those properties are set to Auto.
I see what you mean in terms of which sides/spaces it affects, but I think the spacing
property on children in morphorm is effectively the same as the margin
property on children in CSS. So to "to override the spacing
properties on the children" would be directly equivalent to overriding the margin
property on those children (only on the relevant sides). Of course there is no way to control margins in this in CSS, and auto margins mean something else (they're like stretch!), but still.
You've probably already noticed that morphorm doesn't support wrapping.
I wonder if the best approach to this is to leave it that way, and if people want to use wrapping then they can use Flexbox instead? I guess there's nothing stopping us from taking that approach for now, and we can always implement wrapping in Morphorm later.
I was under the impression that there was more of a standard being followed, but it seems that it's more of a case of "the implementation is the specification"? In which case I think we'll need really nail down exactly how the algorithm ought to behave in corner cases, and try to be careful not to introduce discrepancies between the implementation in the
morphorm
crate and the Taffy implementation.
So the original implementation comes from an application called Subform which no longer exists. Someone on the bevy discord linked to this post https://subformapp.com/articles/why-not-flexbox/, which inspired me to implement from scratch the features shown in the marketing material on that site. Which is to say, as far as I know there is no specification and I did not find any code to use as reference.
I based the orignal algorithm on a once up/once down approach as described in a video I saw explaining the flutter layout algorithm, but using iterators instead of recursion (which as you know I've since changed). The original subform layout used direction-agnostic properties, which I changed to left
, top
, right
, bottom
, etc for ease of use. If it's helpful I can try and write some kind of specification when I can find the time.
I think that ideally we should:
- EITHER release a new version of the
morphorm
crate in tandem with the Taffy release includingmorphorm
, such that the behaviour and API are the same.- OR deprecate the
morphorm
crate in favour of Taffy once a version of Taffy with Morphorm support has been released.
This might be something easier to decide when some of the other parts have been figured out. I don't particularly like the idea of depreciating my own crate but I can see the advantages to having taffy handle flexbox, morphorm, and grid in one place.
On style property changes
Also, the properties have changed to be direction agnostic. Instead of chld_left or child_top it's now child_main_before and child_cross_before and depends on the layout type of the parent. Not yet implemented but planned is RowReverse and ColumnReverse layout types.
I wonder how you'd feel about reverting this for the time being? My reasons being:
- I'm keen for Taffy to offer a strict superset of the layout functionality in the
morphorm
crate, such that there is no tradeoff to be made between features in themorphorm
and features in Taffy. If you switch to Taffy then you get the full Morphorm functionality (+ extra algorithms). I feel like having different styles is going to muddy the waters, and make the upgrade path more difficult.
I'm not sure I fully understand what you mean here. Are you meaning that you'd like for users to be able to use the same properties, like left
etc. but then apply a different algorithm (flexbox or morphorm)? I think with the differences between flexbox and morphorm I'm not sure I see the issue with requiring different properties.
- I'd rather separate out implementation changes from behaviour/API changes. I feel like it's going to be hard to verify correctness if changing both at once.
We're talking about changes between taffy and morphorm here?
- I also can't help but feel like names like
child_main_before
andchild_cross_before
are going to be very confusing to end users (whereaschild_left
andchild_top
are much more intuitive).
I definitely agree with you here, but I'm concerned that not having the properties as direction agnostic would make it too restrictive if you want a layout that can adapt to direction changes. But I'm curious how this is currently handled in taffy? Because flexbox is also direction agnostic but margins/padding are not right?
I'm not against changing it back to the non-direction-agnostic properties though. Users of vizia are already accustomed to the left
,right
, etc. properties so it will be more work to provide internal conversions to direction agnostic ones anyway, I'm just concerned about how to best provide localization of layout.
Regarding Content Sizing
A note on terminology: also like to use "content size". But you find it useful to know that CSS tends to call this "intrinsic size" https://developer.mozilla.org/en-US/docs/Glossary/Intrinsic_Size
Ah, thanks for the info. I've seen that term used before but did not realise it was what I was calling content-size.
In Taffy 0.3, it's a mutually recursive algorithm rather than a simple recursion, as a child node may be sized using a different algorithm. #326 introduces a nice innovation in this model by adding a
measure_child_size
function to theLayoutTree
trait, which means that embedders of Taffy can intercept any queries for child size and run arbitrary code with full access to their own state to determine the correct size (this could call straight back into Taffy, it could implement something like text layout, it could forward the call through some internal interface (and/or implement some other layout algorithm), perhaps later calling back into Taffy to size descendent nodes further down the tree).
This sounds like what I was trying to do with content_size
on the Node
. I'll have to take a closer look at this.
Regarding the
Node
traitInspired by your
Node
trait (and also Druid's and Iced'sWidget
traits), I've started making a similar change to Taffy'sLayoutTree
trait (hasn't been renamed yet) over in #326.It's slightly different to the
Node
trait in Morphorm in that you can't directly access aNode
instance of a child. Instead you can access styles of direct children, and if you want to recurse down the tree you have to call either themeasure_child_size
orperform_child_layout
methods. The reference implementations of these (if you don't implementLayoutTree
yourself) simply create a new instance ofLayoutTree
representing the child and call back into the layout algorithm computation function with this instance, but it gives embedders of Taffy a lot of freedom as explained in the content sizing section above.I'd love to get your thoughts / review on the design of this interface.
This sounds intriguing and I will definitely check it out and give my thoughts. Something I haven't implemented yet with my current Node
approach is a way to skip nodes. So performing layout on the root will recurse the entire tree. Your approach sounds like it has a solution to this.
Regarding the Grid implementation
I think you might be right that the grid feature isn't worth porting. My reasoning is slightly different, which is that it just seems much more similar to CSS Grid than the Morphorm Row/Column are to Flexbox. Notably, CSS Grid already has stretch-like units in the form of the
fr
unit. I think the only thing CSS Grid doesn't have is stretch units for gaps between columns, but that seems like an uncommon use case to me.
I think I would agree with you here. And if morphorm is eventually incorporated into taffy then taffy already has what looks like a very robust grid implementation. The only counter-argument I would have is that it would be nice for users using morphorm to be able to use the morphorm stretch type with grids, but that's subjective.
Miscellaneous
You've probably already noticed that morphorm doesn't support wrapping.
I wonder if the best approach to this is to leave it that way, and if people want to use wrapping then they can use Flexbox instead? I guess there's nothing stopping us from taking that approach for now, and we can always implement wrapping in Morphorm later.
I agree here too. I've found wrapping quite challenging to implement because of all the interdependencies between the axes of a node, particularly when trying to compute the stretch space and size combined with the auto size 'hugging' of the parent.
Which is to say, as far as I know there is no specification and I did not find any code to use as reference.
Yeah, I couldn't find a specification either. There is https://github.com/lynaghk/subform-layout as a reference implementation, but it's obfuscated and in any case not under an OSS licence.
The original subform layout used direction-agnostic properties, which I changed to left, top, right, bottom, etc for ease of use. If it's helpful I can try and write some kind of specification when I can find the time.
Oh interesting. A specification would be great, as would a test suite - preferrably in a declarative machine-parsable format (HTML/XML?) that we could parse to generate tests for Taffy. But I wouldn't consider either blocking.
I don't particularly like the idea of depreciating my own crate but I can see the advantages to having taffy handle flexbox, morphorm, and grid in one place.
Yeah, fair enough. I also don't think it would be fair to expect you to. You would obviously be welcome to come and maintain the implementation in Taffy. But I suspect it would make it harder to experiment and evolve to algorithm, and would come additional levels of scrutiny and review.
I'm not sure I fully understand what you mean here. Are you meaning that you'd like for users to be able to use the same properties, like left etc. but then apply a different algorithm (flexbox or morphorm)? I think with the differences between flexbox and morphorm I'm not sure I see the issue with requiring different properties.
No, I agree that separate properties seem reasonable (although some like width
/height
probably make sense to be the same). What I am wanting to be the same is the style properties in the morphorm
crate and the style properties in the Taffy implementation of Morphorm (i.e. I want to avoid the situation where the morphorm
has left
, top
, etc properties while the Taffy implementation of Morphorm has main_axis_before
, etc, or vice versa).
Something I haven't implemented yet with my current Node approach is a way to skip nodes. So performing layout on the root will recurse the entire tree. Your approach sounds like it has a solution to this.
Taffy skips measuring a node's contents if that node's width/height property can be resolved to a fixed size, (e.g. it has a pixel size, or a percentage size and the container has a defined size in that axis) then that size will be used). It also caches measured sizes (and the inputs used to generate those), and will simply return the value from the cache if possible. Although in most cases, it does still need to recurse through every node in the tree at least once to "perform layout". Because even if we know their size, children still ultimately need to position their own descendants.
I definitely agree with you here, but I'm concerned that not having the properties as direction agnostic would make it too restrictive if you want a layout that can adapt to direction changes. But I'm curious how this is currently handled in taffy? Because flexbox is also direction agnostic but margins/padding are not right?
So, CSS doesn't define flex-direction
relative padding/margins. The only thing which flex-direction affects are the flex-start
and flex-end
alignment properties, and the order in which the children are positioned. However, it does have relative padding/margin (and width, height and much more) properties that change relative to the direction
property (which switches between left-to-right and right-to-left text directions), and the writing-mode
property (which switches between horizontal and vertical text directions).
If it were up to me, I'd probably initially implement Morphorm in Taffy with "absolute" properties (left, right, etc), and then look at implementing direction
, writing-mode
, and relative styles for all algorithms later.
Out of interest, what is the use case for RowReverse/ColumnReverse? I don't think I've ever used these personally. Or are you more worried about switching between Row and Column?
Yeah, I couldn't find a specification either. There is https://github.com/lynaghk/subform-layout as a reference implementation, but it's obfuscated and in any case not under an OSS licence.
Ah yes I do remember finding that, but I chose not to use it because of the license. In the end the only thing I really took from the subform stuff is the concept of stretch space and size as well as the Auto
variant of the units and how it works.
Oh interesting. A specification would be great, as would a test suite - preferrably in a declarative machine-parsable format (HTML/XML?) that we could parse to generate tests for Taffy. But I wouldn't consider either blocking.
I can write up a specification based partly on the morphorm implementation and partly on how I would like it to work. A test suite would be great, and I'm implementing some tests as I rewrite the algorithm but something auto-generated from a declarative format would be great!
No, I agree that separate properties seem reasonable (although some like
width
/height
probably make sense to be the same). What I am wanting to be the same is the style properties in themorphorm
crate and the style properties in the Taffy implementation of Morphorm (i.e. I want to avoid the situation where themorphorm
hasleft
,top
, etc properties while the Taffy implementation of Morphorm hasmain_axis_before
, etc, or vice versa).
Oh I see what you mean. Well hopefully a specification will solve this problem. Then both implementations (if it ends up being separate) can follow the same spec.
Taffy skips measuring a node's contents if that node's width/height property can be resolved to a fixed size, (e.g. it has a pixel size, or a percentage size and the container has a defined size in that axis) then that size will be used). It also caches measured sizes (and the inputs used to generate those), and will simply return the value from the cache if possible. Although in most cases, it does still need to recurse through every node in the tree at least once to "perform layout". Because even if we know their size, children still ultimately need to position their own descendants.
Right yeh, those sound like good optimisations.
So, CSS doesn't define
flex-direction
relative padding/margins. The only thing which flex-direction affects are theflex-start
andflex-end
alignment properties, and the order in which the children are positioned. However, it does have relative padding/margin (and width, height and much more) properties that change relative to thedirection
property (which switches between left-to-right and right-to-left text directions), and thewriting-mode
property (which switches between horizontal and vertical text directions).If it were up to me, I'd probably initially implement Morphorm in Taffy with "absolute" properties (left, right, etc), and then look at implementing
direction
,writing-mode
, and relative styles for all algorithms later.
Ah I was not aware of the writing-mode
property, which seems to apply to both text and layout (and flexbox?). This is perhaps a more ergonomic option than the direction-agnostic properties. I think knowing this I would agree with your suggestion of using left
, right
, etc. and to add some form of direction property.
Out of interest, what is the use case for RowReverse/ColumnReverse? I don't think I've ever used these personally. Or are you more worried about switching between Row and Column?
This was my attempt to allow the user to specify the direction that elements should be stacked for localized layouts, e.g. right-to-left locales, but it looks like writing-mode
would cover this. Though I'm curious now why these are available in flexbox?
In discussions with @geom3trik it has become apparent that Morphorm's algorithm is not as fixed/finished as I initially assumed it to be (it is based on Subform layout, but that was also never formally specified (at least not publically), and that part of this task will likely be to pin down exactly how the algorithm ought to work.
Also through those discussions (and further influenced by @hecrj's push back on integrating Taffy's existing layout modes into Iced), it has become clear to me that the clearest justification for Morphorm's existence in Taffy (more so even than it's simplified mental model) is as a single-pass counterpoint to the CSS algorithms (Flexbox and CSS Grid). That is, a morphorm container should never call measure_size
on it's children, and should call perform_layout
on each child exactly once.
With this in mind, I now think that we ought to make Morphorm layout modes as fully-featured as possible (so in particular, I am now considering things wrapping and grid layout as back in scope) under the hard constraint of being single-pass, and the fuzzier constraint of having a simple mental model. This will enable systems that want utmost layout performance (or that don't want to deal with the caching required for fast multipass layout) to use Taffy by disabling the slower CSS modes, although we should also attempt to make these two groups of layout modes work together so that systems that want to enable all Taffy layout modes can do so.
In implementing this we may wish to take inspiration from Flutter's layout model implements just such a single-pass layout model (it turns out that while Flutter includes a flexbox-like layout mode, it isn't actually flexbox compatible precisely because it is a single-pass variant on the same general idea).
Reading on Flutter's layout model:
Very nice writeup and goals. I'm in favor of both "simple mental model" and "fully featured", so I'm on board with this direction.
Now that CSS Grid support is nearing completion, I thought I'd take a look at what it would take to support Morphorm layout in Taffy (CC: @geom3trik). My findings are summarised below:
Morphorm Styles
Unique Types
LayoutType
(corresponds toDisplay
in Taffy):PositionType
(corresponds toPosition
in Taffy):Units
(corresponds toDimension
in Taffy):Style Properties
Using these types (mostly
Units
), Morphorm has the following style properties. Note:Units
actually support all variants, for exampleborder
(and I think alsomin_size
andmax_size
) only really supports "LengthPercentage" (Auto and Stretch resolve to zero).layout_mode
LayoutType
flex_direction
position_type
Position
position
size
Size<Units>
size
min_size
Size<Units>
min_size
max_size
Size<Units>
max_size
border
Rect<Units>
border
child_spacing
Rect<Units>
padding
row_between
Units
gap.height
col_between
Units
gap.width
grid_rows
Vec<Units>
grid_template_rows
grid_cols
Vec<Units>
grid_tempalte_columns
spacing
Rect<Units>
margin
min_spacing
Rect<Units>
max_spacing
Rect<Units>
row_index
usize
grid_row.start
col_index
usize
grid_column.start
row_span
usize
grid_row.end
col_span
usize
grid_column.end
Analysis
Nearly everything in Morphorm is simplified version of either Flexbox or CSS Grid. There are really three things that aren't:
child_spacing
and*_between
properties. CSS does not allow you to specify child margins on the parent like this. It does have thealign-items
andjustify-items
properties, but those are not as powerful.min_spacing
andmax_spacing
properties. CSS does not allow you to specify min or max values for margins.Stretch
variant ofUnits
. Flexbox/CSS Grid do not allow you to express "fill available space" as a size like this. To achieve this with Flexbox/CSS Grid you need to use special properties that are specified separately.The only really tricky thing here is the
width
/height
properties. They are common to all algorithms, and furthermore by both parent and child nodes access this property. This means that the type of these properties really needs to be a single unified type. I thought this might be a blocker, however I have discovered that an upcoming CSS standard (css-sizing-4) actually does define this functionality and in fact even calls itstretch
. The CSS version doesn't have the weighting parameter (although I have opened an issue proposing that it does - no idea if that's the right place to do that though) so it is roughly equivalent toStretch(1.0)
, but that would a pretty straightforward extension.Algorithm and Code Structure Differences
Morphorm is relative small and simple compared to Taffy's layout algorithms (yay!). Morphorm's
layout.rs
which contains the core implementation for both it's Grid and Row/Column algorithms is just over 1000 LoC. For comparison, Taffy's Flexbox implementation alone is around ~1700 LoC, and the CSS Grid implementation almost double that.Morphorm uses a 3 phased approach to layout:
In contrast, Taffy uses a single phase approach which essentially corresponds to Phase 3 of Morphorm's approach. It also does things equivalent to Morphorm's Phase 2 (probably Phase 1 as well), but it does this lazily on demand.
Morphorm has fairly large/extensive persistent
Cache
object (See the trait and the reference implementation) which I believe it uses to store both intermediate computations and the output of it's layout. In contrast, Taffy stores it's intermediate computations locally within the computation function(s) and throws them away once it's done computing the size for a node. I have a feeling that the easiest way to get Morphorm to work with Taffy might be to make it work more like Taffy's other algorithms do and keep more of it's intermediate results internal: IMO keeping API surface small is going to be key to making this project feasible.Morphorm's layout algorithms themselves obviously have differences (that being the whole point of supporting it!), but I don't think any of that (other than the already discussed
Stretch
variant ofUnits
) is particularly relevant from an integration point of view. Taffy is already setup to let each container node have free reign over their children, so it should be straightforward to slip Morphorm's algorithms into that model.Implementation Proposal
My suggestion based on looking into this is that we don't attempt to use the
morphorm
crate as a dependency, and instead port the Morphorm code/algorithm into Taffy directly (but I'd definitely be interested to hear @geom3trik's opinion on this). This is based on the following:More specifically, I would propose the following implementation plan:
Add a
Stretch(f32)
variant to Taffy's existing style system. Making it available on thewidth
/height
properties and implementing this variant for Flexbox/CSS Grid according to https://www.w3.org/TR/css-sizing-4/#stretch-fit-sizing (except with added support for weighting), and maybe on themargin
and/orposition
properties (the latter two could be done later though).Create a
morphorm
feature flag.Add Morphorm style properties to
Style
(behind the feature flag). This will also involve working how to alter theDisplay
type (e.g. do we addMorphormRow
/MorphormColumn
/MorphormGrid
separately, or do we have a singleMorphorm
variant and sub-differentiate separately?)Implement the Morphorm layout algorithms themselves, refactoring them to fit Taffy's structure as they are ported.
Consider improving Taffy's extension trait system (i.e.
LayoutTree
andMeasureFunc
) with inspiration from Morphorm's traits (Node
,Hierarchy
,Cache
). Possibly using the approach of "just having a Node trait" as proposed here https://github.com/DioxusLabs/taffy/issues/28#issuecomment-1124355022Implement a fracturing of the
Style
into smaller pieces similar to the one Bevy UI is about to implement.I'd love to know others' thoughts, but I'm quite encourage by what I'm seen: this actually looks quite achievable to me!
P.S. I also did some preliminary research on Flutter and Swift UI's layout systems, but I think that to a large degree their systems amount to being layout-agnostic, with each Component being able to implement arbitrary layout algorithms. So I think support for those systems will look more like "an extension point that allows custom algorithm" than an implementation of specific algorithm(s).