diff --git a/masonry/src/widget/zstack.rs b/masonry/src/widget/zstack.rs index 2a5fe7c1e..98cf6a164 100644 --- a/masonry/src/widget/zstack.rs +++ b/masonry/src/widget/zstack.rs @@ -1,6 +1,8 @@ // Copyright 2024 the Xilem Authors // SPDX-License-Identifier: Apache-2.0 +#![warn(missing_docs)] + use crate::{ vello::Scene, widget::WidgetMut, AccessCtx, BoxConstraints, LayoutCtx, PaintCtx, Point, QueryCtx, RegisterCtx, Size, Widget, WidgetId, WidgetPod, @@ -14,15 +16,19 @@ struct Child { alignment: ChildAlignment, } +/// An option specifying how a child widget is aligned within a [`ZStack`]. #[derive(Clone, Copy, PartialEq, Eq)] pub enum ChildAlignment { + /// Specifies that the child should use the global alignment as specified by the parent [`ZStack`] widget. ParentAligned, + /// Specifies that the child should override the global alignment specified by the parent [`ZStack`] widget. SelfAligned(Alignment), } /// A widget container that lays the child widgets on top of each other. /// -/// The alignment of how the children are placed can be specified using [`with_alignment`][Self::with_alignment]. +/// The alignment of how the children are placed can be specified globally using [`with_alignment`][Self::with_alignment]. +/// Each child can additionally override the global alignment using [`ChildAlignment::SelfAligned`]. #[derive(Default)] pub struct ZStack { children: Vec, @@ -34,15 +40,24 @@ pub struct ZStack { /// See also [`VerticalAlignment`] and [`HorizontalAlignment`] for describing only a single axis. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum Alignment { + /// Align to the top leading corner. TopLeading, + /// Align to the center of the top edge. Top, + /// Align to the top trailing corner. TopTrailing, + /// Align to the center of the leading edge. Leading, + /// Align to the center. #[default] Center, + /// Align to the center of the trailing edge. Trailing, + /// Align to the bottom leading corner. BottomLeading, + /// Align to the center of the bottom edge. Bottom, + /// Align to the bottom trailing corner. BottomTrailing, } @@ -50,9 +65,12 @@ pub enum Alignment { /// See also [Alignment]. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum VerticalAlignment { + /// Align to the top edge. Top, + /// Align to the center. #[default] Center, + /// Align to the bottom edge. Bottom, } @@ -60,9 +78,12 @@ pub enum VerticalAlignment { /// See also [Alignment]. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum HorizontalAlignment { + /// Align to the leading edge. Leading, #[default] + /// Align to the center. Center, + /// Align to the trailing edge. Trailing, } @@ -178,6 +199,7 @@ impl ZStack { self.with_child_pod(WidgetPod::new(Box::new(child)), alignment) } + /// Appends a child widget with a given `id` to the `ZStack`. pub fn with_child_id( self, child: impl Widget, @@ -187,6 +209,9 @@ impl ZStack { self.with_child_pod(WidgetPod::new_with_id(Box::new(child), id), alignment) } + /// Appends a child widget pod to the `ZStack`. + /// + /// See also [`Self::with_child`] if the widget is not already wrapped in a [`WidgetPod`]. pub fn with_child_pod( mut self, child: WidgetPod>, @@ -213,6 +238,9 @@ impl ZStack { Self::insert_child_pod(this, child_pod, alignment); } + /// Add a child widget with a given `id` to the `ZStack`. + /// + /// See [`Self::add_child`] for more details. pub fn add_child_id( this: &mut WidgetMut<'_, Self>, child: impl Widget, @@ -235,12 +263,14 @@ impl ZStack { this.ctx.request_layout(); } + /// Remove a child from the `ZStack`. pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) { let child = this.widget.children.remove(idx); this.ctx.remove_child(child.widget); this.ctx.request_layout(); } + /// Get a mutable reference to a child of the `ZStack`. pub fn child_mut<'t>( this: &'t mut WidgetMut<'_, Self>, idx: usize, @@ -249,7 +279,7 @@ impl ZStack { Some(this.ctx.get_mut(child)) } - /// Changes the alignment of the widget. + /// Change the alignment of the `ZStack`. /// /// See also [`with_alignment`][Self::with_alignment]. pub fn set_alignment(this: &mut WidgetMut<'_, Self>, alignment: impl Into) { @@ -257,6 +287,7 @@ impl ZStack { this.ctx.request_layout(); } + /// Change the alignment of a child of the `ZStack`. pub fn update_child_alignment( this: &mut WidgetMut<'_, Self>, idx: usize, @@ -282,9 +313,8 @@ impl Widget for ZStack { } // Second pass: place the children given the calculated max_size bounds. - let child_bc = BoxConstraints::new(Size::ZERO, max_size); for child in &mut self.children { - let child_size = ctx.run_layout(&mut child.widget, &child_bc); + let child_size = ctx.child_size(&child.widget); let end = max_size - child_size; let end = Point::new(end.width, end.height); diff --git a/xilem/examples/http_cats.rs b/xilem/examples/http_cats.rs index 9aa7f7a0c..902047479 100644 --- a/xilem/examples/http_cats.rs +++ b/xilem/examples/http_cats.rs @@ -210,7 +210,6 @@ impl Status { .rounded(4.) .background(Color::BLACK.multiply_alpha(0.5)), ) - // HACK: Trailing padding workaround scrollbar covering content .padding((30., 42., 0., 0.)) .alignment(Alignment::TopTrailing), )), diff --git a/xilem/src/view/zstack.rs b/xilem/src/view/zstack.rs index 902c7f3a2..50f8dbd7f 100644 --- a/xilem/src/view/zstack.rs +++ b/xilem/src/view/zstack.rs @@ -1,6 +1,8 @@ // Copyright 2024 the Xilem Authors // SPDX-License-Identifier: Apache-2.0 +#![warn(missing_docs)] + use std::marker::PhantomData; use crate::{ @@ -25,12 +27,12 @@ use xilem_core::{MessageResult, ViewId}; /// /// ``` /// use xilem::WidgetView; -/// use xilem::view::{zstack, label}; +/// use xilem::view::{zstack, label, button}; /// -/// fn view() -> impl WidgetView<()> { -/// zstack::<(), (), _>(( +/// fn view() -> impl WidgetView { +/// zstack(( /// label("Background"), -/// label("Foreground") +/// button("Click me", |_| {}) /// )) /// } /// ``` @@ -90,7 +92,7 @@ where widget::ZStack::set_alignment(&mut element, self.alignment); } - let mut splice = StackSplice::new(element); + let mut splice = ZStackSplice::new(element); self.sequence .seq_rebuild(&prev.sequence, view_state, ctx, &mut splice); debug_assert!(splice.scratch.is_empty()); @@ -102,7 +104,7 @@ where ctx: &mut ViewCtx, element: Mut, ) { - let mut splice = StackSplice::new(element); + let mut splice = ZStackSplice::new(element); self.sequence.seq_teardown(view_state, ctx, &mut splice); debug_assert!(splice.scratch.into_inner().is_empty()); } @@ -121,7 +123,11 @@ where // --- MARK: ZStackExt --- +/// A trait that extends a [`WidgetView`] with methods to provide parameters for a parent [`ZStack`]. pub trait ZStackExt: WidgetView { + /// Applies [`ChildAlignment`] to this view. + /// This allows the view to override the default [`Alignment`] of the parent [`ZStack`]. + /// This can only be used on views that are direct children of a [`ZStack`]. fn alignment(self, alignment: impl Into) -> ZStackItem where State: 'static, @@ -134,12 +140,16 @@ pub trait ZStackExt: WidgetView { impl> ZStackExt for V {} +/// A wrapper around a [`WidgetView`], with a specified [`ChildAlignment`]. +/// This struct is most often constructed indrectly using [`ZStackExt::alignment`]. pub struct ZStackItem { view: V, alignment: ChildAlignment, phantom: PhantomData (State, Action)>, } +/// Constructs a new `ZStackItem`. +/// See also [`ZStackExt::alignment`], for constructing a `ZStackItem` from an existing view. pub fn zstack_item( view: V, alignment: impl Into, @@ -221,11 +231,14 @@ where } // --- MARK: ZStackElement --- + +/// A struct implementing [`ViewElement`] for a `ZStack`. pub struct ZStackElement { widget: Pod>, alignment: ChildAlignment, } +/// A mutable version of `ZStackElement`. pub struct ZStackElementMut<'w> { parent: WidgetMut<'w, widget::ZStack>, idx: usize, @@ -283,6 +296,8 @@ impl SuperElement, ViewCtx> for ZStackElement { } // MARK: Sequence + +/// A trait implementing `ViewSequence` for `ZStackElements`. pub trait ZStackSequence: ViewSequence { @@ -295,13 +310,14 @@ impl ZStackSequence for Seq where // MARK: Splice -pub struct StackSplice<'w> { +/// An implementation of [`ElementSplice`] for `ZStackElements`. +pub struct ZStackSplice<'w> { idx: usize, element: WidgetMut<'w, widget::ZStack>, scratch: AppendVec, } -impl<'w> StackSplice<'w> { +impl<'w> ZStackSplice<'w> { fn new(element: WidgetMut<'w, widget::ZStack>) -> Self { Self { idx: 0, @@ -311,7 +327,7 @@ impl<'w> StackSplice<'w> { } } -impl ElementSplice for StackSplice<'_> { +impl ElementSplice for ZStackSplice<'_> { fn with_scratch(&mut self, f: impl FnOnce(&mut AppendVec) -> R) -> R { let ret = f(&mut self.scratch); for element in self.scratch.drain() {