-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support multiple layout algorithms #28
Comments
I have some ideas for this, encoded in my now-dead attempt at a layouting engine. (The name might sound familiar; I never made this public till just now because it was never able to do much of anything.) The way it supported multiple layouts was by making a distinction between container nodes and item (aka leaf) nodes. Nodes have a method that can convert itself into a container, and that method decides which layouting algorithm its items will be subject to. So for example, you'd have a Here's what creating an item looks like using this API, and here's creating a container. There are some other examples in files in the Nested layouts: Since the layouting method is decided at layout-time, you can easily (from the user's perspective, anyway) support nested distinct layouts. Feature flags: It should be possible to put these methods and their configuration types behind feature flags. Unified interface: The interface would be unified via the return type from the methods like Custom algorithms: I haven't considered this at all but as a quick guess I'm imagining one could implement a method like Performance: I have absolutely no idea since I never actually got any of this working to a point where it's worth benchmarking 😅 . |
That's very promising: I think the Container vs. Leaf distinction is quite natural, and should transfer well across algorithms. The |
I realised recently that a better approach is to just have the Then there's just a method on the node trait for returning an iterator on the children, and any layout algorithm can be described recursively. The |
Ah; at first I was confused what purpose a trait for nodes would serve, that example helped me understand. That seems to be using an ECS architecture, and a trait makes sense for that, since all the objects are stored "flatly". My project organized things hierarchically with I guess it depends on whether this project wants to do ECS, something like what I've come up with, or something else entirely. (I don't have any real preference for any particular approach since I haven't really explored the alternatives.) |
That is definitely true for the Using enums to express the tree isn't something I had thought of, but I guess that only really makes sense if you want to force a distinction between containers and non-containers. In morphorm, any node can contain children and then it's up to the user to design an API where it's possible or not to add those children to a node. |
Any specific ordering or prioritization for these? I might tackle one if I have some time. |
CSS grid is probably the highest priority due to its popularity. After that, my personal favorite is Morphorm, then Cassowary. Once those three are in we can see what sort of gaps are still left; I don't think there's a lot of need to support very similar APIs. EDIT: the other dead simple "layout algorithm" I want is the identity layout algorithm. Users just pass in absolute positionings and we return them. This is both a useful escape hatch and serves as a great test ground for the broader architecture. |
Could it support a Flutter-style (one pass) layout algorithm? Or is that covered by one of the others? I refer to: https://medium.com/snapp-mobile/flutter-anatomy-layout-internals-part-1-de99b772ab99 |
CSS grid also works in combination with Flexbox, I use the |
Mhmm. I think we'll want a few diverse layout algorithms in place first, then start experimenting with patterns there. If we need to define pairwise compatibility rules, we can use a generic trait that takes the other layout algorithm, ala |
Regarding leaf nodes, would it make sense for them to be "just another layout type"? So you end up with: enum Display {
Flexbox,
CSSGrid,
Leaf,
// More layout algorithms here...
} where the Leaf layout type works similarly to
|
Oh that's a cool idea. The idea of "Leaf" as a layout algorithm is pretty appealing 🤔 I'm a bit nervous to use an enum rather than a trait here: like you say, I want an escape hatch for custom layouts if we can get away with it. |
More relevant conversation #205 (comment) |
I've done quite a bit of research into and thinking about this, and I think I've now gotten to a settled viewpoint on this topic which I will write out below. Two types of "layout algorithm"Considering the "layout algorithms" listed in the top-level description of this (and a couple of others that I'm adding in), I believe they fall into two categories: True algorithmsThese are well-defined algorithms that specify a specific way to size and position boxes in 2D space. Included in this category is:
I believe it would make sense to implement these algorithms as part of Taffy itself (to the extent that we have the engineering resources to do so and the specific algorithm is considered priority). And indeed we are already making good progress on this with a CSS Grid implementation nearly complete, and work on Morphorm scoped out. Layout FrameworksOn the other hand we have broader "layout frameworks". These do not prescribe a specific way of doing layout, but rather provide a framwork within which individual widgets can implement their own layout algorithm. These include:
These frameworks vary in exactly how they implement layout. On one end of the spectrum you have Flutter which has a pretty complete Flexbox implementation as a widget. On the other end of the spectrum you have Swift UI which uses simplistic hstack/vstack layout, but combines that with lot of "widget combinators" like padding/border to achieve complex layouts (so in SwiftUI there is a seperate widget specifically for applying padding, another one for borders, etc). What they have in common is that they are extensible. And specifically, they are extensible in end-user code. While end-users will commonly use the built-in "vocabulary widgets" (hstack, padding, etc) to define their layouts, they are also free to write their own widgets which implement custom algorithms (and indeed there are libraries like SwiftYogaKit that implement Flexbox as a SwiftUI widget) I believe that the way to support these frameworks in Taffy would not be to attempt to implement the specific vocabulary types (there are too many of them, and most of them are so trivial to implement that potential consumers of Taffy are unlikely to consider gaining implementations of them worth the pain of integrating with a 3rd party library). Rather, supporting these frameworks would consist in having excellent support for custom layout algorithms (and would probably also constitute a solution to #57). Supporting custom layout modes/algorithmsRethinking our approachThe crux of this issue then becomes how best to support custom layout algorithms. And I think I have had a bit of a revelation in my thinking around this issue. So far, most of our discussion (or at least most of my thinking) has been about how to cram support for custom layout modes into Taffy. Which is awkward because it's hard to know what the requirements for the custom layout modes will be so you end trying to design a super-generic solution which quickly becomes very complex, cumbersome, or simply not actually possible to implement. My revelation (inspired by how Flutter and Druid integrate flexbox-like layout) is that we should flip our approach on it's head: rather than trying to make it possible to embed support for custom layout modes into Taffy, we should instead make it straightforward for consumers of Taffy to embed Taffy (and specifically Taffy's layout algorithms) into their own layout systems which may implement Taffy layout modes as well as their own custom modes (e.g. text layout, image layout, and/or any SwiftUI style combinators) Extending the
|
From a first look this sounds good! Would it be possible / how would it look like to nest different types of layout algorithms or to combine them? |
|
It would absolutely be possible to combine them (as is already the case with Flexbox and CSS Grid). Each node would:
Children of a node can use any layout algorithm they like to lay out their own content. |
@alice-i-cecile Excellent - it sounds like we're in agreement on everything! I'll probably get to this soon, because I think doing something like this is going to be necessary for baseline alignment support in CSS Grid (technically I wouldn't need to expose it on the trait, but I might as well if I'm touching that code anyway :))
Yes, definitely keen to get mega-issue closed! |
Tracking Issues:
This library will be dramatically more useful if it can be used to support multiple layout strategies. This is useful because:
Must have:
Nice to have:
Possible layout algorithms we may want to support:
The text was updated successfully, but these errors were encountered: