From 6e60db52d8a058aa31e1b2ec64f613e6c242dd8e Mon Sep 17 00:00:00 2001 From: Kaur Kuut Date: Wed, 27 May 2026 19:45:36 +0300 Subject: [PATCH] Tweak some docs. --- masonry/src/doc/implementing_container_widget.md | 3 ++- masonry_core/src/core/contexts.rs | 15 +++++++++------ masonry_core/src/core/widget.rs | 11 +++++++++-- masonry_core/src/core/widget_state.rs | 4 ++-- masonry_core/src/doc/pass_system.md | 10 +++++++--- masonry_core/src/passes/layout.rs | 2 +- masonry_testing/src/harness.rs | 3 +-- 7 files changed, 31 insertions(+), 17 deletions(-) diff --git a/masonry/src/doc/implementing_container_widget.md b/masonry/src/doc/implementing_container_widget.md index ae4fdad8d..b9aee953e 100644 --- a/masonry/src/doc/implementing_container_widget.md +++ b/masonry/src/doc/implementing_container_widget.md @@ -163,7 +163,8 @@ There are a few things to note here: ### `compose` -The `compose` method is called during the compose pass, after layout. +The `compose` method may be called during the compose pass, after layout. +Masonry guarantees that `compose` is called after that widget's `layout` method runs, or when the widget explicitly requests compose. The compose pass runs top-down and assigns transforms to children. Transform-only layout changes (e.g. scrolling) should request compose instead of requesting layout. diff --git a/masonry_core/src/core/contexts.rs b/masonry_core/src/core/contexts.rs index efdcf6b43..b64e7fc63 100644 --- a/masonry_core/src/core/contexts.rs +++ b/masonry_core/src/core/contexts.rs @@ -440,11 +440,11 @@ impl EventCtx<'_> { /// capture the pointer during any other event. /// /// A widget normally only receives pointer events when the pointer is inside the widget's - /// layout box. Pointer capture causes widget layout boxes to be ignored: when the pointer is + /// border-box. Pointer capture causes border-box hit checks to be ignored: when the pointer is /// captured by a widget, that widget will continue receiving pointer events when the pointer - /// is outside the widget's layout box. Other widgets the pointer is over will not receive + /// is outside the widget's border-box. Other widgets the pointer is over will not receive /// events. Events that are not marked as handled by the capturing widget, bubble up to the - /// widget's ancestors, ignoring their layout boxes as well. + /// widget's ancestors, ignoring their border-boxes as well. /// /// The pointer cannot be captured by multiple widgets at the same time. If a widget has /// captured the pointer and another widget captures it, the first widget loses the pointer @@ -1584,11 +1584,12 @@ impl_context_method!( self.widget_state.set_needs_layout(true); } - // TODO - Document better - /// Requests a [`compose`] pass. + /// Requests that this widget's [`compose`] method be called. /// /// The compose pass is often cheaper than the layout pass, /// because it can only transform individual widgets' position. + /// Use this when widget-owned state read by [`compose`] changes, + /// such as a scroll offset applied to a child during compose. /// /// [`compose`]: crate::core::Widget::compose pub fn request_compose(&mut self) { @@ -1920,7 +1921,9 @@ impl_context_method!( /// Removes the IME cursor area. /// - /// See [`LayoutCtx::set_ime_area`](LayoutCtx::set_ime_area) for more details. + /// See [`set_ime_area`] for more details. + /// + /// [`set_ime_area`]: Self::set_ime_area pub fn clear_ime_area(&mut self) { self.widget_state.ime_area = None; } diff --git a/masonry_core/src/core/widget.rs b/masonry_core/src/core/widget.rs index aaf6f0f57..767f3e55e 100644 --- a/masonry_core/src/core/widget.rs +++ b/masonry_core/src/core/widget.rs @@ -332,7 +332,7 @@ pub trait Widget: AsDynWidget + Any { /// 1. (Optionally) Call [`compute_size`] to get the border-box size the child wants to be. /// If the container has somehow already decided on the child length on one axis, then it /// should instead call [`compute_length`] with the correct border-box `cross_length`. - /// 2. Decide on a final border-box [`Size`] that the child should be. The parent is in control. + /// 2. Decide what the border-box [`Size`] of the child should be. The parent is in control. /// Note, however, that the child will still be in control of its own [`paint`] method. /// If a child is given a size smaller than its [`MinContent`], its painting is likely /// to overflow its bounds, depending on both the child's and the parent's clip settings. @@ -361,7 +361,14 @@ pub trait Widget: AsDynWidget + Any { /// [`MinContent`]: crate::layout::Dim::MinContent fn layout(&mut self, ctx: &mut LayoutCtx<'_>, props: &PropertiesRef<'_>, size: Size); - /// Runs after the widget's final transform has been computed. + /// Updates compose-only state like scroll translations. + /// + /// Cheaper alternative than doing a full layout. + /// + /// This method is guaranteed to be called after this widget's [`layout`] method runs, + /// and after this widget explicitly requests compose. It may also be called in other scenarios. + /// + /// [`layout`]: Self::layout fn compose(&mut self, ctx: &mut ComposeCtx<'_>) {} /// Paints the widget's background. diff --git a/masonry_core/src/core/widget_state.rs b/masonry_core/src/core/widget_state.rs index 63c189e0b..0227a6324 100644 --- a/masonry_core/src/core/widget_state.rs +++ b/masonry_core/src/core/widget_state.rs @@ -33,8 +33,8 @@ use crate::layout::MeasurementCache; /// Some fields follow a naming scheme: /// - `request_xxx`: this specific widget has requested the xxx pass to run on it. /// - `needs_xxx`: this widget or a descendant has requested the xxx pass to run on it. -/// - `is_xxx`: this widget has the xxx property. -/// - `has_xxx`: this widget or a descendant has the xxx property. +/// - `is_xxx`: this widget is in the xxx state. +/// - `has_xxx`: this widget or a descendant is in the xxx state. /// /// # Resetting flags /// diff --git a/masonry_core/src/doc/pass_system.md b/masonry_core/src/doc/pass_system.md index 8e9c2aa52..5f1521fde 100644 --- a/masonry_core/src/doc/pass_system.md +++ b/masonry_core/src/doc/pass_system.md @@ -68,7 +68,8 @@ To address these invalidations, Masonry runs a set of **rewrite passes** over th The layout pass may call [`Widget::measure`] any number of times, including zero. It may then call [`Widget::layout`]. -The compose pass will call [`Widget::compose`]. +The compose pass will call [`Widget::compose`] on widgets that requested compose. +Running [`Widget::layout`] also requests [`Widget::compose`] for that widget. The update_xxx passes call the widgets' update method. By default, each of these passes completes without doing any work, unless pass-dependent invalidation flags are set. @@ -189,7 +190,10 @@ Not doing so is a logical bug, and may trigger debug assertions. ### Compose pass The **compose** pass runs top-down and assigns transforms to children. -Transform-only layout changes (e.g. scrolling) should request compose instead of requesting layout. +Transform-only presentation changes (e.g. scrolling) should request compose instead of requesting layout. + +[`Widget::compose`] is called when the widget explicitly requests compose or after that widget's [`Widget::layout`] method runs. +It may also be called in other scenarios, but widgets should not rely on [`Widget::compose`] as a notification for every change to their window transform. Compose is meant to be a cheaper way to position widgets than layout. Because the compose pass is more limited than layout, it's easier to recompute in many situations. @@ -229,7 +233,7 @@ External mutation is how Xilem applies any changes to the widget tree produced b Some notes about pass context types: - Render passes should be pure and can be skipped occasionally, therefore their context types ([`PaintCtx`] and [`AccessCtx`]) can't set invalidation flags or send signals. -- The `layout` and `compose` passes lay out all widgets, which are transiently invalid during the passes, therefore [`MeasureCtx`], [`LayoutCtx`], and [`ComposeCtx`] cannot access the size and position of the `self` widget. +- The `layout` and `compose` passes lay out all widgets, which are transiently invalid during the passes, therefore [`MeasureCtx`] and [`LayoutCtx`] cannot access the size and position of the `self` widget. They can access the layout of children if they have already been laid out. - For the same reason, [`MeasureCtx`], [`LayoutCtx`], and [`ComposeCtx`] cannot create a `WidgetRef` reference to a child. - [`MutateCtx`], [`EventCtx`] and [`UpdateCtx`] can let you add and remove children. diff --git a/masonry_core/src/passes/layout.rs b/masonry_core/src/passes/layout.rs index 3c3967224..125ab0d5b 100644 --- a/masonry_core/src/passes/layout.rs +++ b/masonry_core/src/passes/layout.rs @@ -5,7 +5,7 @@ //! before any translations applied in [`compose`](crate::passes::compose). //! //! The framework helps orchestrate the size computation alongside [`Widget::measure`]. -//! The final chosen size is passed to [`Widget::layout`]. +//! The layout size is passed to [`Widget::layout`]. use dpi::LogicalSize; use tracing::{info_span, trace}; diff --git a/masonry_testing/src/harness.rs b/masonry_testing/src/harness.rs index 27570714f..59ea10d91 100644 --- a/masonry_testing/src/harness.rs +++ b/masonry_testing/src/harness.rs @@ -180,7 +180,7 @@ pub struct TestHarnessParams { /// This is useful: /// /// 1) For individual widgets, as they will often be designed with content outside their - /// layout box (e.g. drop shadows, focus indicators). + /// border-box (e.g. drop shadows, focus indicators). /// 2) For full apps, as it allows (manual) validation that none of the app content is cut off by /// the window border. /// @@ -694,7 +694,6 @@ impl TestHarness { pub fn mouse_move_to(&mut self, id: WidgetId) { let widget = self.get_widget_with_id(id); let local_widget_center = widget.ctx().border_box().center(); - let widget_center = widget.ctx().window_transform() * local_widget_center; // TODO - Add reachable_by_pointer() method.