zng/style.rs
1//! Style mixin and other types.
2//!
3//! A [`Style!`](struct@Style) is an special widget that represents a set of properties that are dynamically applied to
4//! another styleable widget. Styleable widgets inherit from [`StyleMix<P>`](struct@StyleMix) and provide a contextual
5//! `style_fn` property that sets the widget style.
6//!
7//! Styles extend the contextual style by default, only replacing the intersection of properties.
8//! The special [`replace`](struct@Style#method.replace) property can be set on a style to fully replace the contextual style.
9//!
10//! The example below demonstrates multiple contexts setting style for buttons.
11//!
12//! ```
13//! use zng::prelude::*;
14//! # let _app = APP.defaults();
15//!
16//! # let _ =
17//! Stack! {
18//! direction = StackDirection::top_to_bottom();
19//! spacing = 5;
20//!
21//! zng::button::style_fn = Style! {
22//! // override the default background_color for all buttons in the Stack.
23//! // note that this does not override the hovered/pressed background.
24//! widget::background_color = colors::BLUE;
25//! };
26//!
27//! children = ui_vec![
28//! // these buttons have the default style with blue background.
29//! Button! {
30//! child = Text!("Default+BLUE");
31//! },
32//! Button! {
33//! child = Text!("Default+BLUE");
34//! },
35//! Stack! {
36//! direction = StackDirection::top_to_bottom();
37//! spacing = 5;
38//!
39//! zng::button::style_fn = Style! {
40//! // override the default border for all buttons in the Stack.
41//! widget::border = 2, colors::GREEN;
42//! };
43//!
44//! children = ui_vec![
45//! // these buttons have the default style, with blue background and green border.
46//! Button! {
47//! child = Text!("Default+BLUE+GREEN");
48//! },
49//! Button! {
50//! child = Text!("Default+BLUE+GREEN");
51//! },
52//! Stack! {
53//! direction = StackDirection::top_to_bottom();
54//! spacing = 5;
55//!
56//! zng::button::style_fn = Style! {
57//! // override the context style background_color in the Stack.
58//! widget::background_color = colors::RED;
59//! };
60//!
61//! children = ui_vec![
62//! // these buttons have the default style, with green border and red background.
63//! Button! {
64//! child = Text!("Default+GREEN+RED");
65//! },
66//! Button! {
67//! child = Text!("Default+GREEN+RED");
68//! },
69//! // this button ignores the contextual style by setting the `style_fn` to a style
70//! // that is `replace=true`.
71//! Button! {
72//! child = Text!("Default");
73//! style_fn = zng::button::DefaultStyle!();
74//! },
75//! ];
76//! },
77//! ];
78//! },
79//! Stack! {
80//! direction = StackDirection::top_to_bottom();
81//! spacing = 5;
82//!
83//! zng::button::style_fn = Style! {
84//! // replace the default style with this one.
85//! replace = true;
86//! widget::background_color = colors::RED;
87//! };
88//!
89//! // these buttons only have the red background.
90//! children = ui_vec![
91//! Button! {
92//! child = Text!("RED");
93//! },
94//! Button! {
95//! child = Text!("RED");
96//! },
97//! ];
98//! }
99//! ];
100//! }
101//! # ;
102//! ```
103//!
104//! # Named Styles
105//!
106//! Some widgets provide alternate styles that are also contextual. The example below demonstrates a button using
107//! a named style being affected by properties set for that particular style name in context.
108//!
109//! ```
110//! use zng::prelude::*;
111//! # let _app = APP.defaults();
112//!
113//! # let _ =
114//! Stack! {
115//! direction = StackDirection::top_to_bottom();
116//! spacing = 5;
117//!
118//! zng::button::light_style_fn = Style! {
119//! // override the background color of only buttons in the Stack using the `LightStyle!`.
120//! widget::background_color = colors::BLUE;
121//! };
122//! zng::button::style_fn = Style! {
123//! // override the default border for all buttons in the Stack.
124//! widget::border = 2, colors::GREEN;
125//! };
126//!
127//! children = ui_vec![
128//! // This button is affected by the contextual light and default styles.
129//! Button! {
130//! child = Text!("BLUE+GREEN");
131//! style_fn = zng::button::LightStyle!();
132//! },
133//! // This button is only affected by the contextual default style.
134//! Button! {
135//! child = Text!("Normal+GREEN");
136//! },
137//! ];
138//! }
139//! # ;
140//! ```
141//!
142//! Named styles accumulate context the same way the widget default style does. When applied the widget properties are
143//! set/replaced in this order:
144//!
145//! 1 - The default properties set on the widget declaration.
146//! 2 - The default style and any extension/replacement style set for the default style using `style_fn` in a parent widget.
147//! 3 - The named style set using `style_fn` on the widget and any extension/replacement style set for the named style property in a parent widget.
148//! 4 - The properties set on the widget instance.
149//!
150//! Note that on the target widget instance only the `style_fn` property is used, the named style property is standalone and for use in parent widgets.
151//!
152//! Named styles are ideal for cases where an widget can have a distinct appearance without changing its behavior. For example instead of a
153//! *CheckBox!* widget the `Toggle!` widget provides a `toggle::{CheckStyle, check_style_fn}`. Theme implementers can restyle *check-boxes* just
154//! the same, and widget users don't need to change the widget type just to use a different appearance.
155//!
156//! # Shared Styles
157//!
158//! Style instances can be set directly on `style_fn` properties, but if the style is used by more then one widget property values
159//! that can't be cloned will only appear on the last widget to use the style. The [`style_fn!`] macro can be used to declare a
160//! closure that instantiates the style for each usage. The property values that can't be cloned are `impl IntoUiNode`.
161//!
162//! The example below demonstrates this issue:
163//!
164//! ```
165//! use zng::prelude::*;
166//! # fn example() {
167//!
168//! # let _ =
169//! Stack! {
170//! direction = StackDirection::top_to_bottom();
171//! spacing = 5;
172//! widget::parallel = false; // init buttons sequentially
173//!
174//! zng::button::style_fn = Style! {
175//! // background is `impl IntoUiNode` that can't be cloned. Nodes
176//! // are moved to the last place that requests it.
177//! widget::background = zng::color::flood(colors::AZURE);
178//! };
179//! children = ui_vec![
180//! Button! { child = Text!("Default") },
181//! // the last button to init takes the background node.
182//! Button! { child = Text!("Default+AZURE") },
183//! ];
184//! }
185//! # ; }
186//! ```
187//!
188//! Using a closure to set fixes the issue:
189//!
190//! ```
191//! # use zng::prelude::*;
192//! # fn example() {
193//! #
194//! # let _ =
195//! # Stack! {
196//! zng::button::style_fn = style_fn!(|_| Style! {
197//! widget::background = zng::color::flood(colors::AZURE);
198//! });
199//! # }
200//! # ; }
201
202pub use zng_wgt_style::{Style, StyleArgs, StyleBuilder, StyleFn, StyleMix, impl_named_style_fn, impl_style_fn, style_fn};