pixel_widgets/component.rs
1use std::any::Any;
2use std::collections::hash_map::DefaultHasher;
3use std::future::Future;
4use std::hash::{Hash, Hasher};
5
6use futures::Stream;
7
8use crate::node::component_node::{Runtime, State};
9use crate::node::Node;
10use crate::style::builder::StyleBuilder;
11use crate::widget::Context as WidgetContext;
12
13/// A re-usable component for defining a fragment of a user interface.
14/// Components are the main building block for user interfaces in pixel-widgets.
15///
16/// The examples in this repository all implement some kind of `Component`,
17/// check them out if you just want to read some code.
18pub trait Component {
19 /// Mutable state associated with this `Component`.
20 type State: 'static + Any + Send + Sync;
21
22 /// The message type this `Component` will receive from it's view.
23 type Message: 'static;
24
25 /// The message type this `Component` submits to its parent.
26 type Output: 'static;
27
28 /// Create a new `State` for the `Component`.
29 /// This will be called only once when the `Component` is first created.
30 fn mount(&self) -> Self::State;
31
32 /// Generate the view for the `Component`.
33 /// This will be called just in time before ui rendering.
34 /// When the `Component` is updated,
35 /// the view will be invalidated and the runtime will have to call this function again.
36 fn view<'a>(&'a self, state: &'a Self::State) -> Node<'a, Self::Message>;
37
38 /// Update the `Component` state in response to the `message`.
39 /// Asynchronous operations can be submitted to the `context`,
40 /// which will result in more `update` calls in the future.
41 /// Messages for the parent `Component` or root can also be submitted through the `context`.
42 fn update(
43 &self,
44 _message: Self::Message,
45 _state: State<Self::State>,
46 _context: Context<Self::Message, Self::Output>,
47 ) {
48 }
49
50 /// Returns a `StyleBuilder` with styling information scoped to this component.
51 /// This method will be called when you call
52 /// [`StyleBuilder::component()`](../style/builder/struct.StyleBuilder.html#method.component)
53 /// when building your style.
54 fn style() -> StyleBuilder {
55 StyleBuilder::default()
56 }
57
58 /// Converts the component into a `Node`. This is used by the library to
59 /// instantiate the component in a user interface.
60 fn into_node<'a>(self) -> Node<'a, Self::Output>
61 where
62 Self: 'a + Sized,
63 {
64 Node::from_component(self)
65 }
66
67 /// Converts the component into a `Node` and sets a style class to it.
68 fn class<'a>(self, class: &'a str) -> Node<'a, Self::Output>
69 where
70 Self: 'a + Sized,
71 {
72 let mut node = self.into_node();
73 node.set_class(class);
74 node
75 }
76
77 /// Converts the component into a `Node` and sets a custom key to it.
78 fn key<'a, K>(self, key: K) -> Node<'a, Self::Output>
79 where
80 Self: 'a + Sized,
81 K: Hash,
82 {
83 let mut hasher = DefaultHasher::new();
84 key.hash(&mut hasher);
85 let mut node = self.into_node();
86 node.set_key(hasher.finish());
87 node
88 }
89}
90
91/// Allows for message passing between components
92pub struct Context<'a, Message, Output> {
93 widget_context: &'a mut WidgetContext<Output>,
94 runtime: &'a mut Runtime<Message>,
95}
96
97impl<'a, Message, Output> Context<'a, Message, Output> {
98 pub(crate) fn new(widget_context: &'a mut WidgetContext<Output>, runtime: &'a mut Runtime<Message>) -> Self {
99 Self {
100 widget_context,
101 runtime,
102 }
103 }
104
105 /// Push a message to the parent.
106 pub fn push(&mut self, message: Output) {
107 self.widget_context.push(message);
108 }
109
110 /// Push multiple messages to the parent using an iterator.
111 pub fn extend<I: IntoIterator<Item = Output>>(&mut self, iter: I) {
112 self.widget_context.extend(iter);
113 }
114
115 /// Returns the cursor position
116 pub fn cursor(&self) -> (f32, f32) {
117 self.widget_context.cursor()
118 }
119
120 /// Submits a messsage to self in the future.
121 pub fn wait<F: 'static + Future<Output = Message> + Send + Sync + Unpin>(&mut self, fut: F) {
122 self.runtime.wait(fut);
123 }
124
125 /// Submits a stream of messages to self in the future.
126 pub fn stream<S: 'static + Stream<Item = Message> + Send + Sync + Unpin>(&mut self, stream: S) {
127 self.runtime.stream(stream);
128 }
129}