-
Notifications
You must be signed in to change notification settings - Fork 275
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
RFC: switch layout engine and improve layout experience #374
Comments
Looks good. I'd suggest adding a couple of things:
#122 is a bit stalled as it's a difficult change to make. |
i have tried using taffy in a limited sense, where it works great (after having figured out what options i need to set), though note that i used it as a calculator to have all though this alone is not enough testing, and i also dont know if it is the best way to have a new the code i am speaking oflet column1 = taffy
.new_leaf(Style {
size: Size {
width: points(4.0),
height: auto(),
},
..Default::default()
})
.unwrap();
let column2 = taffy
.new_leaf(Style {
flex_grow: 1.0,
..Default::default()
})
.unwrap();
let column3 = taffy
.new_leaf(Style {
size: Size {
width: points(4.0),
height: auto(),
},
..Default::default()
})
.unwrap();
let column4 = taffy
.new_leaf(Style {
flex_grow: 1.0,
..Default::default()
})
.unwrap();
let column5 = taffy
.new_leaf(Style {
flex_grow: 1.0,
..Default::default()
})
.unwrap();
let root_node = taffy
.new_with_children(
Style {
size: Size {
width: Dimension::Percent(1.0),
height: auto(),
},
..Default::default()
},
&[column1, column2, column3, column4, column5],
)
.unwrap();
taffy
.compute_layout(
root_node,
Size {
width: AvailableSpace::Definite(width as f32),
height: AvailableSpace::Definite(1 as f32),
},
)
.unwrap();
let widths = vec![
Constraint::Length(taffy.layout(column1).unwrap().size.width as u16),
Constraint::Length(taffy.layout(column2).unwrap().size.width as u16),
Constraint::Length(taffy.layout(column3).unwrap().size.width as u16),
Constraint::Length(taffy.layout(column4).unwrap().size.width as u16),
Constraint::Length(taffy.layout(column5).unwrap().size.width as u16),
]
let table = widgets::Table::new(rows)
.header(header)
.block(widgets::Block::default().borders(Borders::ALL).title(block_title))
.highlight_symbol(">> ")
.highlight_style(Style::default().add_modifier(Modifier::REVERSED))
.widths(&widths); |
Looks neat. I wonder how easy it would be to You inspired me to have a bit of a play with this for the styles example and it cleans up the gaps (e.g. this allocates 16 cells across 2 rows of a Rect): fn layout_named_colors(area: Rect) -> Result<Vec<Rect>> {
let mut taffy = Taffy::new();
let grid = repeat_with(|| taffy.new_leaf(Default::default()).unwrap())
.take(16)
.collect_vec();
let root = taffy.new_with_children(
taffy::style::Style {
display: Display::Grid,
size: Size::from_points(area.width as f32, area.height as f32),
grid_template_columns: vec![auto(); 8],
..Default::default()
},
&grid,
)?;
taffy.compute_layout(root, min_content())?;
Ok(grid
.iter()
.map(|col| {
let layout = taffy.layout(*col).unwrap();
Rect::new(
layout.location.x as u16 + area.x,
layout.location.y as u16 + area.y,
layout.size.width as u16,
layout.size.height as u16,
)
})
.collect_vec())
} I suspect that a min_size layout around a fixed size root node (either grid or flex layout) is how the outermost layer of most UIs would be built. I did see something about Cache types in the docs, but couldn't find detail on how this was implemented. It seems a bit more complex than the current layout, so we might want to still keep that interface to hide the complexity (or implement something that works well for the sorts of UIs that work in TUIs. The cool thing about taffy is that I think it will allow us to size widgets based on content rather than content based on widgets (it looks like there is the ability to pass in calculation functions etc.). Perhaps an approach might be to make it a feature flag and gradually move things over to use it? |
Hi, I may not know much about taffy, but I believe taffy tends to bring huge change to Ratatui. Is it easy to keep the user API the same as the current version? It seems quite a breaking change. |
Yep - I'd definitely still like the currently layout API to do the same thing as it already does. My intuition is that mapping the current user API onto taffy instead of cassowary code would probably be possible. I knew nothing about taffy other than it existed yesterday. It took a few tries to get that rendering right, as the docs are sparse and assume a reasonable knowledge of flexbox / grid layout concepts. The change would probably break minor things, but in ways that fix buggy behavior e.g.: |
yes it would be possible to do it non-breakingly, see though a "plain transparent" approach would not break the current API (aside from maybe some edge cases), but would leave a lot of configuration options on the table that taffy would offer. maybe we could consider doing a "Wrapper" type, that both implements a EDIT: though the API would be able to change without breakage, i would still prefer having that in a "major" version and mention that it changed |
For completeness, there's |
In #393 I updated the layout example to show a bunch of combinations of how constraints interact (currently). I'm not sure whether we want to merge that PR, but this be useful as a good visual check for equivalency (and be an easy way to describe any issues that we hit with taffy) |
Problem
The current layout engine
cassowary-rs
has been inactive since 2018 and layout problems have come up here and there (see #354)Current behavior
For example, the current behavior of
cassowary-rs
(at least on how it is used in current master), is:if there is more space available and there are elements that could expand, only one gets expanded to the remaining size (or may not expand at all) and which of the elements to expand is not marked as "consistent" by the engine.
Also a problem currently is how "lower than required space" is handled, which is currently rather undefined behavior (ex #354 (comment)) and in specific cases may even panic sometimes (ex #354 (comment))
Collection of solutions
(none yet decided on)
Open Questions
cassowary-rs
, without modifying public API and have no changes to the user of ratatui)taffy
, then how should it be implemented?taffy
requires a main instance (taffy::Taffy
), and adding new nodes (leafs) onto there and then backwards until there is a root-node (or maybe use a customLayoutTree
? maybe see this, documentation is not great about that)References / notes
Constraint
variants #354 for examplestaffy
seems to be a recommended approach to takePS: this is my first RFC-like issue, please tell me if i missed something or should change
The text was updated successfully, but these errors were encountered: