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(¶graph, 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(¶graph, cx.rect() + state.my_padding.offset());
//! }
//! }
//! ```
mod styles;
mod theme;
pub use styles::*;
pub use theme::*;