Stack with premeasured content now work

This makes nested scroll areas work correctly.
This commit is contained in:
Jonathan Johnson 2023-11-15 07:47:23 -08:00
parent 80ba184c15
commit 947f1cd8a7
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
3 changed files with 61 additions and 20 deletions

18
examples/nested-scroll.rs Normal file
View file

@ -0,0 +1,18 @@
use gooey::widget::MakeWidget;
use gooey::Run;
use kludgine::figures::units::Lp;
fn main() -> gooey::Result {
include_str!("./nested-scroll.rs")
.vertical_scroll()
.height(Lp::inches(3))
.and(
include_str!("./canvas.rs")
.vertical_scroll()
.height(Lp::inches(3)),
)
.into_rows()
.vertical_scroll()
.expand()
.run()
}

View file

@ -296,7 +296,8 @@ struct Layout {
total_weights: u32,
allocated_space: (UPx, Lp),
fractional: Vec<(LotId, u8)>,
measured: Vec<LotId>,
fit_to_content: Vec<LotId>,
premeasured: Vec<LotId>,
pub orientation: StackDirection,
}
@ -316,7 +317,8 @@ impl Layout {
total_weights: 0,
allocated_space: (UPx(0), Lp(0)),
fractional: Vec::new(),
measured: Vec::new(),
fit_to_content: Vec::new(),
premeasured: Vec::new(),
}
}
@ -331,20 +333,23 @@ impl Layout {
match dimension {
StackDimension::FitContent => {
self.measured.retain(|&measured| measured != id);
self.fit_to_content.retain(|&measured| measured != id);
}
StackDimension::Fractional { weight } => {
self.fractional.retain(|(measured, _)| *measured != id);
self.total_weights -= u32::from(weight);
}
StackDimension::Measured { min, .. } => match min {
Dimension::Px(pixels) => {
self.allocated_space.0 -= pixels.into_unsigned();
StackDimension::Measured { min, .. } => {
self.premeasured.retain(|&measured| measured != id);
match min {
Dimension::Px(pixels) => {
self.allocated_space.0 -= pixels.into_unsigned();
}
Dimension::Lp(lp) => {
self.allocated_space.1 -= lp;
}
}
Dimension::Lp(lp) => {
self.allocated_space.1 -= lp;
}
},
}
}
dimension
@ -364,7 +369,7 @@ impl Layout {
let id = self.children.insert(index, child);
let layout = match child {
StackDimension::FitContent => {
self.measured.push(id);
self.fit_to_content.push(id);
UPx(0)
}
StackDimension::Fractional { weight } => {
@ -373,6 +378,7 @@ impl Layout {
UPx(0)
}
StackDimension::Measured { min, .. } => {
self.premeasured.push(id);
match min {
Dimension::Px(size) => self.allocated_space.0 += size.into_unsigned(),
Dimension::Lp(size) => self.allocated_space.1 += size,
@ -407,7 +413,7 @@ impl Layout {
// Measure the children that fit their content
self.other = UPx(0);
for &id in &self.measured {
for &id in &self.fit_to_content {
let index = self.children.index_of_id(id).expect("child not found");
let (measured, other) = self.orientation.split_size(measure(
index,
@ -420,6 +426,20 @@ impl Layout {
remaining = remaining.saturating_sub(measured);
}
// Measure measure the "other" dimension for children that we know their size already.
for &id in &self.premeasured {
let index = self.children.index_of_id(id).expect("child not found");
let (_, other) = self.orientation.split_size(measure(
index,
self.orientation.make_size(
ConstraintLimit::Known(self.layouts[index].size),
other_constraint,
),
!needs_final_layout,
));
self.other = self.other.max(other);
}
// Measure the weighted children within the remaining space
if self.total_weights > 0 {
let space_per_weight = remaining / self.total_weights;

View file

@ -868,7 +868,9 @@ where
),
kludgine,
);
let last_rendered_at = context.last_layout().expect("passed hit test");
let Some(last_rendered_at) = context.last_layout() else {
continue;
};
context.mouse_drag(location - last_rendered_at.origin, device_id, *button);
}
} else {
@ -886,11 +888,10 @@ where
self.mouse_state.widget = None;
for widget in self.root.tree.widgets_at_point(location) {
let mut widget_context = context.for_other(&widget);
let relative = location
- widget_context
.last_layout()
.expect("passed hit test")
.origin;
let Some(widget_layout) = widget_context.last_layout() else {
continue;
};
let relative = location - widget_layout.origin;
if widget_context.hit_test(relative) {
widget_context.hover(relative);
@ -970,8 +971,10 @@ where
kludgine,
),
|context| {
let relative =
*location - context.last_layout().expect("passed hit test").origin;
let Some(layout) = context.last_layout() else {
return IGNORED;
};
let relative = *location - layout.origin;
context.mouse_down(relative, device_id, button)
},
) {