Use nightly feature `arbitrary_self_types`

This commit is contained in:
Olivier FAURE 2025-01-27 12:23:23 +01:00
parent d77b31b892
commit f0d715802b
20 changed files with 376 additions and 372 deletions

View File

@ -1,6 +1,8 @@
// Copyright 2018 the Xilem Authors and the Druid Authors // Copyright 2018 the Xilem Authors and the Druid Authors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::ops::Receiver;
use crate::core::{FromDynWidget, MutateCtx, Widget}; use crate::core::{FromDynWidget, MutateCtx, Widget};
use crate::kurbo::Affine; use crate::kurbo::Affine;
@ -28,6 +30,10 @@ pub struct WidgetMut<'a, W: Widget + ?Sized> {
pub widget: &'a mut W, pub widget: &'a mut W,
} }
impl<W: Widget + ?Sized> Receiver for WidgetMut<'_, W> {
type Target = W;
}
impl<W: Widget + ?Sized> Drop for WidgetMut<'_, W> { impl<W: Widget + ?Sized> Drop for WidgetMut<'_, W> {
fn drop(&mut self) { fn drop(&mut self) {
// If this `WidgetMut` is a reborrow, a parent non-reborrow `WidgetMut` // If this `WidgetMut` is a reborrow, a parent non-reborrow `WidgetMut`

View File

@ -144,6 +144,7 @@
reason = "Potentially controversial code style" reason = "Potentially controversial code style"
)] )]
#![expect(clippy::single_match, reason = "General policy not decided")] #![expect(clippy::single_match, reason = "General policy not decided")]
#![feature(arbitrary_self_types)]
// TODO - Add logo // TODO - Add logo

View File

@ -75,12 +75,12 @@ impl Button {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl Button { impl Button {
/// Set the text. /// Set the text.
pub fn set_text(this: &mut WidgetMut<'_, Self>, new_text: impl Into<ArcStr>) { pub fn set_text(self: &mut WidgetMut<'_, Self>, new_text: impl Into<ArcStr>) {
Label::set_text(&mut Self::label_mut(this), new_text); Label::set_text(&mut self.label_mut(), new_text);
} }
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> { pub fn label_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
this.ctx.get_mut(&mut this.widget.label) self.ctx.get_mut(&mut self.widget.label)
} }
} }

View File

@ -46,21 +46,21 @@ impl Checkbox {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl Checkbox { impl Checkbox {
pub fn set_checked(this: &mut WidgetMut<'_, Self>, checked: bool) { pub fn set_checked(self: &mut WidgetMut<'_, Self>, checked: bool) {
this.widget.checked = checked; self.widget.checked = checked;
// Checked state impacts appearance and accessibility node // Checked state impacts appearance and accessibility node
this.ctx.request_render(); self.ctx.request_render();
} }
/// Set the text. /// Set the text.
/// ///
/// We enforce this to be an `ArcStr` to make the allocation explicit. /// We enforce this to be an `ArcStr` to make the allocation explicit.
pub fn set_text(this: &mut WidgetMut<'_, Self>, new_text: ArcStr) { pub fn set_text(self: &mut WidgetMut<'_, Self>, new_text: ArcStr) {
Label::set_text(&mut Self::label_mut(this), new_text); Label::set_text(&mut self.label_mut(), new_text);
} }
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> { pub fn label_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
this.ctx.get_mut(&mut this.widget.label) self.ctx.get_mut(&mut self.widget.label)
} }
} }
@ -288,15 +288,12 @@ mod tests {
harness.edit_root_widget(|mut checkbox| { harness.edit_root_widget(|mut checkbox| {
let mut checkbox = checkbox.downcast::<Checkbox>(); let mut checkbox = checkbox.downcast::<Checkbox>();
Checkbox::set_checked(&mut checkbox, true); checkbox.set_checked(true);
Checkbox::set_text( checkbox.set_text("The quick brown fox jumps over the lazy dog".into());
&mut checkbox,
ArcStr::from("The quick brown fox jumps over the lazy dog"),
);
let mut label = Checkbox::label_mut(&mut checkbox); let mut label = checkbox.label_mut();
Label::set_brush(&mut label, PRIMARY_LIGHT); label.set_brush(PRIMARY_LIGHT);
Label::insert_style(&mut label, StyleProperty::FontSize(20.0)); label.insert_style(StyleProperty::FontSize(20.0));
}); });
harness.render() harness.render()

View File

@ -305,28 +305,28 @@ impl Flex {
// --- MARK: WIDGETMUT--- // --- MARK: WIDGETMUT---
impl Flex { impl Flex {
/// Set the flex direction (see [`Axis`]). /// Set the flex direction (see [`Axis`]).
pub fn set_direction(this: &mut WidgetMut<'_, Self>, direction: Axis) { pub fn set_direction(self: &mut WidgetMut<'_, Self>, direction: Axis) {
this.widget.direction = direction; self.widget.direction = direction;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the childrens' [`CrossAxisAlignment`]. /// Set the childrens' [`CrossAxisAlignment`].
pub fn set_cross_axis_alignment(this: &mut WidgetMut<'_, Self>, alignment: CrossAxisAlignment) { pub fn set_cross_axis_alignment(self: &mut WidgetMut<'_, Self>, alignment: CrossAxisAlignment) {
this.widget.cross_alignment = alignment; self.widget.cross_alignment = alignment;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the childrens' [`MainAxisAlignment`]. /// Set the childrens' [`MainAxisAlignment`].
pub fn set_main_axis_alignment(this: &mut WidgetMut<'_, Self>, alignment: MainAxisAlignment) { pub fn set_main_axis_alignment(self: &mut WidgetMut<'_, Self>, alignment: MainAxisAlignment) {
this.widget.main_alignment = alignment; self.widget.main_alignment = alignment;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set whether the container must expand to fill the available space on /// Set whether the container must expand to fill the available space on
/// its main axis. /// its main axis.
pub fn set_must_fill_main_axis(this: &mut WidgetMut<'_, Self>, fill: bool) { pub fn set_must_fill_main_axis(self: &mut WidgetMut<'_, Self>, fill: bool) {
this.widget.fill_major_axis = fill; self.widget.fill_major_axis = fill;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the spacing along the major axis between any two elements in logical pixels. /// Set the spacing along the major axis between any two elements in logical pixels.
@ -341,13 +341,13 @@ impl Flex {
/// If `gap` is not a non-negative finite value. /// If `gap` is not a non-negative finite value.
/// ///
/// See also [`use_default_gap`](Self::use_default_gap). /// See also [`use_default_gap`](Self::use_default_gap).
pub fn set_gap(this: &mut WidgetMut<'_, Self>, gap: f64) { pub fn set_gap(self: &mut WidgetMut<'_, Self>, gap: f64) {
if gap.is_finite() && gap >= 0.0 { if gap.is_finite() && gap >= 0.0 {
this.widget.gap = Some(gap); self.widget.gap = Some(gap);
} else { } else {
panic!("Invalid `gap` {gap}, expected a non-negative finite value.") panic!("Invalid `gap` {gap}, expected a non-negative finite value.")
} }
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Use the default gap value. /// Use the default gap value.
@ -359,18 +359,18 @@ impl Flex {
/// ///
/// [`WIDGET_PADDING_VERTICAL`]: crate::theme::WIDGET_PADDING_VERTICAL /// [`WIDGET_PADDING_VERTICAL`]: crate::theme::WIDGET_PADDING_VERTICAL
/// [`WIDGET_PADDING_HORIZONTAL`]: crate::theme::WIDGET_PADDING_VERTICAL /// [`WIDGET_PADDING_HORIZONTAL`]: crate::theme::WIDGET_PADDING_VERTICAL
pub fn use_default_gap(this: &mut WidgetMut<'_, Self>) { pub fn use_default_gap(self: &mut WidgetMut<'_, Self>) {
this.widget.gap = None; self.widget.gap = None;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Equivalent to [`set_gap`](Self::set_gap) if `gap` is `Some`, or /// Equivalent to [`set_gap`](Self::set_gap) if `gap` is `Some`, or
/// [`use_default_gap`](Self::use_default_gap) otherwise. /// [`use_default_gap`](Self::use_default_gap) otherwise.
/// ///
/// Does not perform validation of the provided value. /// Does not perform validation of the provided value.
pub fn set_raw_gap(this: &mut WidgetMut<'_, Self>, gap: Option<f64>) { pub fn set_raw_gap(self: &mut WidgetMut<'_, Self>, gap: Option<f64>) {
this.widget.gap = gap; self.widget.gap = gap;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Add a non-flex child widget. /// Add a non-flex child widget.
@ -378,45 +378,45 @@ impl Flex {
/// See also [`with_child`]. /// See also [`with_child`].
/// ///
/// [`with_child`]: Flex::with_child /// [`with_child`]: Flex::with_child
pub fn add_child(this: &mut WidgetMut<'_, Self>, child: impl Widget) { pub fn add_child(self: &mut WidgetMut<'_, Self>, child: impl Widget) {
let child = Child::Fixed { let child = Child::Fixed {
widget: WidgetPod::new(child).erased(), widget: WidgetPod::new(child).erased(),
alignment: None, alignment: None,
}; };
this.widget.children.push(child); self.widget.children.push(child);
this.ctx.children_changed(); self.ctx.children_changed();
} }
pub fn add_child_id(this: &mut WidgetMut<'_, Self>, child: impl Widget, id: WidgetId) { pub fn add_child_id(self: &mut WidgetMut<'_, Self>, child: impl Widget, id: WidgetId) {
let child = Child::Fixed { let child = Child::Fixed {
widget: WidgetPod::new_with_id(child, id).erased(), widget: WidgetPod::new_with_id(child, id).erased(),
alignment: None, alignment: None,
}; };
this.widget.children.push(child); self.widget.children.push(child);
this.ctx.children_changed(); self.ctx.children_changed();
} }
/// Add a flexible child widget. /// Add a flexible child widget.
pub fn add_flex_child( pub fn add_flex_child(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
child: impl Widget, child: impl Widget,
params: impl Into<FlexParams>, params: impl Into<FlexParams>,
) { ) {
let params = params.into(); let params = params.into();
let child = new_flex_child(params, WidgetPod::new(child).erased()); let child = new_flex_child(params, WidgetPod::new(child).erased());
this.widget.children.push(child); self.widget.children.push(child);
this.ctx.children_changed(); self.ctx.children_changed();
} }
/// Add a spacer widget with a standard size. /// Add a spacer widget with a standard size.
/// ///
/// The actual value of this spacer depends on whether this container is /// The actual value of this spacer depends on whether this container is
/// a row or column, as well as theme settings. /// a row or column, as well as theme settings.
pub fn add_default_spacer(this: &mut WidgetMut<'_, Self>) { pub fn add_default_spacer(self: &mut WidgetMut<'_, Self>) {
let key = axis_default_spacer(this.widget.direction); let key = axis_default_spacer(self.widget.direction);
Self::add_spacer(this, key); self.add_spacer(key);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Add an empty spacer widget with the given size. /// Add an empty spacer widget with the given size.
@ -425,19 +425,19 @@ impl Flex {
/// generally prefer to use [`add_default_spacer`]. /// generally prefer to use [`add_default_spacer`].
/// ///
/// [`add_default_spacer`]: Flex::add_default_spacer /// [`add_default_spacer`]: Flex::add_default_spacer
pub fn add_spacer(this: &mut WidgetMut<'_, Self>, mut len: f64) { pub fn add_spacer(self: &mut WidgetMut<'_, Self>, mut len: f64) {
if len < 0.0 { if len < 0.0 {
tracing::warn!("add_spacer called with negative length: {}", len); tracing::warn!("add_spacer called with negative length: {}", len);
} }
len = len.clamp(0.0, f64::MAX); len = len.clamp(0.0, f64::MAX);
let new_child = Child::FixedSpacer(len, 0.0); let new_child = Child::FixedSpacer(len, 0.0);
this.widget.children.push(new_child); self.widget.children.push(new_child);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Add an empty spacer widget with a specific `flex` factor. /// Add an empty spacer widget with a specific `flex` factor.
pub fn add_flex_spacer(this: &mut WidgetMut<'_, Self>, flex: f64) { pub fn add_flex_spacer(self: &mut WidgetMut<'_, Self>, flex: f64) {
let flex = if flex >= 0.0 { let flex = if flex >= 0.0 {
flex flex
} else { } else {
@ -445,8 +445,8 @@ impl Flex {
0.0 0.0
}; };
let new_child = Child::FlexedSpacer(flex, 0.0); let new_child = Child::FlexedSpacer(flex, 0.0);
this.widget.children.push(new_child); self.widget.children.push(new_child);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Add a non-flex child widget. /// Add a non-flex child widget.
@ -454,13 +454,13 @@ impl Flex {
/// See also [`with_child`]. /// See also [`with_child`].
/// ///
/// [`with_child`]: Flex::with_child /// [`with_child`]: Flex::with_child
pub fn insert_child(this: &mut WidgetMut<'_, Self>, idx: usize, child: impl Widget) { pub fn insert_child(self: &mut WidgetMut<'_, Self>, idx: usize, child: impl Widget) {
Self::insert_child_pod(this, idx, WidgetPod::new(child).erased()); self.insert_child_pod(idx, WidgetPod::new(child).erased());
} }
/// Add a non-flex child widget. /// Add a non-flex child widget.
pub fn insert_child_pod( pub fn insert_child_pod(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
widget: WidgetPod<dyn Widget>, widget: WidgetPod<dyn Widget>,
) { ) {
@ -468,28 +468,28 @@ impl Flex {
widget, widget,
alignment: None, alignment: None,
}; };
this.widget.children.insert(idx, child); self.widget.children.insert(idx, child);
this.ctx.children_changed(); self.ctx.children_changed();
} }
pub fn insert_flex_child( pub fn insert_flex_child(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
child: impl Widget, child: impl Widget,
params: impl Into<FlexParams>, params: impl Into<FlexParams>,
) { ) {
Self::insert_flex_child_pod(this, idx, WidgetPod::new(child).erased(), params); self.insert_flex_child_pod(idx, WidgetPod::new(child).erased(), params);
} }
pub fn insert_flex_child_pod( pub fn insert_flex_child_pod(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
child: WidgetPod<dyn Widget>, child: WidgetPod<dyn Widget>,
params: impl Into<FlexParams>, params: impl Into<FlexParams>,
) { ) {
let child = new_flex_child(params.into(), child); let child = new_flex_child(params.into(), child);
this.widget.children.insert(idx, child); self.widget.children.insert(idx, child);
this.ctx.children_changed(); self.ctx.children_changed();
} }
// TODO - remove // TODO - remove
@ -497,10 +497,10 @@ impl Flex {
/// ///
/// The actual value of this spacer depends on whether this container is /// The actual value of this spacer depends on whether this container is
/// a row or column, as well as theme settings. /// a row or column, as well as theme settings.
pub fn insert_default_spacer(this: &mut WidgetMut<'_, Self>, idx: usize) { pub fn insert_default_spacer(self: &mut WidgetMut<'_, Self>, idx: usize) {
let key = axis_default_spacer(this.widget.direction); let key = axis_default_spacer(self.widget.direction);
Self::insert_spacer(this, idx, key); self.insert_spacer(idx, key);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Add an empty spacer widget with the given size. /// Add an empty spacer widget with the given size.
@ -509,19 +509,19 @@ impl Flex {
/// generally prefer to use [`add_default_spacer`]. /// generally prefer to use [`add_default_spacer`].
/// ///
/// [`add_default_spacer`]: Flex::add_default_spacer /// [`add_default_spacer`]: Flex::add_default_spacer
pub fn insert_spacer(this: &mut WidgetMut<'_, Self>, idx: usize, mut len: f64) { pub fn insert_spacer(self: &mut WidgetMut<'_, Self>, idx: usize, mut len: f64) {
if len < 0.0 { if len < 0.0 {
tracing::warn!("add_spacer called with negative length: {}", len); tracing::warn!("add_spacer called with negative length: {}", len);
} }
len = len.clamp(0.0, f64::MAX); len = len.clamp(0.0, f64::MAX);
let new_child = Child::FixedSpacer(len, 0.0); let new_child = Child::FixedSpacer(len, 0.0);
this.widget.children.insert(idx, new_child); self.widget.children.insert(idx, new_child);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Add an empty spacer widget with a specific `flex` factor. /// Add an empty spacer widget with a specific `flex` factor.
pub fn insert_flex_spacer(this: &mut WidgetMut<'_, Self>, idx: usize, flex: f64) { pub fn insert_flex_spacer(self: &mut WidgetMut<'_, Self>, idx: usize, flex: f64) {
let flex = if flex >= 0.0 { let flex = if flex >= 0.0 {
flex flex
} else { } else {
@ -529,29 +529,29 @@ impl Flex {
0.0 0.0
}; };
let new_child = Child::FlexedSpacer(flex, 0.0); let new_child = Child::FlexedSpacer(flex, 0.0);
this.widget.children.insert(idx, new_child); self.widget.children.insert(idx, new_child);
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) { pub fn remove_child(self: &mut WidgetMut<'_, Self>, idx: usize) {
let child = this.widget.children.remove(idx); let child = self.widget.children.remove(idx);
if let Child::Fixed { widget, .. } | Child::Flex { widget, .. } = child { if let Child::Fixed { widget, .. } | Child::Flex { widget, .. } = child {
this.ctx.remove_child(widget); self.ctx.remove_child(widget);
} }
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn child_mut<'t>( pub fn child_mut<'t>(
this: &'t mut WidgetMut<'_, Self>, self: &'t mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
) -> Option<WidgetMut<'t, dyn Widget>> { ) -> Option<WidgetMut<'t, dyn Widget>> {
let child = match &mut this.widget.children[idx] { let child = match &mut self.widget.children[idx] {
Child::Fixed { widget, .. } | Child::Flex { widget, .. } => widget, Child::Fixed { widget, .. } | Child::Flex { widget, .. } => widget,
Child::FixedSpacer(..) => return None, Child::FixedSpacer(..) => return None,
Child::FlexedSpacer(..) => return None, Child::FlexedSpacer(..) => return None,
}; };
Some(this.ctx.get_mut(child)) Some(self.ctx.get_mut(child))
} }
/// Updates the flex parameters for the child at `idx`, /// Updates the flex parameters for the child at `idx`,
@ -560,11 +560,11 @@ impl Flex {
/// ///
/// Panics if the element at `idx` is not a widget. /// Panics if the element at `idx` is not a widget.
pub fn update_child_flex_params( pub fn update_child_flex_params(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
params: impl Into<FlexParams>, params: impl Into<FlexParams>,
) { ) {
let child = &mut this.widget.children[idx]; let child = &mut self.widget.children[idx];
let child_val = std::mem::replace(child, Child::FixedSpacer(0.0, 0.0)); let child_val = std::mem::replace(child, Child::FixedSpacer(0.0, 0.0));
let widget = match child_val { let widget = match child_val {
Child::Fixed { widget, .. } | Child::Flex { widget, .. } => widget, Child::Fixed { widget, .. } | Child::Flex { widget, .. } => widget,
@ -574,7 +574,7 @@ impl Flex {
}; };
let new_child = new_flex_child(params.into(), widget); let new_child = new_flex_child(params.into(), widget);
*child = new_child; *child = new_child;
this.ctx.children_changed(); self.ctx.children_changed();
} }
/// Updates the spacer at `idx`, if the spacer was a fixed spacer, it will be overwritten with a flex spacer /// Updates the spacer at `idx`, if the spacer was a fixed spacer, it will be overwritten with a flex spacer
@ -582,8 +582,8 @@ impl Flex {
/// # Panics /// # Panics
/// ///
/// Panics if the element at `idx` is not a spacer. /// Panics if the element at `idx` is not a spacer.
pub fn update_spacer_flex(this: &mut WidgetMut<'_, Self>, idx: usize, flex: f64) { pub fn update_spacer_flex(self: &mut WidgetMut<'_, Self>, idx: usize, flex: f64) {
let child = &mut this.widget.children[idx]; let child = &mut self.widget.children[idx];
match *child { match *child {
Child::FixedSpacer(_, _) | Child::FlexedSpacer(_, _) => { Child::FixedSpacer(_, _) | Child::FlexedSpacer(_, _) => {
@ -593,7 +593,7 @@ impl Flex {
panic!("Can't update spacer parameters of a non-spacer element"); panic!("Can't update spacer parameters of a non-spacer element");
} }
}; };
this.ctx.children_changed(); self.ctx.children_changed();
} }
/// Updates the spacer at `idx`, if the spacer was a flex spacer, it will be overwritten with a fixed spacer /// Updates the spacer at `idx`, if the spacer was a flex spacer, it will be overwritten with a fixed spacer
@ -601,8 +601,8 @@ impl Flex {
/// # Panics /// # Panics
/// ///
/// Panics if the element at `idx` is not a spacer. /// Panics if the element at `idx` is not a spacer.
pub fn update_spacer_fixed(this: &mut WidgetMut<'_, Self>, idx: usize, len: f64) { pub fn update_spacer_fixed(self: &mut WidgetMut<'_, Self>, idx: usize, len: f64) {
let child = &mut this.widget.children[idx]; let child = &mut self.widget.children[idx];
match *child { match *child {
Child::FixedSpacer(_, _) | Child::FlexedSpacer(_, _) => { Child::FixedSpacer(_, _) | Child::FlexedSpacer(_, _) => {
@ -612,16 +612,16 @@ impl Flex {
panic!("Can't update spacer parameters of a non-spacer element"); panic!("Can't update spacer parameters of a non-spacer element");
} }
}; };
this.ctx.children_changed(); self.ctx.children_changed();
} }
pub fn clear(this: &mut WidgetMut<'_, Self>) { pub fn clear(self: &mut WidgetMut<'_, Self>) {
if !this.widget.children.is_empty() { if !self.widget.children.is_empty() {
this.ctx.request_layout(); self.ctx.request_layout();
for child in this.widget.children.drain(..) { for child in self.widget.children.drain(..) {
if let Child::Fixed { widget, .. } | Child::Flex { widget, .. } = child { if let Child::Fixed { widget, .. } | Child::Flex { widget, .. } = child {
this.ctx.remove_child(widget); self.ctx.remove_child(widget);
} }
} }
} }

View File

@ -147,75 +147,75 @@ impl Grid {
/// See also [`with_child`]. /// See also [`with_child`].
/// ///
/// [`with_child`]: Grid::with_child /// [`with_child`]: Grid::with_child
pub fn add_child(this: &mut WidgetMut<'_, Self>, child: impl Widget, params: GridParams) { pub fn add_child(self: &mut WidgetMut<'_, Self>, child: impl Widget, params: GridParams) {
let child_pod: WidgetPod<dyn Widget> = WidgetPod::new(child).erased(); let child_pod: WidgetPod<dyn Widget> = WidgetPod::new(child).erased();
Self::insert_child_pod(this, child_pod, params); self.insert_child_pod(child_pod, params);
} }
pub fn add_child_id( pub fn add_child_id(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
child: impl Widget, child: impl Widget,
id: WidgetId, id: WidgetId,
params: GridParams, params: GridParams,
) { ) {
let child_pod: WidgetPod<dyn Widget> = WidgetPod::new_with_id(child, id).erased(); let child_pod: WidgetPod<dyn Widget> = WidgetPod::new_with_id(child, id).erased();
Self::insert_child_pod(this, child_pod, params); self.insert_child_pod(child_pod, params);
} }
/// Add a child widget. /// Add a child widget.
pub fn insert_child_pod( pub fn insert_child_pod(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
widget: WidgetPod<dyn Widget>, widget: WidgetPod<dyn Widget>,
params: GridParams, params: GridParams,
) { ) {
let child = new_grid_child(params, widget); let child = new_grid_child(params, widget);
this.widget.children.push(child); self.widget.children.push(child);
this.ctx.children_changed(); self.ctx.children_changed();
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn insert_grid_child_at( pub fn insert_grid_child_at(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
child: impl Widget, child: impl Widget,
params: impl Into<GridParams>, params: impl Into<GridParams>,
) { ) {
Self::insert_grid_child_pod(this, idx, WidgetPod::new(child).erased(), params); self.insert_grid_child_pod(idx, WidgetPod::new(child).erased(), params);
} }
pub fn insert_grid_child_pod( pub fn insert_grid_child_pod(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
child: WidgetPod<dyn Widget>, child: WidgetPod<dyn Widget>,
params: impl Into<GridParams>, params: impl Into<GridParams>,
) { ) {
let child = new_grid_child(params.into(), child); let child = new_grid_child(params.into(), child);
this.widget.children.insert(idx, child); self.widget.children.insert(idx, child);
this.ctx.children_changed(); self.ctx.children_changed();
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn set_spacing(this: &mut WidgetMut<'_, Self>, spacing: f64) { pub fn set_spacing(self: &mut WidgetMut<'_, Self>, spacing: f64) {
this.widget.grid_spacing = spacing; self.widget.grid_spacing = spacing;
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn set_width(this: &mut WidgetMut<'_, Self>, width: i32) { pub fn set_width(self: &mut WidgetMut<'_, Self>, width: i32) {
this.widget.grid_width = width; self.widget.grid_width = width;
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn set_height(this: &mut WidgetMut<'_, Self>, height: i32) { pub fn set_height(self: &mut WidgetMut<'_, Self>, height: i32) {
this.widget.grid_height = height; self.widget.grid_height = height;
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn child_mut<'t>( pub fn child_mut<'t>(
this: &'t mut WidgetMut<'_, Self>, self: &'t mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
) -> Option<WidgetMut<'t, dyn Widget>> { ) -> Option<WidgetMut<'t, dyn Widget>> {
let child = this.widget.children[idx].widget_mut()?; let child = self.widget.children[idx].widget_mut()?;
Some(this.ctx.get_mut(child)) Some(self.ctx.get_mut(child))
} }
/// Updates the grid parameters for the child at `idx`, /// Updates the grid parameters for the child at `idx`,
@ -224,19 +224,19 @@ impl Grid {
/// ///
/// Panics if the element at `idx` is not a widget. /// Panics if the element at `idx` is not a widget.
pub fn update_child_grid_params( pub fn update_child_grid_params(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
params: GridParams, params: GridParams,
) { ) {
let child = &mut this.widget.children[idx]; let child = &mut self.widget.children[idx];
child.update_params(params); child.update_params(params);
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) { pub fn remove_child(self: &mut WidgetMut<'_, Self>, idx: usize) {
let child = this.widget.children.remove(idx); let child = self.widget.children.remove(idx);
this.ctx.remove_child(child.widget); self.ctx.remove_child(child.widget);
this.ctx.request_layout(); self.ctx.request_layout();
} }
} }

View File

@ -56,16 +56,16 @@ impl Image {
impl Image { impl Image {
/// Modify the widget's object fit. /// Modify the widget's object fit.
#[inline] #[inline]
pub fn set_fit_mode(this: &mut WidgetMut<'_, Self>, new_object_fit: ObjectFit) { pub fn set_fit_mode(self: &mut WidgetMut<'_, Self>, new_object_fit: ObjectFit) {
this.widget.object_fit = new_object_fit; self.widget.object_fit = new_object_fit;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set new `ImageBuf`. /// Set new `ImageBuf`.
#[inline] #[inline]
pub fn set_image_data(this: &mut WidgetMut<'_, Self>, image_data: ImageBuf) { pub fn set_image_data(self: &mut WidgetMut<'_, Self>, image_data: ImageBuf) {
this.widget.image_data = image_data; self.widget.image_data = image_data;
this.ctx.request_layout(); self.ctx.request_layout();
} }
} }

View File

@ -213,13 +213,13 @@ impl Label {
/// Setting [`StyleProperty::Brush`](parley::StyleProperty::Brush) is not supported. /// Setting [`StyleProperty::Brush`](parley::StyleProperty::Brush) is not supported.
/// Use [`set_brush`](Self::set_brush) instead. /// Use [`set_brush`](Self::set_brush) instead.
pub fn insert_style( pub fn insert_style(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
property: impl Into<StyleProperty>, property: impl Into<StyleProperty>,
) -> Option<StyleProperty> { ) -> Option<StyleProperty> {
let old = this.widget.insert_style_inner(property.into()); let old = self.widget.insert_style_inner(property.into());
this.widget.styles_changed = true; self.widget.styles_changed = true;
this.ctx.request_layout(); self.ctx.request_layout();
old old
} }
@ -229,11 +229,11 @@ impl Label {
/// In most cases, these are the defaults for this widget. /// In most cases, these are the defaults for this widget.
/// ///
/// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize). /// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize).
pub fn retain_styles(this: &mut WidgetMut<'_, Self>, f: impl FnMut(&StyleProperty) -> bool) { pub fn retain_styles(self: &mut WidgetMut<'_, Self>, f: impl FnMut(&StyleProperty) -> bool) {
this.widget.styles.retain(f); self.widget.styles.retain(f);
this.widget.styles_changed = true; self.widget.styles_changed = true;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Remove the style with the discriminant `property`. /// Remove the style with the discriminant `property`.
@ -247,65 +247,65 @@ impl Label {
/// ///
/// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize). /// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize).
pub fn remove_style( pub fn remove_style(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
property: Discriminant<StyleProperty>, property: Discriminant<StyleProperty>,
) -> Option<StyleProperty> { ) -> Option<StyleProperty> {
let old = this.widget.styles.remove(property); let old = self.widget.styles.remove(property);
this.widget.styles_changed = true; self.widget.styles_changed = true;
this.ctx.request_layout(); self.ctx.request_layout();
old old
} }
/// Replace the text of this widget. /// Replace the text of this widget.
pub fn set_text(this: &mut WidgetMut<'_, Self>, new_text: impl Into<ArcStr>) { pub fn set_text(self: &mut WidgetMut<'_, Self>, new_text: impl Into<ArcStr>) {
this.widget.text = new_text.into(); self.widget.text = new_text.into();
this.widget.styles_changed = true; self.widget.styles_changed = true;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// The runtime requivalent of [`with_line_break_mode`](Self::with_line_break_mode). /// The runtime requivalent of [`with_line_break_mode`](Self::with_line_break_mode).
pub fn set_line_break_mode(this: &mut WidgetMut<'_, Self>, line_break_mode: LineBreaking) { pub fn set_line_break_mode(self: &mut WidgetMut<'_, Self>, line_break_mode: LineBreaking) {
this.widget.line_break_mode = line_break_mode; self.widget.line_break_mode = line_break_mode;
// We don't need to set an internal invalidation, as `max_advance` is always recalculated // We don't need to set an internal invalidation, as `max_advance` is always recalculated
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// The runtime requivalent of [`with_alignment`](Self::with_alignment). /// The runtime requivalent of [`with_alignment`](Self::with_alignment).
pub fn set_alignment(this: &mut WidgetMut<'_, Self>, alignment: Alignment) { pub fn set_alignment(self: &mut WidgetMut<'_, Self>, alignment: Alignment) {
this.widget.alignment = alignment; self.widget.alignment = alignment;
this.widget.alignment_changed = true; self.widget.alignment_changed = true;
this.ctx.request_layout(); self.ctx.request_layout();
} }
#[doc(alias = "set_color")] #[doc(alias = "set_color")]
/// The runtime requivalent of [`with_brush`](Self::with_brush). /// The runtime requivalent of [`with_brush`](Self::with_brush).
pub fn set_brush(this: &mut WidgetMut<'_, Self>, brush: impl Into<Brush>) { pub fn set_brush(self: &mut WidgetMut<'_, Self>, brush: impl Into<Brush>) {
let brush = brush.into(); let brush = brush.into();
this.widget.brush = brush; self.widget.brush = brush;
// We need to repaint unless the disabled brush is currently being used. // We need to repaint unless the disabled brush is currently being used.
if this.widget.disabled_brush.is_none() || this.ctx.is_disabled() { if self.widget.disabled_brush.is_none() || self.ctx.is_disabled() {
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
} }
/// The runtime requivalent of [`with_disabled_brush`](Self::with_disabled_brush). /// The runtime requivalent of [`with_disabled_brush`](Self::with_disabled_brush).
pub fn set_disabled_brush(this: &mut WidgetMut<'_, Self>, brush: impl Into<Option<Brush>>) { pub fn set_disabled_brush(self: &mut WidgetMut<'_, Self>, brush: impl Into<Option<Brush>>) {
let brush = brush.into(); let brush = brush.into();
this.widget.disabled_brush = brush; self.widget.disabled_brush = brush;
if this.ctx.is_disabled() { if self.ctx.is_disabled() {
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
} }
/// The runtime requivalent of [`with_hint`](Self::with_hint). /// The runtime requivalent of [`with_hint`](Self::with_hint).
pub fn set_hint(this: &mut WidgetMut<'_, Self>, hint: bool) { pub fn set_hint(self: &mut WidgetMut<'_, Self>, hint: bool) {
this.widget.hint = hint; self.widget.hint = hint;
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
} }

View File

@ -171,33 +171,33 @@ impl<W: Widget + ?Sized> Portal<W> {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl<W: Widget + FromDynWidget + ?Sized> Portal<W> { impl<W: Widget + FromDynWidget + ?Sized> Portal<W> {
pub fn child_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, W> { pub fn child_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, W> {
this.ctx.get_mut(&mut this.widget.child) self.ctx.get_mut(&mut self.widget.child)
} }
pub fn horizontal_scrollbar_mut<'t>( pub fn horizontal_scrollbar_mut<'t>(
this: &'t mut WidgetMut<'_, Self>, self: &'t mut WidgetMut<'_, Self>,
) -> WidgetMut<'t, ScrollBar> { ) -> WidgetMut<'t, ScrollBar> {
this.ctx.get_mut(&mut this.widget.scrollbar_horizontal) self.ctx.get_mut(&mut self.widget.scrollbar_horizontal)
} }
pub fn vertical_scrollbar_mut<'t>( pub fn vertical_scrollbar_mut<'t>(
this: &'t mut WidgetMut<'_, Self>, self: &'t mut WidgetMut<'_, Self>,
) -> WidgetMut<'t, ScrollBar> { ) -> WidgetMut<'t, ScrollBar> {
this.ctx.get_mut(&mut this.widget.scrollbar_vertical) self.ctx.get_mut(&mut self.widget.scrollbar_vertical)
} }
// TODO - rewrite doc // TODO - rewrite doc
/// Set whether to constrain the child horizontally. /// Set whether to constrain the child horizontally.
pub fn set_constrain_horizontal(this: &mut WidgetMut<'_, Self>, constrain: bool) { pub fn set_constrain_horizontal(self: &mut WidgetMut<'_, Self>, constrain: bool) {
this.widget.constrain_horizontal = constrain; self.widget.constrain_horizontal = constrain;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set whether to constrain the child vertically. /// Set whether to constrain the child vertically.
pub fn set_constrain_vertical(this: &mut WidgetMut<'_, Self>, constrain: bool) { pub fn set_constrain_vertical(self: &mut WidgetMut<'_, Self>, constrain: bool) {
this.widget.constrain_vertical = constrain; self.widget.constrain_vertical = constrain;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set whether the child's size must be greater than or equal the size of /// Set whether the child's size must be greater than or equal the size of
@ -206,42 +206,42 @@ impl<W: Widget + FromDynWidget + ?Sized> Portal<W> {
/// See [`content_must_fill`] for more details. /// See [`content_must_fill`] for more details.
/// ///
/// [`content_must_fill`]: Portal::content_must_fill /// [`content_must_fill`]: Portal::content_must_fill
pub fn set_content_must_fill(this: &mut WidgetMut<'_, Self>, must_fill: bool) { pub fn set_content_must_fill(self: &mut WidgetMut<'_, Self>, must_fill: bool) {
this.widget.must_fill = must_fill; self.widget.must_fill = must_fill;
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn set_viewport_pos(this: &mut WidgetMut<'_, Self>, position: Point) -> bool { pub fn set_viewport_pos(self: &mut WidgetMut<'_, Self>, position: Point) -> bool {
let portal_size = this.ctx.layout_rect().size(); let portal_size = self.ctx.layout_rect().size();
let content_size = this let content_size = self
.ctx .ctx
.get_mut(&mut this.widget.child) .get_mut(&mut self.widget.child)
.ctx .ctx
.layout_rect() .layout_rect()
.size(); .size();
let pos_changed = this let pos_changed = self
.widget .widget
.set_viewport_pos_raw(portal_size, content_size, position); .set_viewport_pos_raw(portal_size, content_size, position);
if pos_changed { if pos_changed {
let progress_x = this.widget.viewport_pos.x / (content_size - portal_size).width; let progress_x = self.widget.viewport_pos.x / (content_size - portal_size).width;
Self::horizontal_scrollbar_mut(this).widget.cursor_progress = progress_x; self.horizontal_scrollbar_mut().widget.cursor_progress = progress_x;
Self::horizontal_scrollbar_mut(this).ctx.request_render(); self.horizontal_scrollbar_mut().ctx.request_render();
let progress_y = this.widget.viewport_pos.y / (content_size - portal_size).height; let progress_y = self.widget.viewport_pos.y / (content_size - portal_size).height;
Self::vertical_scrollbar_mut(this).widget.cursor_progress = progress_y; self.vertical_scrollbar_mut().widget.cursor_progress = progress_y;
Self::vertical_scrollbar_mut(this).ctx.request_render(); self.vertical_scrollbar_mut().ctx.request_render();
this.ctx.request_layout(); self.ctx.request_layout();
} }
pos_changed pos_changed
} }
pub fn pan_viewport_by(this: &mut WidgetMut<'_, Self>, translation: Vec2) -> bool { pub fn pan_viewport_by(self: &mut WidgetMut<'_, Self>, translation: Vec2) -> bool {
Self::set_viewport_pos(this, this.widget.viewport_pos + translation) self.set_viewport_pos(self.widget.viewport_pos + translation)
} }
// Note - Rect is in child coordinates // Note - Rect is in child coordinates
pub fn pan_viewport_to(this: &mut WidgetMut<'_, Self>, target: Rect) -> bool { pub fn pan_viewport_to(self: &mut WidgetMut<'_, Self>, target: Rect) -> bool {
let viewport = Rect::from_origin_size(this.widget.viewport_pos, this.ctx.widget_state.size); let viewport = Rect::from_origin_size(self.widget.viewport_pos, self.ctx.widget_state.size);
let new_pos_x = compute_pan_range( let new_pos_x = compute_pan_range(
viewport.min_x()..viewport.max_x(), viewport.min_x()..viewport.max_x(),
@ -254,7 +254,7 @@ impl<W: Widget + FromDynWidget + ?Sized> Portal<W> {
) )
.start; .start;
Self::set_viewport_pos(this, Point::new(new_pos_x, new_pos_y)) self.set_viewport_pos(Point::new(new_pos_x, new_pos_y))
} }
} }

View File

@ -62,16 +62,16 @@ impl ProgressBar {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl ProgressBar { impl ProgressBar {
pub fn set_progress(this: &mut WidgetMut<'_, Self>, mut progress: Option<f64>) { pub fn set_progress(self: &mut WidgetMut<'_, Self>, mut progress: Option<f64>) {
clamp_progress(&mut progress); clamp_progress(&mut progress);
let progress_changed = this.widget.progress != progress; let progress_changed = self.widget.progress != progress;
if progress_changed { if progress_changed {
this.widget.progress = progress; self.widget.progress = progress;
let mut label = this.ctx.get_mut(&mut this.widget.label); let mut label = self.ctx.get_mut(&mut self.widget.label);
Label::set_text(&mut label, Self::value(progress)); Label::set_text(&mut label, Self::value(progress));
} }
this.ctx.request_layout(); self.ctx.request_layout();
this.ctx.request_render(); self.ctx.request_render();
} }
} }

View File

@ -93,8 +93,8 @@ impl Prose {
/// Edit the underlying text area. /// Edit the underlying text area.
/// ///
/// Used to modify most properties of the text. /// Used to modify most properties of the text.
pub fn text_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, TextArea<false>> { pub fn text_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, TextArea<false>> {
this.ctx.get_mut(&mut this.widget.text) self.ctx.get_mut(&mut self.widget.text)
} }
/// Whether to clip the text to the available space. /// Whether to clip the text to the available space.
@ -103,9 +103,9 @@ impl Prose {
/// wraps a text area with [word wrapping](TextArea::set_word_wrap) enabled. /// wraps a text area with [word wrapping](TextArea::set_word_wrap) enabled.
/// ///
/// The runtime requivalent of [`with_clip`](Self::with_clip). /// The runtime requivalent of [`with_clip`](Self::with_clip).
pub fn set_clip(this: &mut WidgetMut<'_, Self>, clip: bool) { pub fn set_clip(self: &mut WidgetMut<'_, Self>, clip: bool) {
this.widget.clip = clip; self.widget.clip = clip;
this.ctx.request_layout(); self.ctx.request_layout();
} }
} }

View File

@ -34,8 +34,8 @@ impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> {
} }
impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> { impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> {
pub fn child_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, W> { pub fn child_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, W> {
this.ctx.get_mut(&mut this.widget.pod) self.ctx.get_mut(&mut self.widget.pod)
} }
} }

View File

@ -105,17 +105,17 @@ impl ScrollBar {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl ScrollBar { impl ScrollBar {
// TODO - Remove? // TODO - Remove?
pub fn set_sizes(this: &mut WidgetMut<'_, Self>, portal_size: f64, content_size: f64) { pub fn set_sizes(self: &mut WidgetMut<'_, Self>, portal_size: f64, content_size: f64) {
this.widget.portal_size = portal_size; self.widget.portal_size = portal_size;
this.widget.content_size = content_size; self.widget.content_size = content_size;
this.ctx.request_render(); self.ctx.request_render();
} }
// TODO - Remove? // TODO - Remove?
pub fn set_content_size(this: &mut WidgetMut<'_, Self>, content_size: f64) { pub fn set_content_size(self: &mut WidgetMut<'_, Self>, content_size: f64) {
// TODO - cursor_progress // TODO - cursor_progress
this.widget.content_size = content_size; self.widget.content_size = content_size;
this.ctx.request_render(); self.ctx.request_render();
} }
} }

View File

@ -331,43 +331,43 @@ impl SizedBox {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl SizedBox { impl SizedBox {
pub fn set_child(this: &mut WidgetMut<'_, Self>, child: impl Widget) { pub fn set_child(self: &mut WidgetMut<'_, Self>, child: impl Widget) {
if let Some(child) = this.widget.child.take() { if let Some(child) = self.widget.child.take() {
this.ctx.remove_child(child); self.ctx.remove_child(child);
} }
this.widget.child = Some(WidgetPod::new(child).erased()); self.widget.child = Some(WidgetPod::new(child).erased());
this.ctx.children_changed(); self.ctx.children_changed();
this.ctx.request_layout(); self.ctx.request_layout();
} }
pub fn remove_child(this: &mut WidgetMut<'_, Self>) { pub fn remove_child(self: &mut WidgetMut<'_, Self>) {
if let Some(child) = this.widget.child.take() { if let Some(child) = self.widget.child.take() {
this.ctx.remove_child(child); self.ctx.remove_child(child);
} }
} }
/// Set container's width. /// Set container's width.
pub fn set_width(this: &mut WidgetMut<'_, Self>, width: f64) { pub fn set_width(self: &mut WidgetMut<'_, Self>, width: f64) {
this.widget.width = Some(width); self.widget.width = Some(width);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set container's height. /// Set container's height.
pub fn set_height(this: &mut WidgetMut<'_, Self>, height: f64) { pub fn set_height(self: &mut WidgetMut<'_, Self>, height: f64) {
this.widget.height = Some(height); self.widget.height = Some(height);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set container's width. /// Set container's width.
pub fn unset_width(this: &mut WidgetMut<'_, Self>) { pub fn unset_width(self: &mut WidgetMut<'_, Self>) {
this.widget.width = None; self.widget.width = None;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set container's height. /// Set container's height.
pub fn unset_height(this: &mut WidgetMut<'_, Self>) { pub fn unset_height(self: &mut WidgetMut<'_, Self>) {
this.widget.height = None; self.widget.height = None;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the background for this widget. /// Set the background for this widget.
@ -377,57 +377,57 @@ impl SizedBox {
/// ///
/// [`Image`]: vello::peniko::Image /// [`Image`]: vello::peniko::Image
/// [`Color`]: crate::peniko::Color /// [`Color`]: crate::peniko::Color
pub fn set_background(this: &mut WidgetMut<'_, Self>, brush: impl Into<Brush>) { pub fn set_background(self: &mut WidgetMut<'_, Self>, brush: impl Into<Brush>) {
this.widget.background = Some(brush.into()); self.widget.background = Some(brush.into());
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
/// Clears background. /// Clears background.
pub fn clear_background(this: &mut WidgetMut<'_, Self>) { pub fn clear_background(self: &mut WidgetMut<'_, Self>) {
this.widget.background = None; self.widget.background = None;
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
/// Paint a border around the widget with a brush and width. /// Paint a border around the widget with a brush and width.
pub fn set_border( pub fn set_border(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
brush: impl Into<Brush>, brush: impl Into<Brush>,
width: impl Into<f64>, width: impl Into<f64>,
) { ) {
this.widget.border = Some(BorderStyle { self.widget.border = Some(BorderStyle {
brush: brush.into(), brush: brush.into(),
width: width.into(), width: width.into(),
}); });
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Clears border. /// Clears border.
pub fn clear_border(this: &mut WidgetMut<'_, Self>) { pub fn clear_border(self: &mut WidgetMut<'_, Self>) {
this.widget.border = None; self.widget.border = None;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Round off corners of this container by setting a corner radius /// Round off corners of this container by setting a corner radius
pub fn set_rounded(this: &mut WidgetMut<'_, Self>, radius: impl Into<RoundedRectRadii>) { pub fn set_rounded(self: &mut WidgetMut<'_, Self>, radius: impl Into<RoundedRectRadii>) {
this.widget.corner_radius = radius.into(); self.widget.corner_radius = radius.into();
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
/// Clears padding. /// Clears padding.
pub fn clear_padding(this: &mut WidgetMut<'_, Self>) { pub fn clear_padding(self: &mut WidgetMut<'_, Self>) {
Self::set_padding(this, Padding::ZERO); self.set_padding(Padding::ZERO);
} }
/// Set the padding around this widget. /// Set the padding around this widget.
pub fn set_padding(this: &mut WidgetMut<'_, Self>, padding: impl Into<Padding>) { pub fn set_padding(self: &mut WidgetMut<'_, Self>, padding: impl Into<Padding>) {
this.widget.padding = padding.into(); self.widget.padding = padding.into();
this.ctx.request_layout(); self.ctx.request_layout();
} }
// TODO - Doc // TODO - Doc
pub fn child_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> Option<WidgetMut<'t, dyn Widget>> { pub fn child_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> Option<WidgetMut<'t, dyn Widget>> {
let child = this.widget.child.as_mut()?; let child = self.widget.child.as_mut()?;
Some(this.ctx.get_mut(child)) Some(self.ctx.get_mut(child))
} }
} }

View File

@ -60,14 +60,14 @@ impl Default for Spinner {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl Spinner { impl Spinner {
/// Set the spinner's color. /// Set the spinner's color.
pub fn set_color(this: &mut WidgetMut<'_, Self>, color: impl Into<Color>) { pub fn set_color(self: &mut WidgetMut<'_, Self>, color: impl Into<Color>) {
this.widget.color = color.into(); self.widget.color = color.into();
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
/// Reset the spinner's color to its default value. /// Reset the spinner's color to its default value.
pub fn reset_color(this: &mut WidgetMut<'_, Self>) { pub fn reset_color(self: &mut WidgetMut<'_, Self>) {
Self::set_color(this, DEFAULT_SPINNER_COLOR); self.set_color(DEFAULT_SPINNER_COLOR);
} }
} }

View File

@ -298,24 +298,24 @@ impl Split {
/// ///
/// The value must be between `0.0` and `1.0`, inclusive. /// The value must be between `0.0` and `1.0`, inclusive.
/// The default split point is `0.5`. /// The default split point is `0.5`.
pub fn set_split_point(this: &mut WidgetMut<'_, Self>, split_point: f64) { pub fn set_split_point(self: &mut WidgetMut<'_, Self>, split_point: f64) {
assert!( assert!(
(0.0..=1.0).contains(&split_point), (0.0..=1.0).contains(&split_point),
"split_point must be in the range [0.0-1.0]!" "split_point must be in the range [0.0-1.0]!"
); );
this.widget.split_point_chosen = split_point; self.widget.split_point_chosen = split_point;
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the minimum size for both sides of the split axis. /// Set the minimum size for both sides of the split axis.
/// ///
/// The value must be greater than or equal to `0.0`. /// The value must be greater than or equal to `0.0`.
/// The value will be rounded up to the nearest integer. /// The value will be rounded up to the nearest integer.
pub fn set_min_size(this: &mut WidgetMut<'_, Self>, first: f64, second: f64) { pub fn set_min_size(self: &mut WidgetMut<'_, Self>, first: f64, second: f64) {
assert!(first >= 0.0); assert!(first >= 0.0);
assert!(second >= 0.0); assert!(second >= 0.0);
this.widget.min_size = (first.ceil(), second.ceil()); self.widget.min_size = (first.ceil(), second.ceil());
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the size of the splitter bar. /// Set the size of the splitter bar.
@ -323,10 +323,10 @@ impl Split {
/// The value must be positive or zero. /// The value must be positive or zero.
/// The value will be rounded up to the nearest integer. /// The value will be rounded up to the nearest integer.
/// The default splitter bar size is `6.0`. /// The default splitter bar size is `6.0`.
pub fn set_bar_size(this: &mut WidgetMut<'_, Self>, bar_size: f64) { pub fn set_bar_size(self: &mut WidgetMut<'_, Self>, bar_size: f64) {
assert!(bar_size >= 0.0, "bar_size must be 0.0 or greater!"); assert!(bar_size >= 0.0, "bar_size must be 0.0 or greater!");
this.widget.bar_size = bar_size.ceil(); self.widget.bar_size = bar_size.ceil();
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the minimum size of the splitter bar area. /// Set the minimum size of the splitter bar area.
@ -341,27 +341,27 @@ impl Split {
/// The value must be positive or zero. /// The value must be positive or zero.
/// The value will be rounded up to the nearest integer. /// The value will be rounded up to the nearest integer.
/// The default minimum splitter bar area is `6.0`. /// The default minimum splitter bar area is `6.0`.
pub fn set_min_bar_area(this: &mut WidgetMut<'_, Self>, min_bar_area: f64) { pub fn set_min_bar_area(self: &mut WidgetMut<'_, Self>, min_bar_area: f64) {
assert!(min_bar_area >= 0.0, "min_bar_area must be 0.0 or greater!"); assert!(min_bar_area >= 0.0, "min_bar_area must be 0.0 or greater!");
this.widget.min_bar_area = min_bar_area.ceil(); self.widget.min_bar_area = min_bar_area.ceil();
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set whether the split point can be changed by dragging. /// Set whether the split point can be changed by dragging.
pub fn set_draggable(this: &mut WidgetMut<'_, Self>, draggable: bool) { pub fn set_draggable(self: &mut WidgetMut<'_, Self>, draggable: bool) {
this.widget.draggable = draggable; self.widget.draggable = draggable;
// Bar mutability impacts appearance, but not accessibility node // Bar mutability impacts appearance, but not accessibility node
// TODO - This might change in a future implementation // TODO - This might change in a future implementation
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
/// Set whether the splitter bar is drawn as a solid rectangle. /// Set whether the splitter bar is drawn as a solid rectangle.
/// ///
/// If this is `false` (the default), the bar will be drawn as two parallel lines. /// If this is `false` (the default), the bar will be drawn as two parallel lines.
pub fn set_bar_solid(this: &mut WidgetMut<'_, Self>, solid: bool) { pub fn set_bar_solid(self: &mut WidgetMut<'_, Self>, solid: bool) {
this.widget.solid = solid; self.widget.solid = solid;
// Bar solidity impacts appearance, but not accessibility node // Bar solidity impacts appearance, but not accessibility node
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
} }

View File

@ -335,12 +335,12 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// This is the runtime equivalent of [`with_style`](Self::with_style). /// This is the runtime equivalent of [`with_style`](Self::with_style).
#[track_caller] #[track_caller]
pub fn insert_style( pub fn insert_style(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
property: impl Into<StyleProperty>, property: impl Into<StyleProperty>,
) -> Option<StyleProperty> { ) -> Option<StyleProperty> {
let old = this.widget.insert_style_inner(property.into()); let old = self.widget.insert_style_inner(property.into());
this.ctx.request_layout(); self.ctx.request_layout();
old old
} }
@ -350,10 +350,10 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// In most cases, these are the defaults for this widget. /// In most cases, these are the defaults for this widget.
/// ///
/// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize). /// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize).
pub fn retain_styles(this: &mut WidgetMut<'_, Self>, f: impl FnMut(&StyleProperty) -> bool) { pub fn retain_styles(self: &mut WidgetMut<'_, Self>, f: impl FnMut(&StyleProperty) -> bool) {
this.widget.editor.edit_styles().retain(f); self.widget.editor.edit_styles().retain(f);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Remove the style with the discriminant `property`. /// Remove the style with the discriminant `property`.
@ -367,12 +367,12 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// ///
/// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize). /// Of note, behaviour is unspecified for unsetting the [`FontSize`](parley::StyleProperty::FontSize).
pub fn remove_style( pub fn remove_style(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
property: Discriminant<StyleProperty>, property: Discriminant<StyleProperty>,
) -> Option<StyleProperty> { ) -> Option<StyleProperty> {
let old = this.widget.editor.edit_styles().remove(property); let old = self.widget.editor.edit_styles().remove(property);
this.ctx.request_layout(); self.ctx.request_layout();
old old
} }
@ -380,20 +380,20 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// ///
/// This is likely to be disruptive if the user is focused on this widget, /// This is likely to be disruptive if the user is focused on this widget,
/// as it does not retain selections, and may cause undesirable interactions with IME. /// as it does not retain selections, and may cause undesirable interactions with IME.
pub fn reset_text(this: &mut WidgetMut<'_, Self>, new_text: &str) { pub fn reset_text(self: &mut WidgetMut<'_, Self>, new_text: &str) {
// If the IME is currently composing, we need to clear the compose first. This is quite // If the IME is currently composing, we need to clear the compose first. This is quite
// disruptive, but we've warned about that. The platform's state is not reset, and the // disruptive, but we've warned about that. The platform's state is not reset, and the
// preedit will show up again when the platform updates it. // preedit will show up again when the platform updates it.
if this.widget.editor.is_composing() { if self.widget.editor.is_composing() {
let (fctx, lctx) = this.ctx.text_contexts(); let (fctx, lctx) = self.ctx.text_contexts();
this.widget.editor.driver(fctx, lctx).clear_compose(); self.widget.editor.driver(fctx, lctx).clear_compose();
} }
this.widget.editor.set_text(new_text); self.widget.editor.set_text(new_text);
let (fctx, lctx) = this.ctx.text_contexts(); let (fctx, lctx) = self.ctx.text_contexts();
this.widget.editor.driver(fctx, lctx).move_to_text_end(); self.widget.editor.driver(fctx, lctx).move_to_text_end();
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Control [word wrapping](https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap) for the text area. /// Control [word wrapping](https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap) for the text area.
@ -406,15 +406,15 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// so it is recommended to leave word wrapping enabled. /// so it is recommended to leave word wrapping enabled.
/// ///
/// The runtime equivalent of [`with_word_wrap`](Self::with_word_wrap). /// The runtime equivalent of [`with_word_wrap`](Self::with_word_wrap).
pub fn set_word_wrap(this: &mut WidgetMut<'_, Self>, wrap_words: bool) { pub fn set_word_wrap(self: &mut WidgetMut<'_, Self>, wrap_words: bool) {
this.widget.word_wrap = wrap_words; self.widget.word_wrap = wrap_words;
let width = if wrap_words { let width = if wrap_words {
this.widget.last_available_width self.widget.last_available_width
} else { } else {
None None
}; };
this.widget.editor.set_width(width); self.widget.editor.set_width(width);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text. /// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text.
@ -422,10 +422,10 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// Text alignment might have unexpected results when the text area has no horizontal constraints. /// Text alignment might have unexpected results when the text area has no horizontal constraints.
/// ///
/// The runtime equivalent of [`with_alignment`](Self::with_alignment). /// The runtime equivalent of [`with_alignment`](Self::with_alignment).
pub fn set_alignment(this: &mut WidgetMut<'_, Self>, alignment: Alignment) { pub fn set_alignment(self: &mut WidgetMut<'_, Self>, alignment: Alignment) {
this.widget.editor.set_alignment(alignment); self.widget.editor.set_alignment(alignment);
this.ctx.request_layout(); self.ctx.request_layout();
} }
#[doc(alias = "set_color")] #[doc(alias = "set_color")]
@ -434,13 +434,13 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// In most cases, this will be the text's color, but gradients and images are also supported. /// In most cases, this will be the text's color, but gradients and images are also supported.
/// ///
/// The runtime equivalent of [`with_brush`](Self::with_brush). /// The runtime equivalent of [`with_brush`](Self::with_brush).
pub fn set_brush(this: &mut WidgetMut<'_, Self>, brush: impl Into<Brush>) { pub fn set_brush(self: &mut WidgetMut<'_, Self>, brush: impl Into<Brush>) {
let brush = brush.into(); let brush = brush.into();
this.widget.brush = brush; self.widget.brush = brush;
// We need to repaint unless the disabled brush is currently being used. // We need to repaint unless the disabled brush is currently being used.
if this.widget.disabled_brush.is_none() || !this.ctx.is_disabled() { if self.widget.disabled_brush.is_none() || !self.ctx.is_disabled() {
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
} }
@ -449,12 +449,12 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// If this is `None`, the [normal brush](Self::set_brush) will be used. /// If this is `None`, the [normal brush](Self::set_brush) will be used.
/// ///
/// The runtime equivalent of [`with_disabled_brush`](Self::with_disabled_brush). /// The runtime equivalent of [`with_disabled_brush`](Self::with_disabled_brush).
pub fn set_disabled_brush(this: &mut WidgetMut<'_, Self>, brush: impl Into<Option<Brush>>) { pub fn set_disabled_brush(self: &mut WidgetMut<'_, Self>, brush: impl Into<Option<Brush>>) {
let brush = brush.into(); let brush = brush.into();
this.widget.disabled_brush = brush; self.widget.disabled_brush = brush;
if this.ctx.is_disabled() { if self.ctx.is_disabled() {
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
} }
@ -462,9 +462,9 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// ///
/// The runtime equivalent of [`with_hint`](Self::with_hint). /// The runtime equivalent of [`with_hint`](Self::with_hint).
/// For full documentation, see that method. /// For full documentation, see that method.
pub fn set_hint(this: &mut WidgetMut<'_, Self>, hint: bool) { pub fn set_hint(self: &mut WidgetMut<'_, Self>, hint: bool) {
this.widget.hint = hint; self.widget.hint = hint;
this.ctx.request_paint_only(); self.ctx.request_paint_only();
} }
/// Set the padding around the text. /// Set the padding around the text.
@ -472,23 +472,23 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// This is the area outside the tight bound on the text where pointer events will be detected. /// This is the area outside the tight bound on the text where pointer events will be detected.
/// ///
/// The runtime equivalent of [`with_padding`](Self::with_padding). /// The runtime equivalent of [`with_padding`](Self::with_padding).
pub fn set_padding(this: &mut WidgetMut<'_, Self>, padding: impl Into<Padding>) { pub fn set_padding(self: &mut WidgetMut<'_, Self>, padding: impl Into<Padding>) {
this.widget.padding = padding.into(); self.widget.padding = padding.into();
// TODO: We could reset the width available to the editor here directly. // TODO: We could reset the width available to the editor here directly.
// Determine whether there's any advantage to that // Determine whether there's any advantage to that
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Set the selection to the given byte range. /// Set the selection to the given byte range.
/// ///
/// No-op if either index is not a char boundary. /// No-op if either index is not a char boundary.
pub fn select_byte_range(this: &mut WidgetMut<'_, Self>, start: usize, end: usize) { pub fn select_byte_range(self: &mut WidgetMut<'_, Self>, start: usize, end: usize) {
let (fctx, lctx) = this.ctx.text_contexts(); let (fctx, lctx) = self.ctx.text_contexts();
this.widget self.widget
.editor .editor
.driver(fctx, lctx) .driver(fctx, lctx)
.select_byte_range(start, end); .select_byte_range(start, end);
this.ctx.request_render(); self.ctx.request_render();
} }
/// Set the selection to the first instance of the given text. /// Set the selection to the first instance of the given text.
@ -496,12 +496,12 @@ impl<const EDITABLE: bool> TextArea<EDITABLE> {
/// This is mostly useful for testing. /// This is mostly useful for testing.
/// ///
/// No-op if the text isn't found. /// No-op if the text isn't found.
pub fn select_text(this: &mut WidgetMut<'_, Self>, text: &str) { pub fn select_text(self: &mut WidgetMut<'_, Self>, text: &str) {
let Some(start) = this.widget.text().to_string().find(text) else { let Some(start) = self.widget.text().to_string().find(text) else {
return; return;
}; };
let end = start + text.len(); let end = start + text.len();
Self::select_byte_range(this, start, end); self.select_byte_range(start, end);
} }
} }

View File

@ -92,8 +92,8 @@ impl Textbox {
/// Edit the underlying text area. /// Edit the underlying text area.
/// ///
/// Used to modify most properties of the text. /// Used to modify most properties of the text.
pub fn text_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, TextArea<true>> { pub fn text_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, TextArea<true>> {
this.ctx.get_mut(&mut this.widget.text) self.ctx.get_mut(&mut self.widget.text)
} }
/// Whether to clip the text to the drawn boundaries. /// Whether to clip the text to the drawn boundaries.
@ -102,9 +102,9 @@ impl Textbox {
/// wraps a text area with [word wrapping](TextArea::set_word_wrap) enabled. /// wraps a text area with [word wrapping](TextArea::set_word_wrap) enabled.
/// ///
/// The runtime requivalent of [`with_clip`](Self::with_clip). /// The runtime requivalent of [`with_clip`](Self::with_clip).
pub fn set_clip(this: &mut WidgetMut<'_, Self>, clip: bool) { pub fn set_clip(self: &mut WidgetMut<'_, Self>, clip: bool) {
this.widget.clip = clip; self.widget.clip = clip;
this.ctx.request_layout(); self.ctx.request_layout();
} }
} }

View File

@ -154,20 +154,20 @@ impl VariableLabel {
// --- MARK: WIDGETMUT --- // --- MARK: WIDGETMUT ---
impl VariableLabel { impl VariableLabel {
/// Get the underlying label for this widget. /// Get the underlying label for this widget.
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> { pub fn label_mut<'t>(self: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
this.ctx.get_mut(&mut this.widget.label) self.ctx.get_mut(&mut self.widget.label)
} }
/// Set the text of this label. /// Set the text of this label.
pub fn set_text(this: &mut WidgetMut<'_, Self>, new_text: impl Into<ArcStr>) { pub fn set_text(self: &mut WidgetMut<'_, Self>, new_text: impl Into<ArcStr>) {
Label::set_text(&mut Self::label_mut(this), new_text); Label::set_text(&mut self.label_mut(), new_text);
} }
/// Set the weight which this font will target. /// Set the weight which this font will target.
pub fn set_target_weight(this: &mut WidgetMut<'_, Self>, target: f32, over_millis: f32) { pub fn set_target_weight(self: &mut WidgetMut<'_, Self>, target: f32, over_millis: f32) {
this.widget.weight.move_to(target, over_millis); self.widget.weight.move_to(target, over_millis);
this.ctx.request_layout(); self.ctx.request_layout();
this.ctx.request_anim_frame(); self.ctx.request_anim_frame();
} }
} }

View File

@ -227,72 +227,72 @@ impl ZStack {
/// ///
/// See also [`with_child`][Self::with_child]. /// See also [`with_child`][Self::with_child].
pub fn add_child( pub fn add_child(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
child: impl Widget, child: impl Widget,
alignment: impl Into<ChildAlignment>, alignment: impl Into<ChildAlignment>,
) { ) {
let child_pod: WidgetPod<dyn Widget> = WidgetPod::new(child).erased(); let child_pod: WidgetPod<dyn Widget> = WidgetPod::new(child).erased();
Self::insert_child_pod(this, child_pod, alignment); self.insert_child_pod(child_pod, alignment);
} }
/// Add a child widget with a given `id` to the `ZStack`. /// Add a child widget with a given `id` to the `ZStack`.
/// ///
/// See [`Self::add_child`] for more details. /// See [`Self::add_child`] for more details.
pub fn add_child_id( pub fn add_child_id(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
child: impl Widget, child: impl Widget,
id: WidgetId, id: WidgetId,
alignment: impl Into<ChildAlignment>, alignment: impl Into<ChildAlignment>,
) { ) {
let child_pod: WidgetPod<dyn Widget> = WidgetPod::new_with_id(child, id).erased(); let child_pod: WidgetPod<dyn Widget> = WidgetPod::new_with_id(child, id).erased();
Self::insert_child_pod(this, child_pod, alignment); self.insert_child_pod(child_pod, alignment);
} }
/// Add a child widget to the `ZStack`. /// Add a child widget to the `ZStack`.
pub fn insert_child_pod( pub fn insert_child_pod(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
widget: WidgetPod<dyn Widget>, widget: WidgetPod<dyn Widget>,
alignment: impl Into<ChildAlignment>, alignment: impl Into<ChildAlignment>,
) { ) {
let child = Child::new(widget, alignment.into()); let child = Child::new(widget, alignment.into());
this.widget.children.push(child); self.widget.children.push(child);
this.ctx.children_changed(); self.ctx.children_changed();
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Remove a child from the `ZStack`. /// Remove a child from the `ZStack`.
pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) { pub fn remove_child(self: &mut WidgetMut<'_, Self>, idx: usize) {
let child = this.widget.children.remove(idx); let child = self.widget.children.remove(idx);
this.ctx.remove_child(child.widget); self.ctx.remove_child(child.widget);
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Get a mutable reference to a child of the `ZStack`. /// Get a mutable reference to a child of the `ZStack`.
pub fn child_mut<'t>( pub fn child_mut<'t>(
this: &'t mut WidgetMut<'_, Self>, self: &'t mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
) -> Option<WidgetMut<'t, dyn Widget>> { ) -> Option<WidgetMut<'t, dyn Widget>> {
let child = &mut this.widget.children[idx].widget; let child = &mut self.widget.children[idx].widget;
Some(this.ctx.get_mut(child)) Some(self.ctx.get_mut(child))
} }
/// Change the alignment of the `ZStack`. /// Change the alignment of the `ZStack`.
/// ///
/// See also [`with_alignment`][Self::with_alignment]. /// See also [`with_alignment`][Self::with_alignment].
pub fn set_alignment(this: &mut WidgetMut<'_, Self>, alignment: impl Into<Alignment>) { pub fn set_alignment(self: &mut WidgetMut<'_, Self>, alignment: impl Into<Alignment>) {
this.widget.alignment = alignment.into(); self.widget.alignment = alignment.into();
this.ctx.request_layout(); self.ctx.request_layout();
} }
/// Change the alignment of a child of the `ZStack`. /// Change the alignment of a child of the `ZStack`.
pub fn update_child_alignment( pub fn update_child_alignment(
this: &mut WidgetMut<'_, Self>, self: &mut WidgetMut<'_, Self>,
idx: usize, idx: usize,
alignment: impl Into<ChildAlignment>, alignment: impl Into<ChildAlignment>,
) { ) {
let child = &mut this.widget.children[idx]; let child = &mut self.widget.children[idx];
child.update_alignment(alignment.into()); child.update_alignment(alignment.into());
this.ctx.request_layout(); self.ctx.request_layout();
} }
} }