From b881d0624aaa73670c0d814c5e5b1ea4ba9ed3f0 Mon Sep 17 00:00:00 2001 From: jrmoulton Date: Mon, 30 Mar 2026 14:07:30 -0600 Subject: [PATCH] Bump understory and fix #1052 --- Cargo.lock | 10 +++++----- Cargo.toml | 10 +++++----- src/event/dispatch.rs | 4 ++-- src/event/drag_state.rs | 2 +- src/paint/mod.rs | 8 +++----- src/view/id.rs | 10 +++++----- src/views/scroll.rs | 6 +++--- src/window/state.rs | 17 ++++++++++++----- test/tests/fixed_positioning.rs | 7 +++++++ 9 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d61b933c0..23cfb26cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6366,7 +6366,7 @@ dependencies = [ [[package]] name = "understory_box_tree" version = "0.0.1" -source = "git+https://github.com/jrmoulton/understory?rev=3acd6cde8c5c#3acd6cde8c5c642442f14b02d893b7e1068e41eb" +source = "git+https://github.com/jrmoulton/understory?rev=2c2abb8c4bd9#2c2abb8c4bd9bcca1168e51cbc614d8cfd2d3910" dependencies = [ "bitflags 2.11.0", "kurbo", @@ -6376,7 +6376,7 @@ dependencies = [ [[package]] name = "understory_event_state" version = "0.1.0" -source = "git+https://github.com/jrmoulton/understory?rev=3acd6cde8c5c#3acd6cde8c5c642442f14b02d893b7e1068e41eb" +source = "git+https://github.com/jrmoulton/understory?rev=2c2abb8c4bd9#2c2abb8c4bd9bcca1168e51cbc614d8cfd2d3910" dependencies = [ "kurbo", ] @@ -6384,7 +6384,7 @@ dependencies = [ [[package]] name = "understory_focus" version = "0.1.0" -source = "git+https://github.com/jrmoulton/understory?rev=3acd6cde8c5c#3acd6cde8c5c642442f14b02d893b7e1068e41eb" +source = "git+https://github.com/jrmoulton/understory?rev=2c2abb8c4bd9#2c2abb8c4bd9bcca1168e51cbc614d8cfd2d3910" dependencies = [ "kurbo", ] @@ -6392,7 +6392,7 @@ dependencies = [ [[package]] name = "understory_index" version = "0.0.1" -source = "git+https://github.com/jrmoulton/understory?rev=3acd6cde8c5c#3acd6cde8c5c642442f14b02d893b7e1068e41eb" +source = "git+https://github.com/jrmoulton/understory?rev=2c2abb8c4bd9#2c2abb8c4bd9bcca1168e51cbc614d8cfd2d3910" dependencies = [ "hashbrown 0.16.1", "smallvec", @@ -6401,7 +6401,7 @@ dependencies = [ [[package]] name = "understory_virtual_list" version = "0.1.0" -source = "git+https://github.com/jrmoulton/understory?rev=3acd6cde8c5c#3acd6cde8c5c642442f14b02d893b7e1068e41eb" +source = "git+https://github.com/jrmoulton/understory?rev=2c2abb8c4bd9#2c2abb8c4bd9bcca1168e51cbc614d8cfd2d3910" [[package]] name = "unic-langid" diff --git a/Cargo.toml b/Cargo.toml index 767b7d697..5b03934fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -114,11 +114,11 @@ fluent-bundle = { version = "0.16", optional = true } unic-langid = { version = "0.9", optional = true } sys-locale = { version = "0.3.2", optional = true } ouroboros = { version = "0.18", optional = true } -understory_box_tree = { git = "https://github.com/jrmoulton/understory", rev = "3acd6cde8c5c", package = "understory_box_tree" } -understory_event_state = { git = "https://github.com/jrmoulton/understory", rev = "3acd6cde8c5c", package = "understory_event_state" } -understory_index = { git = "https://github.com/jrmoulton/understory", rev = "3acd6cde8c5c", package = "understory_index" } -understory_focus = { git = "https://github.com/jrmoulton/understory", rev = "3acd6cde8c5c", package = "understory_focus" } -understory_virtual_list = { git = "https://github.com/jrmoulton/understory", rev = "3acd6cde8c5c", package = "understory_virtual_list" } +understory_box_tree = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_box_tree" } +understory_event_state = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_event_state" } +understory_index = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_index" } +understory_focus = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_focus" } +understory_virtual_list = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_virtual_list" } [target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies] muda = { workspace = true } diff --git a/src/event/dispatch.rs b/src/event/dispatch.rs index ed46233ac..9dcb6b8f2 100644 --- a/src/event/dispatch.rs +++ b/src/event/dispatch.rs @@ -834,7 +834,7 @@ impl RouteCx<'_, '_> { .window_state .box_tree .borrow_mut() - .get_or_compute_world_transform(dispatch_step.target_element_id.0) + .world_transform(dispatch_step.target_element_id.0) else { // we are storing pending events so it's possible that a node becomes stale. if it // did, don't panic, just continue. @@ -1265,7 +1265,7 @@ impl RouteCx<'_, '_> { .window_state .box_tree .borrow_mut() - .get_or_compute_world_bounds(hit.owning_id().get_element_id().0) + .world_bounds(hit.owning_id().get_element_id().0) .unwrap_or_default(); let bottom_left = Point::new(bounds.x0, bounds.y1); show_context_menu(menu(), Some(bottom_left)); diff --git a/src/event/drag_state.rs b/src/event/drag_state.rs index 51e7cee2a..869763fc2 100644 --- a/src/event/drag_state.rs +++ b/src/event/drag_state.rs @@ -421,7 +421,7 @@ impl DragTracker { // Calculate percentage based on custom_pct or initial click position // Get world bounds at drag start to know where user clicked let start_world_bounds = box_tree - .get_or_compute_world_bounds(pending.element_id.0) + .world_bounds(pending.element_id.0) .expect("drag source went stale during threshold check"); let click_offset_x = start_pos.x - start_world_bounds.x0; diff --git a/src/paint/mod.rs b/src/paint/mod.rs index c5a5801cc..d70ae9037 100644 --- a/src/paint/mod.rs +++ b/src/paint/mod.rs @@ -162,7 +162,7 @@ pub(crate) fn collect_visual_order( } box_tree - .get_or_compute_world_bounds(element_id.0) + .world_bounds(element_id.0) .is_none_or(|bounds| bounds.area() != 0.0) }; @@ -275,10 +275,8 @@ impl GlobalPaintCx<'_> { /// Paint a single visual node with its absolute transform pub(crate) fn paint_visual_node(&mut self, element_id: ElementId, is_post: bool) { // Get state from box tree for this visual node - let mut box_tree = self.window_state.box_tree.borrow_mut(); - let world_transform = box_tree - .get_or_compute_world_transform(element_id.0) - .unwrap_or_default(); + let box_tree = self.window_state.box_tree.borrow_mut(); + let world_transform = box_tree.world_transform(element_id.0).unwrap_or_default(); let layout_rect_local = box_tree.local_bounds(element_id.0).unwrap_or_default(); let clip = box_tree.clipped_local_clip(element_id.0); drop(box_tree); diff --git a/src/view/id.rs b/src/view/id.rs index 25d2d8000..05206842a 100644 --- a/src/view/id.rs +++ b/src/view/id.rs @@ -598,7 +598,7 @@ impl ViewId { VIEW_STORAGE.with_borrow_mut(|s| { s.box_tree(*self) .borrow_mut() - .get_or_compute_world_transform(element_id.0) + .world_transform(element_id.0) .unwrap_or_default() }) } @@ -613,7 +613,7 @@ impl ViewId { VIEW_STORAGE.with_borrow_mut(|s| { s.box_tree(*self) .borrow_mut() - .get_or_compute_world_bounds(element_id.0) + .world_bounds(element_id.0) .unwrap_or_default() }) } @@ -641,7 +641,7 @@ impl ViewId { .with_borrow_mut(|s| { s.box_tree(*self) .borrow_mut() - .get_or_compute_world_bounds(element_id.0) + .world_bounds(element_id.0) .unwrap_or_default() }) .origin() @@ -784,7 +784,7 @@ impl ViewId { let element_id = self.get_element_id(); VIEW_STORAGE.with_borrow_mut(|s| { let box_tree = s.box_tree(*self); - box_tree.borrow_mut().set_local_clip(element_id.0, clip) + box_tree.borrow_mut().set_local_clip(element_id.0, clip); }) } @@ -1398,7 +1398,7 @@ impl ViewId { VIEW_STORAGE.with_borrow_mut(|s| { s.box_tree(*self) .borrow_mut() - .get_or_compute_world_transform(element_id.0) + .world_transform(element_id.0) .unwrap_or_default() * Point::ZERO }) diff --git a/src/views/scroll.rs b/src/views/scroll.rs index df95f2db2..3552c8e11 100644 --- a/src/views/scroll.rs +++ b/src/views/scroll.rs @@ -799,7 +799,7 @@ impl Scroll { fn do_scroll_to_element(&mut self, scroll_to: ScrollTo) -> EventPropagation { let child_element_id = self.child.get_element_id(); let box_tree = self.id.box_tree(); - let mut box_tree = box_tree.borrow_mut(); + let box_tree = box_tree.borrow(); let Some(target_local_rect) = scroll_to .rect @@ -809,10 +809,10 @@ impl Scroll { }; let target_transform = box_tree - .get_or_compute_world_transform(scroll_to.id.0) + .world_transform(scroll_to.id.0) .unwrap_or(Affine::IDENTITY); let child_transform = box_tree - .get_or_compute_world_transform(child_element_id.0) + .world_transform(child_element_id.0) .unwrap_or(Affine::IDENTITY); let target_world_rect = target_transform.transform_rect_bbox(target_local_rect); diff --git a/src/window/state.rs b/src/window/state.rs index 97d3c5122..abe0a4c25 100644 --- a/src/window/state.rs +++ b/src/window/state.rs @@ -953,7 +953,7 @@ impl WindowState { let current_transform = self .box_tree .borrow_mut() - .get_or_compute_world_transform(dragging_preview.element_id.0) + .world_transform(dragging_preview.element_id.0) .unwrap_or(Affine::IDENTITY); let natural_position = dragging.update_and_get_natural_position(current_transform); @@ -996,13 +996,20 @@ impl WindowState { self.drag_tracker.active_drag = None; } + let mut dirty_rects = Vec::new(); + + // Understory now exposes only last-committed world transforms while dirty. + // Commit once to refresh layout-derived parent world transforms before applying + // overlay/fixed corrections that depend on them, then commit the corrected state. + dirty_rects.extend(self.box_tree.borrow_mut().commit().dirty_rects); + self.apply_overlay_parent_transforms(); self.apply_fixed_positioning_transforms(); - let damage = self.box_tree.borrow_mut().commit(); + dirty_rects.extend(self.box_tree.borrow_mut().commit().dirty_rects); let pointer = self.last_pointer; - for damage_rect in &damage.dirty_rects { + for damage_rect in &dirty_rects { if damage_rect.contains(pointer.0) { clear_hit_test_cache(); let root_element_id = self.root_view_id.get_element_id(); @@ -1014,7 +1021,7 @@ impl WindowState { .route_window_event(); } } - if !damage.dirty_rects.is_empty() { + if !dirty_rects.is_empty() { self.invalidate_focus_nav_cache(); self.request_paint = true; } @@ -1093,7 +1100,7 @@ impl WindowState { let mut tree = self.box_tree.borrow_mut(); for (overlay_element_id, logical_parent_element_id, base_local_transform) in overlay_data { let parent_world = tree - .get_or_compute_world_transform(logical_parent_element_id.0) + .world_transform(logical_parent_element_id.0) .unwrap_or(Affine::IDENTITY); tree.set_local_transform(overlay_element_id.0, parent_world * base_local_transform); } diff --git a/test/tests/fixed_positioning.rs b/test/tests/fixed_positioning.rs index e37a16413..8ce6f7517 100644 --- a/test/tests/fixed_positioning.rs +++ b/test/tests/fixed_positioning.rs @@ -1185,10 +1185,14 @@ fn test_fixed_overlay_with_non_fixed_sibling() { clicked1_clone.set(true); }); + use floem::View; + let id = fixed1.id(); + // Non-fixed element at (300, 200) - this should NOT block the fixed element let non_fixed2 = Empty::new() .style(|s| s.background(BLUE).size(50.0, 50.0)) .action(|| {}); + let id2 = non_fixed2.id(); let view = Stack::new(( // First overlay with fixed child @@ -1209,6 +1213,9 @@ fn test_fixed_overlay_with_non_fixed_sibling() { .style(|s| s.size(400.0, 300.0)); let mut harness = HeadlessHarness::new_with_size(root, view, 400.0, 300.0); + harness.rebuild(); + dbg!(id.get_visual_rect()); + dbg!(id2.get_visual_rect()); // Click at (35, 35) should hit the fixed element harness.click(35.0, 35.0);