ori_core/style/
mod.rs

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! Styling and theming.
//!
//! # Example
//! The below example demonstrates how a view with styling can be implemented.
//!
//! ```rust
//! # use ori_core::{
//! #    style::{Style, Styles, Stylable, StyleBuilder, Theme},
//! #    views::ButtonStyle,
//! #    canvas::Color,
//! #    layout::{Space, Size, Padding},
//! #    view::View,
//! #    event::Event,
//! #    context::{BuildCx, RebuildCx, EventCx, LayoutCx, DrawCx},
//! #    rebuild::Rebuild,
//! #    text::{Paragraph, TextAlign, TextWrap},
//! # };
//! #[derive(Clone, Rebuild)]
//! struct MyStyle {
//!     // we use `rebuild` to draw the view when `my_color` changes
//!     #[rebuild(draw)]
//!     my_color: Color,
//!
//!     // we use `rebuild` to layout the view when `my_padding` changes
//!     #[rebuild(layout)]
//!     my_padding: Padding,
//! }
//!
//! // `Style` must be implemented for use in `Styles`
//! impl Style for MyStyle {
//!     fn default_style() -> StyleBuilder<Self> {
//!         StyleBuilder::new(|theme: &Theme, button: &ButtonStyle| {
//!             MyStyle {
//!                 my_color: theme.accent,
//!                 my_padding: button.padding,
//!             }
//!         })
//!     }
//! }
//!
//! #[derive(Rebuild)]
//! struct MyView {
//!     // we use this field to override the color of the style
//!     //
//!     // note that this field doesn't have the `rebuild` attribute, this is
//!     // because `MyStyle` already has a `rebuild` attribute for `my_color`
//!     // and we only care about when the style changes
//!     my_color: Option<Color>,
//!
//!     // this field is not related to the style
//!     #[rebuild(layout)]
//!     non_styled_field: String,
//! }
//!
//! impl Stylable for MyView {
//!     type Style = MyStyle;
//!
//!     fn style(&self, base: &Self::Style) -> Self::Style {
//!         MyStyle {
//!             my_color: self.my_color.unwrap_or(base.my_color),
//!             
//!             // generally it's preferred to be able to override every field of the style
//!             // even though it's not required, the current implementation of `MyView` doesn't
//!             // allow overriding `my_padding`
//!             ..base.clone()
//!         }
//!     }
//! }
//!
//! impl<T> View<T> for MyView {
//!     // we need to store the style in the `State` of our `View` implementation
//!     type State = MyStyle;
//!
//!     fn build(&mut self, cx: &mut BuildCx, _data: &mut T) -> Self::State {
//!         // we build the `style` in the `build` method
//!         self.style(cx.style())
//!     }
//!
//!     fn rebuild(
//!         &mut self,
//!         state: &mut Self::State,
//!         cx: &mut RebuildCx,
//!         _data: &mut T,
//!         _old: &Self,
//!     ) {
//!         // we rebuild the `style` in the `rebuild` method
//!         self.rebuild_style(cx, state);
//!     }
//!
//!     fn event(
//!         &mut self,
//!         _state: &mut Self::State,
//!         _cx: &mut EventCx,
//!         _data: &mut T,
//!         _event: &Event,
//!     ) -> bool {
//!         // we don't care about events in this example
//!         false
//!     }
//!     
//!     fn layout(
//!         &mut self,
//!         state: &mut Self::State,
//!         cx: &mut LayoutCx,
//!         _data: &mut T,
//!         space: Space,
//!     ) -> Size {
//!         // we create a paragraph with the non-styled field
//!         let paragraph = Paragraph::new(1.0, TextAlign::Start, TextWrap::Word)
//!             .with_text(&self.non_styled_field, Default::default());
//!
//!         // we calculate the size that the padding will take
//!         let pad_size = state.my_padding.size();
//!
//!         // we calculate the maximum width that the paragraph can take
//!         let max_width = space.max.width - pad_size.width;
//!
//!         // we measure the paragraph
//!         let size = cx.measure_paragraph(&paragraph, max_width);
//!
//!         // we constrain the size of the view to fit the space given
//!         space.fit(size + pad_size)
//!     }
//!     
//!     fn draw(
//!         &mut self,
//!         state: &mut Self::State,
//!         cx: &mut DrawCx,
//!         _data: &mut T,
//!     ) {
//!         // we create a paragraph with the non-styled field
//!         let paragraph = Paragraph::new(1.0, TextAlign::Start, TextWrap::Word)
//!             .with_text(&self.non_styled_field, Default::default());
//!
//!         // we draw the paragraph offset by the padding
//!         cx.paragraph(&paragraph, cx.rect() + state.my_padding.offset());
//!     }
//! }
//! ```

mod styles;
mod theme;

pub use styles::*;
pub use theme::*;