Skip to main content

xilem/
widget_view.rs

1// Copyright 2025 the Xilem Authors
2// SPDX-License-Identifier: Apache-2.0
3
4use masonry::kurbo::Affine;
5
6use masonry::core::{FromDynWidget, HasProperty, Property, Widget};
7
8use crate::core::{View, ViewSequence};
9use crate::view::{Prop, Transformed, transformed};
10use crate::{AnyWidgetView, Pod, ViewCtx};
11
12#[expect(missing_docs, reason = "TODO - Document these items")]
13pub trait WidgetView<State, Action = ()>:
14    View<State, Action, ViewCtx, Element = Pod<Self::Widget>> + Send + Sync
15{
16    type Widget: Widget + FromDynWidget + ?Sized;
17
18    /// Returns a boxed type erased [`AnyWidgetView`]
19    ///
20    /// # Examples
21    /// ```
22    /// use xilem::{view::label, WidgetView};
23    ///
24    /// # fn view<State: 'static>() -> impl WidgetView<State> + use<State> {
25    /// label("a label").boxed()
26    /// # }
27    ///
28    /// ```
29    fn boxed(self) -> Box<AnyWidgetView<State, Action>>
30    where
31        State: 'static,
32        Action: 'static,
33        Self: Sized,
34    {
35        Box::new(self)
36    }
37
38    /// This widget with a 2d transform applied.
39    ///
40    /// See [`transformed`] for similar functionality with a builder-API using this.
41    /// The return type is the same as for `transformed`, and so also has these
42    /// builder methods.
43    fn transform(self, by: Affine) -> Transformed<Self, State, Action>
44    where
45        Self: Sized,
46    {
47        transformed(self).transform(by)
48    }
49
50    /// Set a [`Property`] on this view, when the underlying widget [supports](HasProperty) it.
51    ///
52    /// This overrides previous set properties of the same type.
53    ///
54    /// It can be used to create syntax-sugar extension traits with more documentation, as seen in [`Style`](crate::style::Style).
55    ///
56    /// # Examples
57    /// ```
58    /// use xilem::{masonry::properties::CornerRadius, view::{text_button, label}, WidgetView};
59    ///
60    /// # fn view<State: 'static>() -> impl WidgetView<State> + use<State> {
61    /// text_button("click me", |_| {})
62    ///     .prop(CornerRadius { radius: 20.0 })
63    ///     .prop(CornerRadius { radius: 5.0 })
64    /// // The corner radius of this button will be 5.0
65    /// # }
66    ///
67    /// ```
68    fn prop<P>(self, property: P) -> Prop<P, Self, State, Action>
69    where
70        State: 'static,
71        Action: 'static,
72        Self: Sized,
73        Self::Widget: HasProperty<P>,
74        P: Property + PartialEq + Clone,
75    {
76        Prop {
77            property,
78            child: self,
79            phantom: std::marker::PhantomData,
80        }
81    }
82}
83
84impl<V, State, Action, W> WidgetView<State, Action> for V
85where
86    V: View<State, Action, ViewCtx, Element = Pod<W>> + Send + Sync,
87    W: Widget + FromDynWidget + ?Sized,
88{
89    type Widget = W;
90}
91
92/// An ordered sequence of widget views, it's used for `0..N` views.
93/// See [`ViewSequence`] for more technical details.
94///
95/// # Examples
96///
97/// ```
98/// use xilem::{view::prose, WidgetViewSequence};
99///
100/// fn prose_sequence<State: 'static>(
101///     texts: impl Iterator<Item = &'static str>,
102/// ) -> impl WidgetViewSequence<State> {
103///     texts.map(prose).collect::<Vec<_>>()
104/// }
105/// ```
106pub trait WidgetViewSequence<State, Action = ()>:
107    ViewSequence<State, Action, ViewCtx, Pod<dyn Widget>>
108{
109}
110
111impl<Seq, State, Action> WidgetViewSequence<State, Action> for Seq where
112    Seq: ViewSequence<State, Action, ViewCtx, Pod<dyn Widget>>
113{
114}