bevy_mod_stylebuilder/
builder.rs

1#![allow(missing_docs)]
2//! Defines fluent builder for styles.
3
4use bevy::{
5    asset::AssetPath,
6    color::{LinearRgba, Srgba},
7    prelude::*,
8    ui::{self, ZIndex},
9};
10
11/// An object that provides a fluent interface for defining styles for bevy_ui nodes.
12/// Most components such as `BackgroundColor` are mutated immediately, however some component types
13/// such as `Style` are cached in the builder and not applied until `finish` is called.
14pub struct StyleBuilder<'a, 'w> {
15    pub target: &'a mut EntityWorldMut<'w>,
16    pub(crate) style: ui::Style,
17    pub(crate) style_changed: bool,
18}
19
20impl<'a, 'w> StyleBuilder<'a, 'w> {
21    /// Construct a new StyleBuilder instance.
22    pub fn new(target: &'a mut EntityWorldMut<'w>, style: ui::Style) -> Self {
23        Self {
24            target,
25            style,
26            style_changed: false,
27        }
28    }
29
30    /// Helper method for loading assets.
31    pub fn load_asset<A: Asset>(&mut self, path: AssetPath<'_>) -> Handle<A> {
32        self.target.world_scope(|world| {
33            let server = world.get_resource::<AssetServer>().unwrap();
34            server.load(path)
35        })
36    }
37
38    /// Consumes the [`StyleBuilder`] and applies the style to the target entity.
39    pub fn finish(self) {
40        if self.style_changed {
41            self.target.insert(self.style);
42        }
43    }
44}
45
46// LineBreak(BreakLineOn),
47
48/// Trait that represents a CSS color
49pub trait ColorParam {
50    fn to_val(self) -> Option<Color>;
51}
52
53impl ColorParam for Option<Color> {
54    fn to_val(self) -> Option<Color> {
55        self
56    }
57}
58
59impl ColorParam for Color {
60    fn to_val(self) -> Option<Color> {
61        Some(self)
62    }
63}
64
65impl ColorParam for Srgba {
66    fn to_val(self) -> Option<Color> {
67        Some(Color::srgba(self.red, self.green, self.blue, self.alpha))
68    }
69}
70
71impl ColorParam for Option<Srgba> {
72    fn to_val(self) -> Option<Color> {
73        self.map(|c| Color::srgba(c.red, c.green, c.blue, c.alpha))
74    }
75}
76
77impl ColorParam for LinearRgba {
78    fn to_val(self) -> Option<Color> {
79        Some(self.into())
80    }
81}
82
83impl ColorParam for Option<LinearRgba> {
84    fn to_val(self) -> Option<Color> {
85        self.map(|c| c.into())
86    }
87}
88
89impl ColorParam for &str {
90    fn to_val(self) -> Option<Color> {
91        let c = Srgba::hex(self).unwrap();
92        Some(Color::srgba(c.red, c.green, c.blue, c.alpha))
93    }
94}
95
96/// Trait that represents a CSS "length"
97pub trait LengthParam {
98    fn to_val(self) -> ui::Val;
99}
100
101impl LengthParam for ui::Val {
102    fn to_val(self) -> ui::Val {
103        self
104    }
105}
106
107impl LengthParam for f32 {
108    fn to_val(self) -> ui::Val {
109        ui::Val::Px(self)
110    }
111}
112
113impl LengthParam for i32 {
114    fn to_val(self) -> ui::Val {
115        ui::Val::Px(self as f32)
116    }
117}
118
119/// Trait that represents a CSS Z-index
120pub trait ZIndexParam {
121    fn to_val(self) -> ZIndex;
122}
123
124impl ZIndexParam for ZIndex {
125    fn to_val(self) -> ZIndex {
126        self
127    }
128}
129
130impl ZIndexParam for i32 {
131    fn to_val(self) -> ZIndex {
132        ZIndex::Local(self)
133    }
134}
135
136/// Trait that represents CSS edge widths (margin, padding, etc.)
137pub trait UiRectParam {
138    fn to_uirect(self) -> ui::UiRect;
139}
140
141impl UiRectParam for ui::UiRect {
142    fn to_uirect(self) -> ui::UiRect {
143        self
144    }
145}
146
147impl UiRectParam for ui::Val {
148    fn to_uirect(self) -> ui::UiRect {
149        ui::UiRect::all(self)
150    }
151}
152
153impl UiRectParam for f32 {
154    fn to_uirect(self) -> ui::UiRect {
155        ui::UiRect::all(ui::Val::Px(self))
156    }
157}
158
159impl UiRectParam for i32 {
160    fn to_uirect(self) -> ui::UiRect {
161        ui::UiRect::all(ui::Val::Px(self as f32))
162    }
163}
164
165impl<H: LengthParam, V: LengthParam> UiRectParam for (H, V) {
166    fn to_uirect(self) -> ui::UiRect {
167        ui::UiRect::axes(self.0.to_val(), self.1.to_val())
168    }
169}
170
171/// Trait that represents border radius
172pub trait BorderRadiusParam {
173    fn to_border_radius(self) -> ui::BorderRadius;
174}
175
176impl BorderRadiusParam for ui::BorderRadius {
177    fn to_border_radius(self) -> ui::BorderRadius {
178        self
179    }
180}
181
182impl BorderRadiusParam for ui::Val {
183    fn to_border_radius(self) -> ui::BorderRadius {
184        ui::BorderRadius::all(self)
185    }
186}
187
188impl BorderRadiusParam for f32 {
189    fn to_border_radius(self) -> ui::BorderRadius {
190        ui::BorderRadius::all(ui::Val::Px(self))
191    }
192}
193
194impl BorderRadiusParam for i32 {
195    fn to_border_radius(self) -> ui::BorderRadius {
196        ui::BorderRadius::all(ui::Val::Px(self as f32))
197    }
198}
199
200/// Trait that represents an optional float
201pub trait OptFloatParam {
202    fn to_val(self) -> Option<f32>;
203}
204
205impl OptFloatParam for Option<f32> {
206    fn to_val(self) -> Option<f32> {
207        self
208    }
209}
210
211impl OptFloatParam for f32 {
212    fn to_val(self) -> Option<f32> {
213        Some(self)
214    }
215}
216
217impl OptFloatParam for i32 {
218    fn to_val(self) -> Option<f32> {
219        Some(self as f32)
220    }
221}
222
223/// Enum that represents either a handle or an owned path.
224///
225/// This is useful for when you want to specify an asset, but also want it to be have lifetime 'static
226#[derive(Clone, Debug)]
227pub enum HandleOrOwnedPath<T: Asset> {
228    Handle(Handle<T>),
229    Path(String),
230}
231
232impl<T: Asset> Default for HandleOrOwnedPath<T> {
233    fn default() -> Self {
234        Self::Path("".to_string())
235    }
236}
237
238// Necessary because we don't want to require T: PartialEq
239impl<T: Asset> PartialEq for HandleOrOwnedPath<T> {
240    fn eq(&self, other: &Self) -> bool {
241        match (self, other) {
242            (HandleOrOwnedPath::Handle(h1), HandleOrOwnedPath::Handle(h2)) => h1 == h2,
243            (HandleOrOwnedPath::Path(p1), HandleOrOwnedPath::Path(p2)) => p1 == p2,
244            _ => false,
245        }
246    }
247}
248
249impl<T: Asset> From<Handle<T>> for HandleOrOwnedPath<T> {
250    fn from(h: Handle<T>) -> Self {
251        HandleOrOwnedPath::Handle(h)
252    }
253}
254
255impl<T: Asset> From<&str> for HandleOrOwnedPath<T> {
256    fn from(p: &str) -> Self {
257        HandleOrOwnedPath::Path(p.to_string())
258    }
259}
260
261impl<T: Asset> From<String> for HandleOrOwnedPath<T> {
262    fn from(p: String) -> Self {
263        HandleOrOwnedPath::Path(p.clone())
264    }
265}
266
267impl<T: Asset> From<&String> for HandleOrOwnedPath<T> {
268    fn from(p: &String) -> Self {
269        HandleOrOwnedPath::Path(p.to_string())
270    }
271}
272
273impl<T: Asset + Clone> From<&HandleOrOwnedPath<T>> for HandleOrOwnedPath<T> {
274    fn from(p: &HandleOrOwnedPath<T>) -> Self {
275        p.to_owned()
276    }
277}
278
279/// Enum that represents either a handle or an asset path or nothing.
280#[derive(Clone, Default, Debug)]
281pub enum MaybeHandleOrPath<'a, T: Asset> {
282    #[default]
283    None,
284    Handle(Handle<T>),
285    Path(AssetPath<'a>),
286}
287
288// Necessary because we don't want to require T: PartialEq
289impl<'a, T: Asset> PartialEq for MaybeHandleOrPath<'a, T> {
290    fn eq(&self, other: &Self) -> bool {
291        match (self, other) {
292            (MaybeHandleOrPath::None, MaybeHandleOrPath::None) => true,
293            (MaybeHandleOrPath::Handle(h1), MaybeHandleOrPath::Handle(h2)) => h1 == h2,
294            (MaybeHandleOrPath::Path(p1), MaybeHandleOrPath::Path(p2)) => p1 == p2,
295            _ => false,
296        }
297    }
298}
299
300impl<T: Asset> From<Handle<T>> for MaybeHandleOrPath<'_, T> {
301    fn from(h: Handle<T>) -> Self {
302        MaybeHandleOrPath::Handle(h)
303    }
304}
305
306impl<'a, T: Asset> From<AssetPath<'a>> for MaybeHandleOrPath<'a, T> {
307    fn from(p: AssetPath<'a>) -> Self {
308        MaybeHandleOrPath::Path(p)
309    }
310}
311
312impl<'a, T: Asset> From<&'a str> for MaybeHandleOrPath<'a, T> {
313    fn from(p: &'a str) -> Self {
314        MaybeHandleOrPath::Path(AssetPath::parse(p))
315    }
316}
317
318impl<'a, T: Asset> From<Option<AssetPath<'a>>> for MaybeHandleOrPath<'a, T> {
319    fn from(p: Option<AssetPath<'a>>) -> Self {
320        match p {
321            Some(p) => MaybeHandleOrPath::Path(p),
322            None => MaybeHandleOrPath::None,
323        }
324    }
325}
326
327impl<'a, T: Asset> From<&'a HandleOrOwnedPath<T>> for MaybeHandleOrPath<'a, T> {
328    fn from(p: &'a HandleOrOwnedPath<T>) -> Self {
329        match p {
330            HandleOrOwnedPath::Handle(h) => MaybeHandleOrPath::Handle(h.clone()),
331            HandleOrOwnedPath::Path(p) => MaybeHandleOrPath::Path(AssetPath::parse(p)),
332        }
333    }
334}