Document more items (#899)

Make missing_docs annotations more granular.
This commit is contained in:
Olivier FAURE 2025-03-21 15:50:16 +01:00 committed by GitHub
parent ab341367b0
commit 125dab7949
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 269 additions and 147 deletions

View File

@ -1,8 +1,7 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
// We use allow because expect(missing_docs) is noisy with rust-analyzer.
#![allow(missing_docs, reason = "We have many as-yet undocumented items")]
#![expect(missing_docs, reason = "TODO - Document these items")]
use std::num::NonZeroUsize;
use std::sync::Arc;

View File

@ -10,12 +10,9 @@ mod event;
mod object_fit;
mod properties;
mod text;
#[allow(missing_docs, reason = "TODO")]
mod widget;
mod widget_arena;
#[allow(missing_docs, reason = "TODO")]
mod widget_mut;
#[allow(missing_docs, reason = "TODO")]
mod widget_pod;
mod widget_ref;
mod widget_state;

View File

@ -45,6 +45,7 @@ use crate::kurbo::{Point, Size};
pub struct WidgetId(pub(crate) NonZeroU64);
impl WidgetId {
/// A serialized representation of the `WidgetId` for debugging purposes.
pub fn trace(self) -> DisplayValue<Self> {
tracing::field::display(self)
}
@ -242,6 +243,7 @@ pub trait Widget: AsAny + AsDynWidget {
bc: &BoxConstraints,
) -> Size;
/// Runs after the widget's final transform has been computed.
fn compose(&mut self, ctx: &mut ComposeCtx) {}
/// Paint the widget appearance.
@ -495,6 +497,7 @@ impl WidgetId {
}
}
/// Returns the integer value of the `WidgetId`.
pub fn to_raw(self) -> u64 {
self.0.into()
}

View File

@ -8,8 +8,6 @@ use anymap3::Entry;
use crate::core::{FromDynWidget, MutateCtx, Widget};
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`].
///
/// 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.
#[non_exhaustive]
pub struct WidgetMut<'a, W: Widget + ?Sized> {
pub ctx: MutateCtx<'a>,
/// The widget we're mutating.
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> {
@ -48,8 +48,8 @@ impl<W: Widget + ?Sized> WidgetMut<'_, W> {
pub fn reborrow_mut(&mut self) -> WidgetMut<'_, W> {
let widget = &mut self.widget;
WidgetMut {
ctx: self.ctx.reborrow_mut(),
widget,
ctx: self.ctx.reborrow_mut(),
}
}
@ -118,8 +118,8 @@ impl<W: Widget + ?Sized> WidgetMut<'_, W> {
let w1_name = self.widget.type_name();
match W2::from_dyn_mut(self.widget.as_mut_dyn()) {
Some(widget) => WidgetMut {
ctx: self.ctx.reborrow_mut(),
widget,
ctx: self.ctx.reborrow_mut(),
},
None => {
panic!(

View File

@ -55,6 +55,7 @@ impl<W: Widget + ?Sized> WidgetPod<W> {
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 {
Self {
id,
@ -67,6 +68,7 @@ impl<W: Widget + ?Sized> WidgetPod<W> {
}
// 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 {
Self {
id,

View File

@ -1,9 +1,9 @@
// Copyright 2019 the Xilem Authors and the Druid Authors
// 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::peniko::Color;

View File

@ -86,7 +86,9 @@ impl<T: Any> AsAny for T {
// --- MARK: PAINT HELPERS ---
#[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 {
u: f64,
v: f64,
@ -96,7 +98,7 @@ pub struct UnitPoint {
single_use_lifetimes,
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>(
scene: &mut Scene,
path: &impl Shape,
@ -112,8 +114,6 @@ pub fn stroke<'b>(
scene.stroke(&style, Affine::IDENTITY, brush, None, path);
}
#[allow(unused)]
#[allow(missing_docs)]
impl UnitPoint {
/// `(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(
scene: &mut Scene,
path: &impl Shape,
@ -164,7 +164,7 @@ pub fn fill_lin_gradient(
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) {
scene.fill(Fill::NonZero, Affine::IDENTITY, color, None, path);
}

View File

@ -79,7 +79,7 @@ impl Button {
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> {
this.ctx.get_mut(&mut this.widget.label)
}

View File

@ -46,7 +46,7 @@ impl Checkbox {
// --- MARK: WIDGETMUT ---
impl Checkbox {
#[expect(missing_docs, reason = "TODO")]
/// Check or uncheck the box.
pub fn set_checked(this: &mut WidgetMut<'_, Self>, checked: bool) {
this.widget.checked = checked;
// Checked state impacts appearance and accessibility node
@ -60,7 +60,7 @@ impl Checkbox {
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> {
this.ctx.get_mut(&mut this.widget.label)
}

View File

@ -294,12 +294,12 @@ impl Flex {
self
}
#[expect(missing_docs, reason = "TODO")]
/// Returns the number of children (widgets and spacers) this flex container has.
pub fn len(&self) -> usize {
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 {
self.len() == 0
}
@ -390,7 +390,11 @@ impl Flex {
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) {
let child = Child::Fixed {
widget: WidgetPod::new_with_id(child, id).erased(),
@ -453,16 +457,20 @@ impl Flex {
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) {
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(
this: &mut WidgetMut<'_, Self>,
idx: usize,
@ -476,7 +484,11 @@ impl Flex {
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(
this: &mut WidgetMut<'_, Self>,
idx: usize,
@ -486,7 +498,11 @@ impl Flex {
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(
this: &mut WidgetMut<'_, Self>,
idx: usize,
@ -499,22 +515,30 @@ impl Flex {
}
// 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
/// 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) {
let key = axis_default_spacer(this.widget.direction);
Self::insert_spacer(this, idx, key);
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
/// generally prefer to use [`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) {
if len < 0.0 {
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.
///
/// # 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) {
let flex = if flex >= 0.0 {
flex
@ -539,7 +567,13 @@ impl Flex {
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) {
let child = this.widget.children.remove(idx);
if let Child::Fixed { widget, .. } | Child::Flex { widget, .. } = child {
@ -548,7 +582,13 @@ impl Flex {
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>(
this: &'t mut WidgetMut<'_, Self>,
idx: usize,
@ -623,7 +663,7 @@ impl Flex {
this.ctx.children_changed();
}
#[expect(missing_docs, reason = "TODO")]
/// Remove all children from the container.
pub fn clear(this: &mut WidgetMut<'_, Self>) {
if !this.widget.children.is_empty() {
this.ctx.request_layout();

View File

@ -32,17 +32,21 @@ struct Child {
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
#[expect(missing_docs, reason = "TODO")]
/// Parameters required when adding an item to a [`Grid`] container.
pub struct GridParams {
/// Index of the column this item is starting from.
pub x: i32,
/// Index of the row this item is starting from.
pub y: i32,
/// Number of columns this item spans.
pub width: i32,
/// Number of rows this item spans.
pub height: i32,
}
// --- MARK: 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 {
Self {
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 {
self.grid_spacing = spacing;
self
}
/// Builder-style variant of [`Grid::add_child`].
///
/// Convenient for assembling a group of widgets in a single expression.
/// Builder-style method to add a child widget.
pub fn with_child(self, child: impl Widget, params: GridParams) -> Self {
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 {
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 {
let child = Child {
widget,
@ -86,13 +88,6 @@ impl Grid {
// --- MARK: 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) {
self.x = params.x;
self.y = params.y;
@ -113,8 +108,13 @@ fn new_grid_child(params: GridParams, widget: WidgetPod<dyn Widget>) -> Child {
// --- MARK: 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 {
// TODO - Use u32 params instead?
if x < 0 {
debug_panic!("Grid x value should be a non-negative number; got {}", x);
x = 0;
@ -150,15 +150,15 @@ impl GridParams {
impl Grid {
/// Add a child widget.
///
/// See also [`with_child`].
///
/// [`with_child`]: Grid::with_child
/// See also [`with_child`](Grid::with_child).
pub fn add_child(this: &mut WidgetMut<'_, Self>, child: impl Widget, params: GridParams) {
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(
this: &mut WidgetMut<'_, Self>,
child: impl Widget,
@ -166,11 +166,13 @@ impl Grid {
params: GridParams,
) {
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.
pub fn insert_child_pod(
/// Add a child widget already wrapped in a [`WidgetPod`].
///
/// See also [`with_child_pod`](Grid::with_child_pod).
pub fn add_child_pod(
this: &mut WidgetMut<'_, Self>,
widget: WidgetPod<dyn Widget>,
params: GridParams,
@ -181,7 +183,14 @@ impl Grid {
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(
this: &mut WidgetMut<'_, Self>,
idx: usize,
@ -191,7 +200,14 @@ impl Grid {
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(
this: &mut WidgetMut<'_, Self>,
idx: usize,
@ -204,31 +220,37 @@ impl Grid {
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) {
this.widget.grid_spacing = spacing;
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) {
this.widget.grid_width = width;
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) {
this.widget.grid_height = height;
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>(
this: &'t mut WidgetMut<'_, Self>,
idx: usize,
) -> Option<WidgetMut<'t, dyn Widget>> {
let child = this.widget.children[idx].widget_mut()?;
Some(this.ctx.get_mut(child))
) -> WidgetMut<'t, dyn Widget> {
let child = &mut this.widget.children[idx].widget;
this.ctx.get_mut(child)
}
/// Updates the grid parameters for the child at `idx`,
@ -246,7 +268,11 @@ impl Grid {
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) {
let child = this.widget.children.remove(idx);
this.ctx.remove_child(child.widget);
@ -281,8 +307,8 @@ impl Widget for Grid {
}
fn register_children(&mut self, ctx: &mut crate::core::RegisterCtx) {
for child in self.children.iter_mut().filter_map(|x| x.widget_mut()) {
ctx.register_child(child);
for child in self.children.iter_mut() {
ctx.register_child(&mut child.widget);
}
}
@ -343,8 +369,7 @@ impl Widget for Grid {
fn children_ids(&self) -> SmallVec<[WidgetId; 16]> {
self.children
.iter()
.filter_map(|child| child.widget())
.map(|widget_pod| widget_pod.id())
.map(|child| child.widget.id())
.collect()
}

View File

@ -18,6 +18,8 @@ use crate::theme;
use crate::util::{UnitPoint, fill_lin_gradient, stroke};
use crate::widgets::{Label, LineBreaking};
// TODO - NaN probably shouldn't be a meaningful value in our API.
/// A 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 {
/// Create a new `ProgressBar`.
///
/// `progress` is a number between 0 and 1 inclusive. If it is `NaN`, then an
/// indefinite progress bar will be shown.
/// Otherwise, the input will be clamped to [0, 1].
pub fn new(mut progress: Option<f64>) -> Self {
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 new(progress: Option<f64>) -> Self {
let progress = clamp_progress(progress);
let label = WidgetPod::new(
Label::new(Self::value(progress)).with_line_break_mode(LineBreaking::Overflow),
);
@ -63,9 +65,13 @@ impl ProgressBar {
// --- MARK: WIDGETMUT ---
impl ProgressBar {
#[expect(missing_docs, reason = "TODO")]
pub fn set_progress(this: &mut WidgetMut<'_, Self>, mut progress: Option<f64>) {
clamp_progress(&mut progress);
/// Set the progress displayed by the bar.
///
/// 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;
if progress_changed {
this.widget.progress = progress;
@ -80,13 +86,12 @@ impl ProgressBar {
/// Helper to ensure progress is either a number between [0, 1] inclusive, or `None`.
///
/// NaNs are converted to `None`.
fn clamp_progress(progress: &mut Option<f64>) {
if let Some(value) = progress {
if value.is_nan() {
*progress = None;
} else {
*progress = Some(value.clamp(0., 1.));
}
fn clamp_progress(progress: Option<f64>) -> Option<f64> {
let progress = progress?;
if progress.is_nan() {
None
} else {
Some(progress.clamp(0., 1.))
}
}

View File

@ -14,15 +14,15 @@ use crate::core::{
};
use crate::kurbo::Size;
// TODO: This is a hack to provide an accessibility node with a Window type.
// This should eventually be removed.
#[expect(missing_docs, reason = "TODO")]
// TODO: This should eventually be removed once accesskit does that for us.
// See https://github.com/AccessKit/accesskit/issues/531
/// A widget wrapper that reports a [`Role::Window`] to the accessibility API.
pub struct RootWidget<W: ?Sized> {
pub(crate) pod: WidgetPod<W>,
}
impl<W: Widget> RootWidget<W> {
#[expect(missing_docs, reason = "TODO")]
/// Create a new root widget.
pub fn new(widget: W) -> Self {
Self {
pod: WidgetPod::new(widget),
@ -31,14 +31,14 @@ impl<W: Widget> 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 {
Self { pod }
}
}
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> {
this.ctx.get_mut(&mut this.widget.pod)
}

View File

@ -327,7 +327,9 @@ impl SizedBox {
// --- MARK: WIDGETMUT ---
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) {
if let Some(child) = this.widget.child.take() {
this.ctx.remove_child(child);
@ -337,7 +339,9 @@ impl SizedBox {
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>) {
if let Some(child) = this.widget.child.take() {
this.ctx.remove_child(child);
@ -422,7 +426,7 @@ impl SizedBox {
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>> {
let child = this.widget.child.as_mut()?;
Some(this.ctx.get_mut(child))

View File

@ -53,7 +53,7 @@ impl<ChildA: Widget, ChildB: Widget> 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 {
Self {
split_axis: Axis::Horizontal,
@ -304,12 +304,12 @@ where
ChildA: 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> {
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> {
this.ctx.get_mut(&mut this.widget.child2)
}

View File

@ -133,12 +133,16 @@ impl VariableLabel {
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 {
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 {
Self {
label,

View File

@ -1,6 +1,8 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
#![expect(missing_docs, reason = "TODO - Document these items")]
use std::sync::Arc;
use masonry::app::{AppDriver, EventLoopProxy, MasonryState, MasonryUserEvent};

View File

@ -128,7 +128,6 @@
#![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")]
#![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")]
// 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")]
use std::collections::HashMap;
@ -178,11 +177,13 @@ pub struct Xilem<State, Logic> {
fonts: Vec<Vec<u8>>,
}
#[expect(missing_docs, reason = "TODO - Document these items")]
impl<State, Logic, View> Xilem<State, Logic>
where
Logic: FnMut(&mut State) -> View,
View: WidgetView<State>,
{
/// Initialize the builder state for your app.
pub fn new(state: State, logic: Logic) -> Self {
let runtime = tokio::runtime::Runtime::new().unwrap();
Self {
@ -287,6 +288,7 @@ where
/// and so might not actually own the underlying widget value.
/// When creating widgets in Xilem, layered views all want access to the - using
/// `WidgetPod` for this purpose would require fallible unwrapping.
#[expect(missing_docs, reason = "TODO - Document these items")]
pub struct Pod<W: Widget + FromDynWidget + ?Sized> {
pub widget: Box<W>,
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 = ()>:
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>>;
/// A context type passed to various methods of Xilem traits.
pub struct ViewCtx {
/// 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 {
pub fn new_pod<W: Widget + FromDynWidget>(&mut self, widget: W) -> Pod<W> {
Pod::new(widget)

View File

@ -84,20 +84,23 @@ pub struct 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 {
self.axis = axis;
self
}
/// Set the childrens' [`CrossAxisAlignment`].
pub fn cross_axis_alignment(mut self, axis: CrossAxisAlignment) -> Self {
self.cross_axis_alignment = axis;
self
}
/// Set the childrens' [`MainAxisAlignment`].
pub fn main_axis_alignment(mut self, axis: MainAxisAlignment) -> Self {
self.main_axis_alignment = axis;
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 {
self.fill_major_axis = fill_major_axis;
self
@ -214,12 +217,17 @@ where
}
}
/// A child element of a [`Flex`] view.
pub enum FlexElement {
/// Child widget.
Child(Pod<dyn Widget>, FlexParams),
/// Child spacer with fixed size.
FixedSpacer(f64),
/// Child spacer with flex size.
FlexSpacer(f64),
}
/// A mutable reference to a [`FlexElement`], used internally by Xilem traits.
pub struct FlexElementMut<'w> {
parent: WidgetMut<'w, widgets::Flex>,
idx: usize,
@ -549,6 +557,7 @@ where
/// A spacer that can be used within a [`Flex`] [`View`]
#[derive(Copy, Clone, PartialEq)]
#[expect(missing_docs, reason = "TODO - Need to document units used.")]
pub enum FlexSpacer {
Fixed(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`]
pub enum AnyFlexChild<State, Action = ()> {
/// A child widget.
Item(FlexItem<Box<AnyWidgetView<State, Action>>, State, Action>),
/// A spacer.
Spacer(FlexSpacer),
}

View File

@ -76,6 +76,7 @@ pub struct Grid<Seq, State, Action = ()> {
}
impl<Seq, State, Action> Grid<Seq, State, Action> {
/// Set the spacing (both vertical and horizontal) between grid items.
#[track_caller]
pub fn spacing(mut self, spacing: f64) -> Self {
if spacing.is_finite() && spacing >= 0.0 {
@ -104,12 +105,8 @@ where
let mut widget = widgets::Grid::with_dimensions(self.width, self.height);
widget = widget.with_spacing(self.spacing);
let seq_state = self.sequence.seq_build(ctx, &mut elements);
for child in elements.into_inner() {
widget = match child {
GridElement::Child(child, params) => {
widget.with_child_pod(child.erased_widget_pod(), params)
}
}
for element in elements.into_inner() {
widget = widget.with_child_pod(element.child.erased_widget_pod(), element.params);
}
let pod = ctx.new_pod(widget);
(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,
// because there isn't enough information to determine an appropriate spot
// 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>(
@ -203,8 +204,7 @@ impl<W: Widget + FromDynWidget + ?Sized> SuperElement<Pod<W>, ViewCtx> for GridE
f: impl FnOnce(Mut<Pod<W>>) -> R,
) -> (Mut<Self>, R) {
let ret = {
let mut child = widgets::Grid::child_mut(&mut this.parent, this.idx)
.expect("This is supposed to be a widget");
let mut child = widgets::Grid::child_mut(&mut this.parent, this.idx);
let downcast = child.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 {
let ret = f(&mut self.scratch);
for element in self.scratch.drain() {
match element {
GridElement::Child(child, params) => {
widgets::Grid::insert_grid_child_pod(
&mut self.element,
self.idx,
child.erased_widget_pod(),
params,
);
}
};
widgets::Grid::insert_grid_child_pod(
&mut self.element,
self.idx,
element.child.erased_widget_pod(),
element.params,
);
self.idx += 1;
}
ret
}
fn insert(&mut self, element: GridElement) {
match element {
GridElement::Child(child, params) => {
widgets::Grid::insert_grid_child_pod(
&mut self.element,
self.idx,
child.erased_widget_pod(),
params,
);
}
};
widgets::Grid::insert_grid_child_pod(
&mut self.element,
self.idx,
element.child.erased_widget_pod(),
element.params,
);
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 {}
pub enum GridElement {
Child(Pod<dyn Widget>, GridParams),
/// A child widget within a [`Grid`] view.
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> {
parent: WidgetMut<'w, widgets::Grid>,
idx: usize,
}
// Used for manipulating the ViewSequence.
pub struct GridSplice<'w> {
struct GridSplice<'w> {
idx: usize,
element: WidgetMut<'w, widgets::Grid>,
scratch: AppendVec<GridElement>,
@ -375,6 +372,7 @@ pub struct GridItem<V, State, Action> {
phantom: PhantomData<fn() -> (State, Action)>,
}
/// Creates a [`GridItem`] from a view and [`GridParams`].
pub fn grid_item<V, State, Action>(
view: V,
params: impl Into<GridParams>,
@ -405,7 +403,13 @@ where
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
let (pod, state) = self.view.build(ctx);
(GridElement::Child(pod.erased(), self.params), state)
(
GridElement {
child: pod.erased(),
params: self.params,
},
state,
)
}
fn rebuild(
@ -423,8 +427,7 @@ where
self.params,
);
}
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx)
.expect("GridWrapper always has a widget child");
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx);
self.view
.rebuild(&prev.view, view_state, ctx, child.downcast());
}
@ -436,8 +439,7 @@ where
ctx: &mut ViewCtx,
mut element: Mut<Self::Element>,
) {
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx)
.expect("GridWrapper always has a widget child");
let mut child = widgets::Grid::child_mut(&mut element.parent, element.idx);
self.view.teardown(view_state, ctx, child.downcast());
}

View File

@ -21,6 +21,7 @@ where
}
}
/// The [`View`] created by [`portal`].
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Portal<V, State, Action> {
child: V,

View File

@ -6,10 +6,15 @@ use masonry::widgets;
use crate::core::{DynMessage, Mut, ViewMarker};
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 {
ProgressBar { progress }
}
/// The [`View`] created by [`progress_bar`].
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct ProgressBar {
progress: Option<f64>,
}

View File

@ -10,6 +10,7 @@ use vello::peniko::Brush;
use crate::core::{DynMessage, Mut, ViewMarker};
use crate::{Color, MessageResult, Pod, TextAlignment, View, ViewCtx, ViewId};
/// A view which displays selectable text.
pub fn prose(content: impl Into<ArcStr>) -> Prose {
Prose {
content: content.into(),
@ -30,6 +31,7 @@ pub fn inline_prose(content: impl Into<ArcStr>) -> Prose {
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."]
pub struct Prose {
content: ArcStr,
@ -43,22 +45,27 @@ pub struct Prose {
}
impl Prose {
/// Set the brush used to paint the text.
#[doc(alias = "color")]
pub fn brush(mut self, brush: impl Into<Brush>) -> Self {
self.text_brush = brush.into();
self
}
/// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text.
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
self.alignment = alignment;
self
}
/// Set the font size of the text.
#[doc(alias = "font_size")]
pub fn text_size(mut self, text_size: f32) -> Self {
self.text_size = text_size;
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 {
self.line_break_mode = line_break_mode;
self

View File

@ -1,6 +1,8 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
#![expect(missing_docs, reason = "TODO - Document these items")]
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;

View File

@ -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>;
/// A view which displays editable text.
pub fn textbox<F, State, Action>(contents: String, on_changed: F) -> Textbox<State, Action>
where
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."]
pub struct Textbox<State, Action> {
contents: String,
@ -39,17 +41,20 @@ pub struct Textbox<State, Action> {
}
impl<State, Action> Textbox<State, Action> {
/// Set the brush used to paint the text.
#[doc(alias = "color")]
pub fn brush(mut self, color: impl Into<Brush>) -> Self {
self.text_brush = color.into();
self
}
/// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text.
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
self.alignment = alignment;
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
where
F: Fn(&mut State, String) -> Action + Send + Sync + 'static,

View File

@ -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."]
pub struct VariableLabel {
label: Label,
@ -63,17 +64,20 @@ impl VariableLabel {
self
}
/// Set the brush used to paint the text.
#[doc(alias = "color")]
pub fn brush(mut self, brush: impl Into<Brush>) -> Self {
self.label = self.label.brush(brush);
self
}
/// Set the [alignment](https://en.wikipedia.org/wiki/Typographic_alignment) of the text.
pub fn alignment(mut self, alignment: TextAlignment) -> Self {
self.label = self.label.alignment(alignment);
self
}
/// Set the font size of the text.
#[doc(alias = "font_size")]
pub fn text_size(mut self, text_size: f32) -> Self {
self.label = self.label.text_size(text_size);

View File

@ -1,6 +1,8 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
#![expect(missing_docs, reason = "TODO - Document these items")]
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;

View File

@ -1,8 +1,6 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
#![warn(missing_docs)]
use std::marker::PhantomData;
use masonry::core::{FromDynWidget, Widget, WidgetMut};

View File

@ -21,9 +21,9 @@ pub trait PhantomElementCtx: ViewPathTracker {
}
/// A [`View`] which can be one of nine inner view types.
#[allow(missing_docs)] // On variants
#[derive(Debug)]
#[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 = ()> {
A(A),
B(B),

View File

@ -27,8 +27,7 @@
#![expect(clippy::cast_possible_truncation, reason = "Deferred: Noisy")]
#![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")]
#![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")]
// expect doesn't work here: https://github.com/rust-lang/rust/pull/130025
#![allow(missing_docs, reason = "We have many as-yet undocumented items")]
#![expect(missing_docs, reason = "We have many as-yet undocumented items")]
#![expect(unreachable_pub, reason = "Potentially controversial code style")]
#![expect(
unnameable_types,