1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::any::Any;
use std::collections::hash_map::DefaultHasher;
use std::future::Future;
use std::hash::{Hash, Hasher};

use futures::Stream;

use crate::node::component_node::{Runtime, State};
use crate::node::Node;
use crate::style::builder::StyleBuilder;
use crate::widget::Context as WidgetContext;

/// A re-usable component for defining a fragment of a user interface.
/// Components are the main building block for user interfaces in pixel-widgets.
///
/// The examples in this repository all implement some kind of `Component`,
/// check them out if you just want to read some code.
pub trait Component {
    /// Mutable state associated with this `Component`.
    type State: 'static + Any + Send + Sync;

    /// The message type this `Component` will receive from it's view.
    type Message: 'static;

    /// The message type this `Component` submits to its parent.
    type Output: 'static;

    /// Create a new `State` for the `Component`.
    /// This will be called only once when the `Component` is first created.
    fn mount(&self) -> Self::State;

    /// Generate the view for the `Component`.
    /// This will be called just in time before ui rendering.
    /// When the `Component` is updated,
    ///  the view will be invalidated and the runtime will have to call this function again.
    fn view<'a>(&'a self, state: &'a Self::State) -> Node<'a, Self::Message>;

    /// Update the `Component` state in response to the `message`.
    /// Asynchronous operations can be submitted to the `context`,
    ///  which will result in more `update` calls in the future.
    /// Messages for the parent `Component` or root can also be submitted through the `context`.
    fn update(
        &self,
        _message: Self::Message,
        _state: State<Self::State>,
        _context: Context<Self::Message, Self::Output>,
    ) {
    }

    /// Returns a `StyleBuilder` with styling information scoped to this component.
    /// This method will be called when you call
    /// [`StyleBuilder::component()`](../style/builder/struct.StyleBuilder.html#method.component)
    /// when building your style.
    fn style() -> StyleBuilder {
        StyleBuilder::default()
    }

    /// Converts the component into a `Node`. This is used by the library to
    ///  instantiate the component in a user interface.
    fn into_node<'a>(self) -> Node<'a, Self::Output>
    where
        Self: 'a + Sized,
    {
        Node::from_component(self)
    }

    /// Converts the component into a `Node` and sets a style class to it.
    fn class<'a>(self, class: &'a str) -> Node<'a, Self::Output>
    where
        Self: 'a + Sized,
    {
        let mut node = self.into_node();
        node.set_class(class);
        node
    }

    /// Converts the component into a `Node` and sets a custom key to it.
    fn key<'a, K>(self, key: K) -> Node<'a, Self::Output>
    where
        Self: 'a + Sized,
        K: Hash,
    {
        let mut hasher = DefaultHasher::new();
        key.hash(&mut hasher);
        let mut node = self.into_node();
        node.set_key(hasher.finish());
        node
    }
}

/// Allows for message passing between components
pub struct Context<'a, Message, Output> {
    widget_context: &'a mut WidgetContext<Output>,
    runtime: &'a mut Runtime<Message>,
}

impl<'a, Message, Output> Context<'a, Message, Output> {
    pub(crate) fn new(widget_context: &'a mut WidgetContext<Output>, runtime: &'a mut Runtime<Message>) -> Self {
        Self {
            widget_context,
            runtime,
        }
    }

    /// Push a message to the parent.
    pub fn push(&mut self, message: Output) {
        self.widget_context.push(message);
    }

    /// Push multiple messages to the parent using an iterator.
    pub fn extend<I: IntoIterator<Item = Output>>(&mut self, iter: I) {
        self.widget_context.extend(iter);
    }

    /// Returns the cursor position
    pub fn cursor(&self) -> (f32, f32) {
        self.widget_context.cursor()
    }

    /// Submits a messsage to self in the future.
    pub fn wait<F: 'static + Future<Output = Message> + Send + Sync + Unpin>(&mut self, fut: F) {
        self.runtime.wait(fut);
    }

    /// Submits a stream of messages to self in the future.
    pub fn stream<S: 'static + Stream<Item = Message> + Send + Sync + Unpin>(&mut self, stream: S) {
        self.runtime.stream(stream);
    }
}