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}