mirror of https://github.com/linebender/xilem
Document more items (#899)
Make missing_docs annotations more granular.
This commit is contained in:
parent
ab341367b0
commit
125dab7949
|
@ -1,8 +1,7 @@
|
||||||
// Copyright 2024 the Xilem Authors
|
// Copyright 2024 the Xilem Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// We use allow because expect(missing_docs) is noisy with rust-analyzer.
|
#![expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
#![allow(missing_docs, reason = "We have many as-yet undocumented items")]
|
|
||||||
|
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -10,12 +10,9 @@ mod event;
|
||||||
mod object_fit;
|
mod object_fit;
|
||||||
mod properties;
|
mod properties;
|
||||||
mod text;
|
mod text;
|
||||||
#[allow(missing_docs, reason = "TODO")]
|
|
||||||
mod widget;
|
mod widget;
|
||||||
mod widget_arena;
|
mod widget_arena;
|
||||||
#[allow(missing_docs, reason = "TODO")]
|
|
||||||
mod widget_mut;
|
mod widget_mut;
|
||||||
#[allow(missing_docs, reason = "TODO")]
|
|
||||||
mod widget_pod;
|
mod widget_pod;
|
||||||
mod widget_ref;
|
mod widget_ref;
|
||||||
mod widget_state;
|
mod widget_state;
|
||||||
|
|
|
@ -45,6 +45,7 @@ use crate::kurbo::{Point, Size};
|
||||||
pub struct WidgetId(pub(crate) NonZeroU64);
|
pub struct WidgetId(pub(crate) NonZeroU64);
|
||||||
|
|
||||||
impl WidgetId {
|
impl WidgetId {
|
||||||
|
/// A serialized representation of the `WidgetId` for debugging purposes.
|
||||||
pub fn trace(self) -> DisplayValue<Self> {
|
pub fn trace(self) -> DisplayValue<Self> {
|
||||||
tracing::field::display(self)
|
tracing::field::display(self)
|
||||||
}
|
}
|
||||||
|
@ -242,6 +243,7 @@ pub trait Widget: AsAny + AsDynWidget {
|
||||||
bc: &BoxConstraints,
|
bc: &BoxConstraints,
|
||||||
) -> Size;
|
) -> Size;
|
||||||
|
|
||||||
|
/// Runs after the widget's final transform has been computed.
|
||||||
fn compose(&mut self, ctx: &mut ComposeCtx) {}
|
fn compose(&mut self, ctx: &mut ComposeCtx) {}
|
||||||
|
|
||||||
/// Paint the widget appearance.
|
/// Paint the widget appearance.
|
||||||
|
@ -495,6 +497,7 @@ impl WidgetId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the integer value of the `WidgetId`.
|
||||||
pub fn to_raw(self) -> u64 {
|
pub fn to_raw(self) -> u64 {
|
||||||
self.0.into()
|
self.0.into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ use anymap3::Entry;
|
||||||
use crate::core::{FromDynWidget, MutateCtx, Widget};
|
use crate::core::{FromDynWidget, MutateCtx, Widget};
|
||||||
use crate::kurbo::Affine;
|
use crate::kurbo::Affine;
|
||||||
|
|
||||||
// TODO - Document extension trait workaround.
|
|
||||||
// See https://xi.zulipchat.com/#narrow/stream/317477-masonry/topic/Thoughts.20on.20simplifying.20WidgetMut/near/436478885
|
|
||||||
/// A rich mutable reference to a [`Widget`].
|
/// A rich mutable reference to a [`Widget`].
|
||||||
///
|
///
|
||||||
/// In Masonry, widgets can't be mutated directly. All mutations go through a `WidgetMut`
|
/// In Masonry, widgets can't be mutated directly. All mutations go through a `WidgetMut`
|
||||||
|
@ -29,8 +27,10 @@ use crate::kurbo::Affine;
|
||||||
/// widgets in downstream crates can use `WidgetMut` as the receiver for inherent methods.
|
/// widgets in downstream crates can use `WidgetMut` as the receiver for inherent methods.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct WidgetMut<'a, W: Widget + ?Sized> {
|
pub struct WidgetMut<'a, W: Widget + ?Sized> {
|
||||||
pub ctx: MutateCtx<'a>,
|
/// The widget we're mutating.
|
||||||
pub widget: &'a mut W,
|
pub widget: &'a mut W,
|
||||||
|
/// A context handle that points to the widget state and other relevant data.
|
||||||
|
pub ctx: MutateCtx<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget + ?Sized> Drop for WidgetMut<'_, W> {
|
impl<W: Widget + ?Sized> Drop for WidgetMut<'_, W> {
|
||||||
|
@ -48,8 +48,8 @@ impl<W: Widget + ?Sized> WidgetMut<'_, W> {
|
||||||
pub fn reborrow_mut(&mut self) -> WidgetMut<'_, W> {
|
pub fn reborrow_mut(&mut self) -> WidgetMut<'_, W> {
|
||||||
let widget = &mut self.widget;
|
let widget = &mut self.widget;
|
||||||
WidgetMut {
|
WidgetMut {
|
||||||
ctx: self.ctx.reborrow_mut(),
|
|
||||||
widget,
|
widget,
|
||||||
|
ctx: self.ctx.reborrow_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,8 +118,8 @@ impl<W: Widget + ?Sized> WidgetMut<'_, W> {
|
||||||
let w1_name = self.widget.type_name();
|
let w1_name = self.widget.type_name();
|
||||||
match W2::from_dyn_mut(self.widget.as_mut_dyn()) {
|
match W2::from_dyn_mut(self.widget.as_mut_dyn()) {
|
||||||
Some(widget) => WidgetMut {
|
Some(widget) => WidgetMut {
|
||||||
ctx: self.ctx.reborrow_mut(),
|
|
||||||
widget,
|
widget,
|
||||||
|
ctx: self.ctx.reborrow_mut(),
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
|
@ -55,6 +55,7 @@ impl<W: Widget + ?Sized> WidgetPod<W> {
|
||||||
Self::new_with_id_and_transform(inner, WidgetId::next(), transform)
|
Self::new_with_id_and_transform(inner, WidgetId::next(), transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new widget pod with a custom transform and a pre-set [`WidgetId`].
|
||||||
pub fn new_with_id_and_transform(inner: Box<W>, id: WidgetId, transform: Affine) -> Self {
|
pub fn new_with_id_and_transform(inner: Box<W>, id: WidgetId, transform: Affine) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
|
@ -67,6 +68,7 @@ impl<W: Widget + ?Sized> WidgetPod<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - Remove transform, have it as a special-case property instead.
|
// TODO - Remove transform, have it as a special-case property instead.
|
||||||
|
/// Create a new widget pod with a custom transform and custom [`Properties`].
|
||||||
pub fn new_with(inner: Box<W>, id: WidgetId, transform: Affine, props: Properties) -> Self {
|
pub fn new_with(inner: Box<W>, id: WidgetId, transform: Affine, props: Properties) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright 2019 the Xilem Authors and the Druid Authors
|
// Copyright 2019 the Xilem Authors and the Druid Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
//! Theme keys and initial values.
|
//! Default values used by various widgets in their paint methods.
|
||||||
|
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs, reason = "Names are self-explanatory.")]
|
||||||
|
|
||||||
use crate::kurbo::Insets;
|
use crate::kurbo::Insets;
|
||||||
use crate::peniko::Color;
|
use crate::peniko::Color;
|
||||||
|
|
|
@ -86,7 +86,9 @@ impl<T: Any> AsAny for T {
|
||||||
// --- MARK: PAINT HELPERS ---
|
// --- MARK: PAINT HELPERS ---
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[allow(missing_docs)]
|
/// A point with coordinates in the range [0.0, 1.0].
|
||||||
|
///
|
||||||
|
/// This is useful for specifying points in a normalized space, such as a gradient.
|
||||||
pub struct UnitPoint {
|
pub struct UnitPoint {
|
||||||
u: f64,
|
u: f64,
|
||||||
v: f64,
|
v: f64,
|
||||||
|
@ -96,7 +98,7 @@ pub struct UnitPoint {
|
||||||
single_use_lifetimes,
|
single_use_lifetimes,
|
||||||
reason = "Anonymous lifetimes in `impl Trait` are unstable, see https://github.com/rust-lang/rust/issues/129255"
|
reason = "Anonymous lifetimes in `impl Trait` are unstable, see https://github.com/rust-lang/rust/issues/129255"
|
||||||
)]
|
)]
|
||||||
#[allow(missing_docs)]
|
/// Helper function for [`Scene::stroke`].
|
||||||
pub fn stroke<'b>(
|
pub fn stroke<'b>(
|
||||||
scene: &mut Scene,
|
scene: &mut Scene,
|
||||||
path: &impl Shape,
|
path: &impl Shape,
|
||||||
|
@ -112,8 +114,6 @@ pub fn stroke<'b>(
|
||||||
scene.stroke(&style, Affine::IDENTITY, brush, None, path);
|
scene.stroke(&style, Affine::IDENTITY, brush, None, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
impl UnitPoint {
|
impl UnitPoint {
|
||||||
/// `(0.0, 0.0)`
|
/// `(0.0, 0.0)`
|
||||||
pub const TOP_LEFT: Self = Self::new(0.0, 0.0);
|
pub const TOP_LEFT: Self = Self::new(0.0, 0.0);
|
||||||
|
@ -151,7 +151,7 @@ impl UnitPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
/// Helper function for [`Scene::fill`] with a linear gradient as the brush.
|
||||||
pub fn fill_lin_gradient(
|
pub fn fill_lin_gradient(
|
||||||
scene: &mut Scene,
|
scene: &mut Scene,
|
||||||
path: &impl Shape,
|
path: &impl Shape,
|
||||||
|
@ -164,7 +164,7 @@ pub fn fill_lin_gradient(
|
||||||
scene.fill(Fill::NonZero, Affine::IDENTITY, &brush, None, path);
|
scene.fill(Fill::NonZero, Affine::IDENTITY, &brush, None, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
/// Helper function for [`Scene::fill`] with a uniform color as the brush.
|
||||||
pub fn fill_color(scene: &mut Scene, path: &impl Shape, color: Color) {
|
pub fn fill_color(scene: &mut Scene, path: &impl Shape, color: Color) {
|
||||||
scene.fill(Fill::NonZero, Affine::IDENTITY, color, None, path);
|
scene.fill(Fill::NonZero, Affine::IDENTITY, color, None, path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl Button {
|
||||||
Label::set_text(&mut Self::label_mut(this), new_text);
|
Label::set_text(&mut Self::label_mut(this), new_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Get a mutable reference to the label.
|
||||||
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
|
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
|
||||||
this.ctx.get_mut(&mut this.widget.label)
|
this.ctx.get_mut(&mut this.widget.label)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ impl Checkbox {
|
||||||
|
|
||||||
// --- MARK: WIDGETMUT ---
|
// --- MARK: WIDGETMUT ---
|
||||||
impl Checkbox {
|
impl Checkbox {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Check or uncheck the box.
|
||||||
pub fn set_checked(this: &mut WidgetMut<'_, Self>, checked: bool) {
|
pub fn set_checked(this: &mut WidgetMut<'_, Self>, checked: bool) {
|
||||||
this.widget.checked = checked;
|
this.widget.checked = checked;
|
||||||
// Checked state impacts appearance and accessibility node
|
// Checked state impacts appearance and accessibility node
|
||||||
|
@ -60,7 +60,7 @@ impl Checkbox {
|
||||||
Label::set_text(&mut Self::label_mut(this), new_text);
|
Label::set_text(&mut Self::label_mut(this), new_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Get a mutable reference to the label.
|
||||||
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
|
pub fn label_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, Label> {
|
||||||
this.ctx.get_mut(&mut this.widget.label)
|
this.ctx.get_mut(&mut this.widget.label)
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,12 +294,12 @@ impl Flex {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Returns the number of children (widgets and spacers) this flex container has.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.children.len()
|
self.children.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Returns `true` if this flex container has no children (widgets or spacers).
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
@ -390,7 +390,11 @@ impl Flex {
|
||||||
this.ctx.children_changed();
|
this.ctx.children_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Add a non-flex child widget with a pre-assigned id.
|
||||||
|
///
|
||||||
|
/// See also [`with_child_id`].
|
||||||
|
///
|
||||||
|
/// [`with_child_id`]: Flex::with_child_id
|
||||||
pub fn add_child_id(this: &mut WidgetMut<'_, Self>, child: impl Widget, id: WidgetId) {
|
pub fn add_child_id(this: &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(),
|
||||||
|
@ -453,16 +457,20 @@ impl Flex {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a non-flex child widget.
|
/// Insert a non-flex child widget at the given index.
|
||||||
///
|
///
|
||||||
/// See also [`with_child`].
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// [`with_child`]: Flex::with_child
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_child(this: &mut WidgetMut<'_, Self>, idx: usize, child: impl Widget) {
|
pub fn insert_child(this: &mut WidgetMut<'_, Self>, idx: usize, child: impl Widget) {
|
||||||
Self::insert_child_pod(this, idx, WidgetPod::new(child).erased());
|
Self::insert_child_pod(this, idx, WidgetPod::new(child).erased());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a non-flex child widget.
|
/// Insert a non-flex child widget wrapped in a [`WidgetPod`] at the given index.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_child_pod(
|
pub fn insert_child_pod(
|
||||||
this: &mut WidgetMut<'_, Self>,
|
this: &mut WidgetMut<'_, Self>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -476,7 +484,11 @@ impl Flex {
|
||||||
this.ctx.children_changed();
|
this.ctx.children_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Insert a flex child widget at the given index.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_flex_child(
|
pub fn insert_flex_child(
|
||||||
this: &mut WidgetMut<'_, Self>,
|
this: &mut WidgetMut<'_, Self>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -486,7 +498,11 @@ impl Flex {
|
||||||
Self::insert_flex_child_pod(this, idx, WidgetPod::new(child).erased(), params);
|
Self::insert_flex_child_pod(this, idx, WidgetPod::new(child).erased(), params);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Insert a flex child widget wrapped in a [`WidgetPod`] at the given index.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_flex_child_pod(
|
pub fn insert_flex_child_pod(
|
||||||
this: &mut WidgetMut<'_, Self>,
|
this: &mut WidgetMut<'_, Self>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -499,22 +515,30 @@ impl Flex {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - remove
|
// TODO - remove
|
||||||
/// Add a spacer widget with a standard size.
|
/// Insert a spacer widget with a standard size at the given index.
|
||||||
///
|
///
|
||||||
/// 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.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_default_spacer(this: &mut WidgetMut<'_, Self>, idx: usize) {
|
pub fn insert_default_spacer(this: &mut WidgetMut<'_, Self>, idx: usize) {
|
||||||
let key = axis_default_spacer(this.widget.direction);
|
let key = axis_default_spacer(this.widget.direction);
|
||||||
Self::insert_spacer(this, idx, key);
|
Self::insert_spacer(this, idx, key);
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an empty spacer widget with the given size.
|
/// Insert an empty spacer widget with the given size at the given index.
|
||||||
///
|
///
|
||||||
/// If you are laying out standard controls in this container, you should
|
/// If you are laying out standard controls in this container, you should
|
||||||
/// 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
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_spacer(this: &mut WidgetMut<'_, Self>, idx: usize, mut len: f64) {
|
pub fn insert_spacer(this: &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);
|
||||||
|
@ -527,6 +551,10 @@ impl Flex {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an empty spacer widget with a specific `flex` factor.
|
/// Add an empty spacer widget with a specific `flex` factor.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_flex_spacer(this: &mut WidgetMut<'_, Self>, idx: usize, flex: f64) {
|
pub fn insert_flex_spacer(this: &mut WidgetMut<'_, Self>, idx: usize, flex: f64) {
|
||||||
let flex = if flex >= 0.0 {
|
let flex = if flex >= 0.0 {
|
||||||
flex
|
flex
|
||||||
|
@ -539,7 +567,13 @@ impl Flex {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Remove the child at `idx`.
|
||||||
|
///
|
||||||
|
/// This child can be a widget or a spacer.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) {
|
pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) {
|
||||||
let child = this.widget.children.remove(idx);
|
let child = this.widget.children.remove(idx);
|
||||||
if let Child::Fixed { widget, .. } | Child::Flex { widget, .. } = child {
|
if let Child::Fixed { widget, .. } | Child::Flex { widget, .. } = child {
|
||||||
|
@ -548,7 +582,13 @@ impl Flex {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Returns a mutable reference to the child widget at `idx`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the child at `idx` is a spacer.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn child_mut<'t>(
|
pub fn child_mut<'t>(
|
||||||
this: &'t mut WidgetMut<'_, Self>,
|
this: &'t mut WidgetMut<'_, Self>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -623,7 +663,7 @@ impl Flex {
|
||||||
this.ctx.children_changed();
|
this.ctx.children_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Remove all children from the container.
|
||||||
pub fn clear(this: &mut WidgetMut<'_, Self>) {
|
pub fn clear(this: &mut WidgetMut<'_, Self>) {
|
||||||
if !this.widget.children.is_empty() {
|
if !this.widget.children.is_empty() {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
|
|
|
@ -32,17 +32,21 @@ struct Child {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone, PartialEq)]
|
#[derive(Default, Debug, Copy, Clone, PartialEq)]
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Parameters required when adding an item to a [`Grid`] container.
|
||||||
pub struct GridParams {
|
pub struct GridParams {
|
||||||
|
/// Index of the column this item is starting from.
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
|
/// Index of the row this item is starting from.
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
|
/// Number of columns this item spans.
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
|
/// Number of rows this item spans.
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MARK: IMPL GRID ---
|
// --- MARK: IMPL GRID ---
|
||||||
impl Grid {
|
impl Grid {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Create a new grid with the given number of columns and rows.
|
||||||
pub fn with_dimensions(width: i32, height: i32) -> Self {
|
pub fn with_dimensions(width: i32, height: i32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
|
@ -52,25 +56,23 @@ impl Grid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Builder-style method for setting the spacing between grid items.
|
||||||
pub fn with_spacing(mut self, spacing: f64) -> Self {
|
pub fn with_spacing(mut self, spacing: f64) -> Self {
|
||||||
self.grid_spacing = spacing;
|
self.grid_spacing = spacing;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder-style variant of [`Grid::add_child`].
|
/// Builder-style method to add a child widget.
|
||||||
///
|
|
||||||
/// Convenient for assembling a group of widgets in a single expression.
|
|
||||||
pub fn with_child(self, child: impl Widget, params: GridParams) -> Self {
|
pub fn with_child(self, child: impl Widget, params: GridParams) -> Self {
|
||||||
self.with_child_pod(WidgetPod::new(child).erased(), params)
|
self.with_child_pod(WidgetPod::new(child).erased(), params)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Builder-style method to add a child widget with a pre-assigned id.
|
||||||
pub fn with_child_id(self, child: impl Widget, id: WidgetId, params: GridParams) -> Self {
|
pub fn with_child_id(self, child: impl Widget, id: WidgetId, params: GridParams) -> Self {
|
||||||
self.with_child_pod(WidgetPod::new_with_id(child, id).erased(), params)
|
self.with_child_pod(WidgetPod::new_with_id(child, id).erased(), params)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Builder-style method to add a child widget already wrapped in a [`WidgetPod`].
|
||||||
pub fn with_child_pod(mut self, widget: WidgetPod<dyn Widget>, params: GridParams) -> Self {
|
pub fn with_child_pod(mut self, widget: WidgetPod<dyn Widget>, params: GridParams) -> Self {
|
||||||
let child = Child {
|
let child = Child {
|
||||||
widget,
|
widget,
|
||||||
|
@ -86,13 +88,6 @@ impl Grid {
|
||||||
|
|
||||||
// --- MARK: IMPL CHILD ---
|
// --- MARK: IMPL CHILD ---
|
||||||
impl Child {
|
impl Child {
|
||||||
fn widget_mut(&mut self) -> Option<&mut WidgetPod<dyn Widget>> {
|
|
||||||
Some(&mut self.widget)
|
|
||||||
}
|
|
||||||
fn widget(&self) -> Option<&WidgetPod<dyn Widget>> {
|
|
||||||
Some(&self.widget)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_params(&mut self, params: GridParams) {
|
fn update_params(&mut self, params: GridParams) {
|
||||||
self.x = params.x;
|
self.x = params.x;
|
||||||
self.y = params.y;
|
self.y = params.y;
|
||||||
|
@ -113,8 +108,13 @@ fn new_grid_child(params: GridParams, widget: WidgetPod<dyn Widget>) -> Child {
|
||||||
|
|
||||||
// --- MARK: IMPL GRIDPARAMS ---
|
// --- MARK: IMPL GRIDPARAMS ---
|
||||||
impl GridParams {
|
impl GridParams {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Create grid parameters with the given values.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When debug assertions are on, panics if the width or height is less than or equal to zero or if x or y is negative.
|
||||||
pub fn new(mut x: i32, mut y: i32, mut width: i32, mut height: i32) -> Self {
|
pub fn new(mut x: i32, mut y: i32, mut width: i32, mut height: i32) -> Self {
|
||||||
|
// TODO - Use u32 params instead?
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
debug_panic!("Grid x value should be a non-negative number; got {}", x);
|
debug_panic!("Grid x value should be a non-negative number; got {}", x);
|
||||||
x = 0;
|
x = 0;
|
||||||
|
@ -150,15 +150,15 @@ impl GridParams {
|
||||||
impl Grid {
|
impl Grid {
|
||||||
/// Add a child widget.
|
/// Add a child widget.
|
||||||
///
|
///
|
||||||
/// See also [`with_child`].
|
/// See also [`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(this: &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::add_child_pod(this, child_pod, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Add a child widget with a pre-assigned id.
|
||||||
|
///
|
||||||
|
/// See also [`with_child_id`](Grid::with_child_id).
|
||||||
pub fn add_child_id(
|
pub fn add_child_id(
|
||||||
this: &mut WidgetMut<'_, Self>,
|
this: &mut WidgetMut<'_, Self>,
|
||||||
child: impl Widget,
|
child: impl Widget,
|
||||||
|
@ -166,11 +166,13 @@ impl Grid {
|
||||||
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::add_child_pod(this, child_pod, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a child widget.
|
/// Add a child widget already wrapped in a [`WidgetPod`].
|
||||||
pub fn insert_child_pod(
|
///
|
||||||
|
/// See also [`with_child_pod`](Grid::with_child_pod).
|
||||||
|
pub fn add_child_pod(
|
||||||
this: &mut WidgetMut<'_, Self>,
|
this: &mut WidgetMut<'_, Self>,
|
||||||
widget: WidgetPod<dyn Widget>,
|
widget: WidgetPod<dyn Widget>,
|
||||||
params: GridParams,
|
params: GridParams,
|
||||||
|
@ -181,7 +183,14 @@ impl Grid {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Insert a child widget at the given index.
|
||||||
|
///
|
||||||
|
/// This lets you control the order in which the children are drawn. Children are
|
||||||
|
/// drawn in index order (i.e. each child is drawn on top of the children with lower indices).
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_grid_child_at(
|
pub fn insert_grid_child_at(
|
||||||
this: &mut WidgetMut<'_, Self>,
|
this: &mut WidgetMut<'_, Self>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -191,7 +200,14 @@ impl Grid {
|
||||||
Self::insert_grid_child_pod(this, idx, WidgetPod::new(child).erased(), params);
|
Self::insert_grid_child_pod(this, idx, WidgetPod::new(child).erased(), params);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Insert a child widget already wrapped in a [`WidgetPod`] at the given index.
|
||||||
|
///
|
||||||
|
/// This lets you control the order in which the children are drawn. Children are
|
||||||
|
/// drawn in index order (i.e. each child is drawn on top of the children with lower indices).
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is larger than the number of children.
|
||||||
pub fn insert_grid_child_pod(
|
pub fn insert_grid_child_pod(
|
||||||
this: &mut WidgetMut<'_, Self>,
|
this: &mut WidgetMut<'_, Self>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -204,31 +220,37 @@ impl Grid {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Set the spacing between grid items.
|
||||||
pub fn set_spacing(this: &mut WidgetMut<'_, Self>, spacing: f64) {
|
pub fn set_spacing(this: &mut WidgetMut<'_, Self>, spacing: f64) {
|
||||||
this.widget.grid_spacing = spacing;
|
this.widget.grid_spacing = spacing;
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
// TODO - Some of these method names should maybe be changed.
|
||||||
|
// "height" and "width" are misleading, since they suggest a pixel size.
|
||||||
|
/// Set the number of columns of the grid.
|
||||||
pub fn set_width(this: &mut WidgetMut<'_, Self>, width: i32) {
|
pub fn set_width(this: &mut WidgetMut<'_, Self>, width: i32) {
|
||||||
this.widget.grid_width = width;
|
this.widget.grid_width = width;
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Set the number of rows of the grid.
|
||||||
pub fn set_height(this: &mut WidgetMut<'_, Self>, height: i32) {
|
pub fn set_height(this: &mut WidgetMut<'_, Self>, height: i32) {
|
||||||
this.widget.grid_height = height;
|
this.widget.grid_height = height;
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Get a mutable reference to the child at `idx`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `idx` is out of bounds.
|
||||||
pub fn child_mut<'t>(
|
pub fn child_mut<'t>(
|
||||||
this: &'t mut WidgetMut<'_, Self>,
|
this: &'t mut WidgetMut<'_, Self>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
) -> Option<WidgetMut<'t, dyn Widget>> {
|
) -> WidgetMut<'t, dyn Widget> {
|
||||||
let child = this.widget.children[idx].widget_mut()?;
|
let child = &mut this.widget.children[idx].widget;
|
||||||
Some(this.ctx.get_mut(child))
|
this.ctx.get_mut(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the grid parameters for the child at `idx`,
|
/// Updates the grid parameters for the child at `idx`,
|
||||||
|
@ -246,7 +268,11 @@ impl Grid {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Removes a child widget at the given index.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the index is out of bounds.
|
||||||
pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) {
|
pub fn remove_child(this: &mut WidgetMut<'_, Self>, idx: usize) {
|
||||||
let child = this.widget.children.remove(idx);
|
let child = this.widget.children.remove(idx);
|
||||||
this.ctx.remove_child(child.widget);
|
this.ctx.remove_child(child.widget);
|
||||||
|
@ -281,8 +307,8 @@ impl Widget for Grid {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_children(&mut self, ctx: &mut crate::core::RegisterCtx) {
|
fn register_children(&mut self, ctx: &mut crate::core::RegisterCtx) {
|
||||||
for child in self.children.iter_mut().filter_map(|x| x.widget_mut()) {
|
for child in self.children.iter_mut() {
|
||||||
ctx.register_child(child);
|
ctx.register_child(&mut child.widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,8 +369,7 @@ impl Widget for Grid {
|
||||||
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
|
||||||
self.children
|
self.children
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|child| child.widget())
|
.map(|child| child.widget.id())
|
||||||
.map(|widget_pod| widget_pod.id())
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ use crate::theme;
|
||||||
use crate::util::{UnitPoint, fill_lin_gradient, stroke};
|
use crate::util::{UnitPoint, fill_lin_gradient, stroke};
|
||||||
use crate::widgets::{Label, LineBreaking};
|
use crate::widgets::{Label, LineBreaking};
|
||||||
|
|
||||||
|
// TODO - NaN probably shouldn't be a meaningful value in our API.
|
||||||
|
|
||||||
/// A progress bar.
|
/// A progress bar.
|
||||||
///
|
///
|
||||||
#[doc = crate::include_screenshot!("widget/screenshots/masonry__widget__progress_bar__tests__25_percent_progressbar.png", "25% progress bar.")]
|
#[doc = crate::include_screenshot!("widget/screenshots/masonry__widget__progress_bar__tests__25_percent_progressbar.png", "25% progress bar.")]
|
||||||
|
@ -33,11 +35,11 @@ pub struct ProgressBar {
|
||||||
impl ProgressBar {
|
impl ProgressBar {
|
||||||
/// Create a new `ProgressBar`.
|
/// Create a new `ProgressBar`.
|
||||||
///
|
///
|
||||||
/// `progress` is a number between 0 and 1 inclusive. If it is `NaN`, then an
|
/// The progress value will be clamped to [0, 1].
|
||||||
/// indefinite progress bar will be shown.
|
///
|
||||||
/// Otherwise, the input will be clamped to [0, 1].
|
/// A `None` value (or NaN) will show an indeterminate progress bar.
|
||||||
pub fn new(mut progress: Option<f64>) -> Self {
|
pub fn new(progress: Option<f64>) -> Self {
|
||||||
clamp_progress(&mut progress);
|
let progress = clamp_progress(progress);
|
||||||
let label = WidgetPod::new(
|
let label = WidgetPod::new(
|
||||||
Label::new(Self::value(progress)).with_line_break_mode(LineBreaking::Overflow),
|
Label::new(Self::value(progress)).with_line_break_mode(LineBreaking::Overflow),
|
||||||
);
|
);
|
||||||
|
@ -63,9 +65,13 @@ impl ProgressBar {
|
||||||
|
|
||||||
// --- MARK: WIDGETMUT ---
|
// --- MARK: WIDGETMUT ---
|
||||||
impl ProgressBar {
|
impl ProgressBar {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Set the progress displayed by the bar.
|
||||||
pub fn set_progress(this: &mut WidgetMut<'_, Self>, mut progress: Option<f64>) {
|
///
|
||||||
clamp_progress(&mut progress);
|
/// The progress value will be clamped to [0, 1].
|
||||||
|
///
|
||||||
|
/// A `None` value (or NaN) will show an indeterminate progress bar.
|
||||||
|
pub fn set_progress(this: &mut WidgetMut<'_, Self>, progress: Option<f64>) {
|
||||||
|
let progress = clamp_progress(progress);
|
||||||
let progress_changed = this.widget.progress != progress;
|
let progress_changed = this.widget.progress != progress;
|
||||||
if progress_changed {
|
if progress_changed {
|
||||||
this.widget.progress = progress;
|
this.widget.progress = progress;
|
||||||
|
@ -80,13 +86,12 @@ impl ProgressBar {
|
||||||
/// Helper to ensure progress is either a number between [0, 1] inclusive, or `None`.
|
/// Helper to ensure progress is either a number between [0, 1] inclusive, or `None`.
|
||||||
///
|
///
|
||||||
/// NaNs are converted to `None`.
|
/// NaNs are converted to `None`.
|
||||||
fn clamp_progress(progress: &mut Option<f64>) {
|
fn clamp_progress(progress: Option<f64>) -> Option<f64> {
|
||||||
if let Some(value) = progress {
|
let progress = progress?;
|
||||||
if value.is_nan() {
|
if progress.is_nan() {
|
||||||
*progress = None;
|
None
|
||||||
} else {
|
} else {
|
||||||
*progress = Some(value.clamp(0., 1.));
|
Some(progress.clamp(0., 1.))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,15 +14,15 @@ use crate::core::{
|
||||||
};
|
};
|
||||||
use crate::kurbo::Size;
|
use crate::kurbo::Size;
|
||||||
|
|
||||||
// TODO: This is a hack to provide an accessibility node with a Window type.
|
// TODO: This should eventually be removed once accesskit does that for us.
|
||||||
// This should eventually be removed.
|
// See https://github.com/AccessKit/accesskit/issues/531
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// A widget wrapper that reports a [`Role::Window`] to the accessibility API.
|
||||||
pub struct RootWidget<W: ?Sized> {
|
pub struct RootWidget<W: ?Sized> {
|
||||||
pub(crate) pod: WidgetPod<W>,
|
pub(crate) pod: WidgetPod<W>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget> RootWidget<W> {
|
impl<W: Widget> RootWidget<W> {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Create a new root widget.
|
||||||
pub fn new(widget: W) -> Self {
|
pub fn new(widget: W) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pod: WidgetPod::new(widget),
|
pod: WidgetPod::new(widget),
|
||||||
|
@ -31,14 +31,14 @@ impl<W: Widget> RootWidget<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> {
|
impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Create a new root widget from a [`WidgetPod`].
|
||||||
pub fn from_pod(pod: WidgetPod<W>) -> Self {
|
pub fn from_pod(pod: WidgetPod<W>) -> Self {
|
||||||
Self { pod }
|
Self { pod }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> {
|
impl<W: Widget + FromDynWidget + ?Sized> RootWidget<W> {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Get a mutable reference to the child widget.
|
||||||
pub fn child_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, W> {
|
pub fn child_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, W> {
|
||||||
this.ctx.get_mut(&mut this.widget.pod)
|
this.ctx.get_mut(&mut this.widget.pod)
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,7 +327,9 @@ impl SizedBox {
|
||||||
|
|
||||||
// --- MARK: WIDGETMUT ---
|
// --- MARK: WIDGETMUT ---
|
||||||
impl SizedBox {
|
impl SizedBox {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Give this container a child widget.
|
||||||
|
///
|
||||||
|
/// If this container already has a child, it will be overwritten.
|
||||||
pub fn set_child(this: &mut WidgetMut<'_, Self>, child: impl Widget) {
|
pub fn set_child(this: &mut WidgetMut<'_, Self>, child: impl Widget) {
|
||||||
if let Some(child) = this.widget.child.take() {
|
if let Some(child) = this.widget.child.take() {
|
||||||
this.ctx.remove_child(child);
|
this.ctx.remove_child(child);
|
||||||
|
@ -337,7 +339,9 @@ impl SizedBox {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Remove the child widget.
|
||||||
|
///
|
||||||
|
/// (If this widget has no child, this method does nothing.)
|
||||||
pub fn remove_child(this: &mut WidgetMut<'_, Self>) {
|
pub fn remove_child(this: &mut WidgetMut<'_, Self>) {
|
||||||
if let Some(child) = this.widget.child.take() {
|
if let Some(child) = this.widget.child.take() {
|
||||||
this.ctx.remove_child(child);
|
this.ctx.remove_child(child);
|
||||||
|
@ -422,7 +426,7 @@ impl SizedBox {
|
||||||
this.ctx.request_layout();
|
this.ctx.request_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Get mutable reference to the child widget, if any.
|
||||||
pub fn child_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> Option<WidgetMut<'t, dyn Widget>> {
|
pub fn child_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> Option<WidgetMut<'t, dyn Widget>> {
|
||||||
let child = this.widget.child.as_mut()?;
|
let child = this.widget.child.as_mut()?;
|
||||||
Some(this.ctx.get_mut(child))
|
Some(this.ctx.get_mut(child))
|
||||||
|
|
|
@ -53,7 +53,7 @@ impl<ChildA: Widget, ChildB: Widget> Split<ChildA, ChildB> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ChildA: Widget + ?Sized, ChildB: Widget + ?Sized> Split<ChildA, ChildB> {
|
impl<ChildA: Widget + ?Sized, ChildB: Widget + ?Sized> Split<ChildA, ChildB> {
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Build split panel from two children already wrapped in [`WidgetPod`]s.
|
||||||
pub fn new_pod(child1: WidgetPod<ChildA>, child2: WidgetPod<ChildB>) -> Self {
|
pub fn new_pod(child1: WidgetPod<ChildA>, child2: WidgetPod<ChildB>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
split_axis: Axis::Horizontal,
|
split_axis: Axis::Horizontal,
|
||||||
|
@ -304,12 +304,12 @@ where
|
||||||
ChildA: Widget + FromDynWidget + ?Sized,
|
ChildA: Widget + FromDynWidget + ?Sized,
|
||||||
ChildB: Widget + FromDynWidget + ?Sized,
|
ChildB: Widget + FromDynWidget + ?Sized,
|
||||||
{
|
{
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Get a mutable reference to the first child widget.
|
||||||
pub fn child1_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, ChildA> {
|
pub fn child1_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, ChildA> {
|
||||||
this.ctx.get_mut(&mut this.widget.child1)
|
this.ctx.get_mut(&mut this.widget.child1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Get a mutable reference to the second child widget.
|
||||||
pub fn child2_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, ChildB> {
|
pub fn child2_mut<'t>(this: &'t mut WidgetMut<'_, Self>) -> WidgetMut<'t, ChildB> {
|
||||||
this.ctx.get_mut(&mut this.widget.child2)
|
this.ctx.get_mut(&mut this.widget.child2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,12 +133,16 @@ impl VariableLabel {
|
||||||
Self::from_label_pod(WidgetPod::new(Label::new(text)))
|
Self::from_label_pod(WidgetPod::new(Label::new(text)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Create a new variable label from the given label.
|
||||||
|
///
|
||||||
|
/// Uses the label's text and style values.
|
||||||
pub fn from_label(label: Label) -> Self {
|
pub fn from_label(label: Label) -> Self {
|
||||||
Self::from_label_pod(WidgetPod::new(label))
|
Self::from_label_pod(WidgetPod::new(label))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(missing_docs, reason = "TODO")]
|
/// Create a new variable label from the given label wrapped in a [`WidgetPod`].
|
||||||
|
///
|
||||||
|
/// Uses the label's text and style values.
|
||||||
pub fn from_label_pod(label: WidgetPod<Label>) -> Self {
|
pub fn from_label_pod(label: WidgetPod<Label>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
label,
|
label,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright 2024 the Xilem Authors
|
// Copyright 2024 the Xilem Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#![expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use masonry::app::{AppDriver, EventLoopProxy, MasonryState, MasonryUserEvent};
|
use masonry::app::{AppDriver, EventLoopProxy, MasonryState, MasonryUserEvent};
|
||||||
|
|
|
@ -128,7 +128,6 @@
|
||||||
#![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")]
|
#![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")]
|
||||||
#![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")]
|
#![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")]
|
||||||
// https://github.com/rust-lang/rust/pull/130025
|
// https://github.com/rust-lang/rust/pull/130025
|
||||||
#![allow(missing_docs, reason = "We have many as-yet undocumented items")]
|
|
||||||
#![expect(clippy::allow_attributes_without_reason, reason = "Deferred: Noisy")]
|
#![expect(clippy::allow_attributes_without_reason, reason = "Deferred: Noisy")]
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -178,11 +177,13 @@ pub struct Xilem<State, Logic> {
|
||||||
fonts: Vec<Vec<u8>>,
|
fonts: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
impl<State, Logic, View> Xilem<State, Logic>
|
impl<State, Logic, View> Xilem<State, Logic>
|
||||||
where
|
where
|
||||||
Logic: FnMut(&mut State) -> View,
|
Logic: FnMut(&mut State) -> View,
|
||||||
View: WidgetView<State>,
|
View: WidgetView<State>,
|
||||||
{
|
{
|
||||||
|
/// Initialize the builder state for your app.
|
||||||
pub fn new(state: State, logic: Logic) -> Self {
|
pub fn new(state: State, logic: Logic) -> Self {
|
||||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
Self {
|
Self {
|
||||||
|
@ -287,6 +288,7 @@ where
|
||||||
/// and so might not actually own the underlying widget value.
|
/// and so might not actually own the underlying widget value.
|
||||||
/// When creating widgets in Xilem, layered views all want access to the - using
|
/// When creating widgets in Xilem, layered views all want access to the - using
|
||||||
/// `WidgetPod` for this purpose would require fallible unwrapping.
|
/// `WidgetPod` for this purpose would require fallible unwrapping.
|
||||||
|
#[expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
pub struct Pod<W: Widget + FromDynWidget + ?Sized> {
|
pub struct Pod<W: Widget + FromDynWidget + ?Sized> {
|
||||||
pub widget: Box<W>,
|
pub widget: Box<W>,
|
||||||
pub id: WidgetId,
|
pub id: WidgetId,
|
||||||
|
@ -366,6 +368,7 @@ impl<W: Widget + FromDynWidget + ?Sized> SuperElement<Pod<W>, ViewCtx> for Pod<d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
pub trait WidgetView<State, Action = ()>:
|
pub trait WidgetView<State, Action = ()>:
|
||||||
View<State, Action, ViewCtx, Element = Pod<Self::Widget>> + Send + Sync
|
View<State, Action, ViewCtx, Element = Pod<Self::Widget>> + Send + Sync
|
||||||
{
|
{
|
||||||
|
@ -438,6 +441,7 @@ impl<Seq, State, Action> WidgetViewSequence<State, Action> for Seq where
|
||||||
|
|
||||||
type WidgetMap = HashMap<WidgetId, Vec<ViewId>>;
|
type WidgetMap = HashMap<WidgetId, Vec<ViewId>>;
|
||||||
|
|
||||||
|
/// A context type passed to various methods of Xilem traits.
|
||||||
pub struct ViewCtx {
|
pub struct ViewCtx {
|
||||||
/// The map from a widgets id to its position in the View tree.
|
/// The map from a widgets id to its position in the View tree.
|
||||||
///
|
///
|
||||||
|
@ -462,6 +466,7 @@ impl ViewPathTracker for ViewCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
impl ViewCtx {
|
impl ViewCtx {
|
||||||
pub fn new_pod<W: Widget + FromDynWidget>(&mut self, widget: W) -> Pod<W> {
|
pub fn new_pod<W: Widget + FromDynWidget>(&mut self, widget: W) -> Pod<W> {
|
||||||
Pod::new(widget)
|
Pod::new(widget)
|
||||||
|
|
|
@ -84,20 +84,23 @@ pub struct Flex<Seq, State, Action = ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Seq, State, Action> Flex<Seq, State, Action> {
|
impl<Seq, State, Action> Flex<Seq, State, Action> {
|
||||||
|
/// Set the flex direction (see [`Axis`]).
|
||||||
pub fn direction(mut self, axis: Axis) -> Self {
|
pub fn direction(mut self, axis: Axis) -> Self {
|
||||||
self.axis = axis;
|
self.axis = axis;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
/// Set the childrens' [`CrossAxisAlignment`].
|
||||||
pub fn cross_axis_alignment(mut self, axis: CrossAxisAlignment) -> Self {
|
pub fn cross_axis_alignment(mut self, axis: CrossAxisAlignment) -> Self {
|
||||||
self.cross_axis_alignment = axis;
|
self.cross_axis_alignment = axis;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
/// Set the childrens' [`MainAxisAlignment`].
|
||||||
pub fn main_axis_alignment(mut self, axis: MainAxisAlignment) -> Self {
|
pub fn main_axis_alignment(mut self, axis: MainAxisAlignment) -> Self {
|
||||||
self.main_axis_alignment = axis;
|
self.main_axis_alignment = axis;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
/// Set whether the container must expand to fill the available space on
|
||||||
|
/// its main axis.
|
||||||
pub fn must_fill_major_axis(mut self, fill_major_axis: bool) -> Self {
|
pub fn must_fill_major_axis(mut self, fill_major_axis: bool) -> Self {
|
||||||
self.fill_major_axis = fill_major_axis;
|
self.fill_major_axis = fill_major_axis;
|
||||||
self
|
self
|
||||||
|
@ -214,12 +217,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A child element of a [`Flex`] view.
|
||||||
pub enum FlexElement {
|
pub enum FlexElement {
|
||||||
|
/// Child widget.
|
||||||
Child(Pod<dyn Widget>, FlexParams),
|
Child(Pod<dyn Widget>, FlexParams),
|
||||||
|
/// Child spacer with fixed size.
|
||||||
FixedSpacer(f64),
|
FixedSpacer(f64),
|
||||||
|
/// Child spacer with flex size.
|
||||||
FlexSpacer(f64),
|
FlexSpacer(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A mutable reference to a [`FlexElement`], used internally by Xilem traits.
|
||||||
pub struct FlexElementMut<'w> {
|
pub struct FlexElementMut<'w> {
|
||||||
parent: WidgetMut<'w, widgets::Flex>,
|
parent: WidgetMut<'w, widgets::Flex>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
@ -549,6 +557,7 @@ where
|
||||||
|
|
||||||
/// A spacer that can be used within a [`Flex`] [`View`]
|
/// A spacer that can be used within a [`Flex`] [`View`]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
#[expect(missing_docs, reason = "TODO - Need to document units used.")]
|
||||||
pub enum FlexSpacer {
|
pub enum FlexSpacer {
|
||||||
Fixed(f64),
|
Fixed(f64),
|
||||||
Flex(f64),
|
Flex(f64),
|
||||||
|
@ -610,7 +619,9 @@ impl<State, Action> View<State, Action, ViewCtx> for FlexSpacer {
|
||||||
|
|
||||||
/// A widget-type-erased flex child [`View`], can be used within a [`Flex`] [`View`]
|
/// A widget-type-erased flex child [`View`], can be used within a [`Flex`] [`View`]
|
||||||
pub enum AnyFlexChild<State, Action = ()> {
|
pub enum AnyFlexChild<State, Action = ()> {
|
||||||
|
/// A child widget.
|
||||||
Item(FlexItem<Box<AnyWidgetView<State, Action>>, State, Action>),
|
Item(FlexItem<Box<AnyWidgetView<State, Action>>, State, Action>),
|
||||||
|
/// A spacer.
|
||||||
Spacer(FlexSpacer),
|
Spacer(FlexSpacer),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,7 @@ pub struct Grid<Seq, State, Action = ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Seq, State, Action> Grid<Seq, State, Action> {
|
impl<Seq, State, Action> Grid<Seq, State, Action> {
|
||||||
|
/// Set the spacing (both vertical and horizontal) between grid items.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn spacing(mut self, spacing: f64) -> Self {
|
pub fn spacing(mut self, spacing: f64) -> Self {
|
||||||
if spacing.is_finite() && spacing >= 0.0 {
|
if spacing.is_finite() && spacing >= 0.0 {
|
||||||
|
@ -104,12 +105,8 @@ where
|
||||||
let mut widget = widgets::Grid::with_dimensions(self.width, self.height);
|
let mut widget = widgets::Grid::with_dimensions(self.width, self.height);
|
||||||
widget = widget.with_spacing(self.spacing);
|
widget = widget.with_spacing(self.spacing);
|
||||||
let seq_state = self.sequence.seq_build(ctx, &mut elements);
|
let seq_state = self.sequence.seq_build(ctx, &mut elements);
|
||||||
for child in elements.into_inner() {
|
for element in elements.into_inner() {
|
||||||
widget = match child {
|
widget = widget.with_child_pod(element.child.erased_widget_pod(), element.params);
|
||||||
GridElement::Child(child, params) => {
|
|
||||||
widget.with_child_pod(child.erased_widget_pod(), params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let pod = ctx.new_pod(widget);
|
let pod = ctx.new_pod(widget);
|
||||||
(pod, seq_state)
|
(pod, seq_state)
|
||||||
|
@ -195,7 +192,11 @@ impl<W: Widget + FromDynWidget + ?Sized> SuperElement<Pod<W>, ViewCtx> for GridE
|
||||||
// There is not much else, beyond purposefully failing, that can be done here,
|
// There is not much else, beyond purposefully failing, that can be done here,
|
||||||
// because there isn't enough information to determine an appropriate spot
|
// because there isn't enough information to determine an appropriate spot
|
||||||
// for the widget.
|
// for the widget.
|
||||||
Self::Child(child.erased(), GridParams::new(1, 1, 1, 1))
|
Self {
|
||||||
|
child: child.erased(),
|
||||||
|
// TODO - Should be 0, 0?
|
||||||
|
params: GridParams::new(1, 1, 1, 1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_downcast_val<R>(
|
fn with_downcast_val<R>(
|
||||||
|
@ -203,8 +204,7 @@ impl<W: Widget + FromDynWidget + ?Sized> SuperElement<Pod<W>, ViewCtx> for GridE
|
||||||
f: impl FnOnce(Mut<Pod<W>>) -> R,
|
f: impl FnOnce(Mut<Pod<W>>) -> R,
|
||||||
) -> (Mut<Self>, R) {
|
) -> (Mut<Self>, R) {
|
||||||
let ret = {
|
let ret = {
|
||||||
let mut child = widgets::Grid::child_mut(&mut this.parent, this.idx)
|
let mut child = widgets::Grid::child_mut(&mut this.parent, this.idx);
|
||||||
.expect("This is supposed to be a widget");
|
|
||||||
let downcast = child.downcast();
|
let downcast = child.downcast();
|
||||||
f(downcast)
|
f(downcast)
|
||||||
};
|
};
|
||||||
|
@ -218,32 +218,24 @@ impl ElementSplice<GridElement> for GridSplice<'_> {
|
||||||
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<GridElement>) -> R) -> R {
|
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<GridElement>) -> R) -> R {
|
||||||
let ret = f(&mut self.scratch);
|
let ret = f(&mut self.scratch);
|
||||||
for element in self.scratch.drain() {
|
for element in self.scratch.drain() {
|
||||||
match element {
|
widgets::Grid::insert_grid_child_pod(
|
||||||
GridElement::Child(child, params) => {
|
&mut self.element,
|
||||||
widgets::Grid::insert_grid_child_pod(
|
self.idx,
|
||||||
&mut self.element,
|
element.child.erased_widget_pod(),
|
||||||
self.idx,
|
element.params,
|
||||||
child.erased_widget_pod(),
|
);
|
||||||
params,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.idx += 1;
|
self.idx += 1;
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, element: GridElement) {
|
fn insert(&mut self, element: GridElement) {
|
||||||
match element {
|
widgets::Grid::insert_grid_child_pod(
|
||||||
GridElement::Child(child, params) => {
|
&mut self.element,
|
||||||
widgets::Grid::insert_grid_child_pod(
|
self.idx,
|
||||||
&mut self.element,
|
element.child.erased_widget_pod(),
|
||||||
self.idx,
|
element.params,
|
||||||
child.erased_widget_pod(),
|
);
|
||||||
params,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.idx += 1;
|
self.idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,17 +334,22 @@ pub trait GridExt<State, Action>: WidgetView<State, Action> {
|
||||||
|
|
||||||
impl<State, Action, V: WidgetView<State, Action>> GridExt<State, Action> for V {}
|
impl<State, Action, V: WidgetView<State, Action>> GridExt<State, Action> for V {}
|
||||||
|
|
||||||
pub enum GridElement {
|
/// A child widget within a [`Grid`] view.
|
||||||
Child(Pod<dyn Widget>, GridParams),
|
pub struct GridElement {
|
||||||
|
/// The child widget.
|
||||||
|
child: Pod<dyn Widget>,
|
||||||
|
/// The grid parameters of the child widget.
|
||||||
|
params: GridParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A mutable reference to a [`GridElement`], used internally by Xilem traits.
|
||||||
pub struct GridElementMut<'w> {
|
pub struct GridElementMut<'w> {
|
||||||
parent: WidgetMut<'w, widgets::Grid>,
|
parent: WidgetMut<'w, widgets::Grid>,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for manipulating the ViewSequence.
|
// Used for manipulating the ViewSequence.
|
||||||
pub struct GridSplice<'w> {
|
struct GridSplice<'w> {
|
||||||
idx: usize,
|
idx: usize,
|
||||||
element: WidgetMut<'w, widgets::Grid>,
|
element: WidgetMut<'w, widgets::Grid>,
|
||||||
scratch: AppendVec<GridElement>,
|
scratch: AppendVec<GridElement>,
|
||||||
|
@ -375,6 +372,7 @@ pub struct GridItem<V, State, Action> {
|
||||||
phantom: PhantomData<fn() -> (State, Action)>,
|
phantom: PhantomData<fn() -> (State, Action)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a [`GridItem`] from a view and [`GridParams`].
|
||||||
pub fn grid_item<V, State, Action>(
|
pub fn grid_item<V, State, Action>(
|
||||||
view: V,
|
view: V,
|
||||||
params: impl Into<GridParams>,
|
params: impl Into<GridParams>,
|
||||||
|
@ -405,7 +403,13 @@ where
|
||||||
|
|
||||||
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
|
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
|
||||||
let (pod, state) = self.view.build(ctx);
|
let (pod, state) = self.view.build(ctx);
|
||||||
(GridElement::Child(pod.erased(), self.params), state)
|
(
|
||||||
|
GridElement {
|
||||||
|
child: pod.erased(),
|
||||||
|
params: self.params,
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rebuild(
|
fn rebuild(
|
||||||
|
@ -423,8 +427,7 @@ where
|
||||||
self.params,
|
self.params,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx)
|
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx);
|
||||||
.expect("GridWrapper always has a widget child");
|
|
||||||
self.view
|
self.view
|
||||||
.rebuild(&prev.view, view_state, ctx, child.downcast());
|
.rebuild(&prev.view, view_state, ctx, child.downcast());
|
||||||
}
|
}
|
||||||
|
@ -436,8 +439,7 @@ where
|
||||||
ctx: &mut ViewCtx,
|
ctx: &mut ViewCtx,
|
||||||
mut element: Mut<Self::Element>,
|
mut element: Mut<Self::Element>,
|
||||||
) {
|
) {
|
||||||
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx)
|
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx);
|
||||||
.expect("GridWrapper always has a widget child");
|
|
||||||
self.view.teardown(view_state, ctx, child.downcast());
|
self.view.teardown(view_state, ctx, child.downcast());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The [`View`] created by [`portal`].
|
||||||
#[must_use = "View values do nothing unless provided to Xilem."]
|
#[must_use = "View values do nothing unless provided to Xilem."]
|
||||||
pub struct Portal<V, State, Action> {
|
pub struct Portal<V, State, Action> {
|
||||||
child: V,
|
child: V,
|
||||||
|
|
|
@ -6,10 +6,15 @@ use masonry::widgets;
|
||||||
use crate::core::{DynMessage, Mut, ViewMarker};
|
use crate::core::{DynMessage, Mut, ViewMarker};
|
||||||
use crate::{MessageResult, Pod, View, ViewCtx, ViewId};
|
use crate::{MessageResult, Pod, View, ViewCtx, ViewId};
|
||||||
|
|
||||||
|
/// A view which displays a progress bar.
|
||||||
|
///
|
||||||
|
/// This can be for showing progress of a task or a download.
|
||||||
pub fn progress_bar(progress: Option<f64>) -> ProgressBar {
|
pub fn progress_bar(progress: Option<f64>) -> ProgressBar {
|
||||||
ProgressBar { progress }
|
ProgressBar { progress }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The [`View`] created by [`progress_bar`].
|
||||||
|
#[must_use = "View values do nothing unless provided to Xilem."]
|
||||||
pub struct ProgressBar {
|
pub struct ProgressBar {
|
||||||
progress: Option<f64>,
|
progress: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use vello::peniko::Brush;
|
||||||
use crate::core::{DynMessage, Mut, ViewMarker};
|
use crate::core::{DynMessage, Mut, ViewMarker};
|
||||||
use crate::{Color, MessageResult, Pod, TextAlignment, View, ViewCtx, ViewId};
|
use crate::{Color, MessageResult, Pod, TextAlignment, View, ViewCtx, ViewId};
|
||||||
|
|
||||||
|
/// A view which displays selectable text.
|
||||||
pub fn prose(content: impl Into<ArcStr>) -> Prose {
|
pub fn prose(content: impl Into<ArcStr>) -> Prose {
|
||||||
Prose {
|
Prose {
|
||||||
content: content.into(),
|
content: content.into(),
|
||||||
|
@ -30,6 +31,7 @@ pub fn inline_prose(content: impl Into<ArcStr>) -> Prose {
|
||||||
prose(content).line_break_mode(LineBreaking::Overflow)
|
prose(content).line_break_mode(LineBreaking::Overflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The [`View`] created by [`prose`] or [`inline_prose`].
|
||||||
#[must_use = "View values do nothing unless provided to Xilem."]
|
#[must_use = "View values do nothing unless provided to Xilem."]
|
||||||
pub struct Prose {
|
pub struct Prose {
|
||||||
content: ArcStr,
|
content: ArcStr,
|
||||||
|
@ -43,22 +45,27 @@ pub struct Prose {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Prose {
|
impl Prose {
|
||||||
|
/// Set the brush used to paint the text.
|
||||||
#[doc(alias = "color")]
|
#[doc(alias = "color")]
|
||||||
pub fn brush(mut self, brush: impl Into<Brush>) -> Self {
|
pub fn brush(mut self, brush: impl Into<Brush>) -> Self {
|
||||||
self.text_brush = brush.into();
|
self.text_brush = brush.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text.
|
||||||
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
|
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
|
||||||
self.alignment = alignment;
|
self.alignment = alignment;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the font size of the text.
|
||||||
#[doc(alias = "font_size")]
|
#[doc(alias = "font_size")]
|
||||||
pub fn text_size(mut self, text_size: f32) -> Self {
|
pub fn text_size(mut self, text_size: f32) -> Self {
|
||||||
self.text_size = text_size;
|
self.text_size = text_size;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set how the text is broken when the content is too wide for its container.
|
||||||
pub fn line_break_mode(mut self, line_break_mode: LineBreaking) -> Self {
|
pub fn line_break_mode(mut self, line_break_mode: LineBreaking) -> Self {
|
||||||
self.line_break_mode = line_break_mode;
|
self.line_break_mode = line_break_mode;
|
||||||
self
|
self
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright 2024 the Xilem Authors
|
// Copyright 2024 the Xilem Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#![expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::{Color, MessageResult, Pod, TextAlignment, ViewCtx, ViewId};
|
||||||
|
|
||||||
type Callback<State, Action> = Box<dyn Fn(&mut State, String) -> Action + Send + Sync + 'static>;
|
type Callback<State, Action> = Box<dyn Fn(&mut State, String) -> Action + Send + Sync + 'static>;
|
||||||
|
|
||||||
|
/// A view which displays editable text.
|
||||||
pub fn textbox<F, State, Action>(contents: String, on_changed: F) -> Textbox<State, Action>
|
pub fn textbox<F, State, Action>(contents: String, on_changed: F) -> Textbox<State, Action>
|
||||||
where
|
where
|
||||||
F: Fn(&mut State, String) -> Action + Send + Sync + 'static,
|
F: Fn(&mut State, String) -> Action + Send + Sync + 'static,
|
||||||
|
@ -28,6 +29,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The [`View`] created by [`textbox`].
|
||||||
#[must_use = "View values do nothing unless provided to Xilem."]
|
#[must_use = "View values do nothing unless provided to Xilem."]
|
||||||
pub struct Textbox<State, Action> {
|
pub struct Textbox<State, Action> {
|
||||||
contents: String,
|
contents: String,
|
||||||
|
@ -39,17 +41,20 @@ pub struct Textbox<State, Action> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action> Textbox<State, Action> {
|
impl<State, Action> Textbox<State, Action> {
|
||||||
|
/// Set the brush used to paint the text.
|
||||||
#[doc(alias = "color")]
|
#[doc(alias = "color")]
|
||||||
pub fn brush(mut self, color: impl Into<Brush>) -> Self {
|
pub fn brush(mut self, color: impl Into<Brush>) -> Self {
|
||||||
self.text_brush = color.into();
|
self.text_brush = color.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text.
|
||||||
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
|
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
|
||||||
self.alignment = alignment;
|
self.alignment = alignment;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a callback that will be run when the user presses the `Enter` key to submit their input.
|
||||||
pub fn on_enter<F>(mut self, on_enter: F) -> Self
|
pub fn on_enter<F>(mut self, on_enter: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(&mut State, String) -> Action + Send + Sync + 'static,
|
F: Fn(&mut State, String) -> Action + Send + Sync + 'static,
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub fn variable_label(text: impl Into<ArcStr>) -> VariableLabel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The [`View`] created by [`variable_label`].
|
||||||
#[must_use = "View values do nothing unless provided to Xilem."]
|
#[must_use = "View values do nothing unless provided to Xilem."]
|
||||||
pub struct VariableLabel {
|
pub struct VariableLabel {
|
||||||
label: Label,
|
label: Label,
|
||||||
|
@ -63,17 +64,20 @@ impl VariableLabel {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the brush used to paint the text.
|
||||||
#[doc(alias = "color")]
|
#[doc(alias = "color")]
|
||||||
pub fn brush(mut self, brush: impl Into<Brush>) -> Self {
|
pub fn brush(mut self, brush: impl Into<Brush>) -> Self {
|
||||||
self.label = self.label.brush(brush);
|
self.label = self.label.brush(brush);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text.
|
||||||
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
|
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
|
||||||
self.label = self.label.alignment(alignment);
|
self.label = self.label.alignment(alignment);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the font size of the text.
|
||||||
#[doc(alias = "font_size")]
|
#[doc(alias = "font_size")]
|
||||||
pub fn text_size(mut self, text_size: f32) -> Self {
|
pub fn text_size(mut self, text_size: f32) -> Self {
|
||||||
self.label = self.label.text_size(text_size);
|
self.label = self.label.text_size(text_size);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright 2024 the Xilem Authors
|
// Copyright 2024 the Xilem Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#![expect(missing_docs, reason = "TODO - Document these items")]
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// Copyright 2024 the Xilem Authors
|
// Copyright 2024 the Xilem Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use masonry::core::{FromDynWidget, Widget, WidgetMut};
|
use masonry::core::{FromDynWidget, Widget, WidgetMut};
|
||||||
|
|
|
@ -21,9 +21,9 @@ pub trait PhantomElementCtx: ViewPathTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`View`] which can be one of nine inner view types.
|
/// A [`View`] which can be one of nine inner view types.
|
||||||
#[allow(missing_docs)] // On variants
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "View values do nothing unless provided to Xilem."]
|
#[must_use = "View values do nothing unless provided to Xilem."]
|
||||||
|
#[expect(missing_docs, reason = "No need to document all variants")]
|
||||||
pub enum OneOf<A = (), B = (), C = (), D = (), E = (), F = (), G = (), H = (), I = ()> {
|
pub enum OneOf<A = (), B = (), C = (), D = (), E = (), F = (), G = (), H = (), I = ()> {
|
||||||
A(A),
|
A(A),
|
||||||
B(B),
|
B(B),
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
#![expect(clippy::cast_possible_truncation, reason = "Deferred: Noisy")]
|
#![expect(clippy::cast_possible_truncation, reason = "Deferred: Noisy")]
|
||||||
#![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")]
|
#![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")]
|
||||||
#![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")]
|
#![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")]
|
||||||
// expect doesn't work here: https://github.com/rust-lang/rust/pull/130025
|
#![expect(missing_docs, reason = "We have many as-yet undocumented items")]
|
||||||
#![allow(missing_docs, reason = "We have many as-yet undocumented items")]
|
|
||||||
#![expect(unreachable_pub, reason = "Potentially controversial code style")]
|
#![expect(unreachable_pub, reason = "Potentially controversial code style")]
|
||||||
#![expect(
|
#![expect(
|
||||||
unnameable_types,
|
unnameable_types,
|
||||||
|
|
Loading…
Reference in New Issue