Skip to main content

egui/class/
classes.rs

1use crate::class::{ClassName, HasClasses};
2use alloc::fmt;
3use smallvec::SmallVec;
4
5/// [`Classes`] is a collection of [`ClassName`]s that can be added to widgets or containers.
6///
7/// This can be used by styling engine to compute a different style
8/// based on the set of classes present on the widget/Ui.
9/// You could also use it to e.g. change widget behavior based on the context of some container.
10///
11/// Class order is preserved and may be used by a style provider for precedence (last class should win).
12///
13/// Use [`HasClasses`] to add/modify classes.
14#[derive(Debug, Default, Clone, Hash)]
15pub struct Classes {
16    classes: SmallVec<[ClassName; 5]>,
17}
18
19impl Classes {
20    /// Add a class to the list if the condition is true.
21    ///
22    /// A class is never added twice. This never removes a class: use [`Self::set`] for that.
23    #[inline]
24    pub(crate) fn add_if(&mut self, class: impl Into<ClassName>, condition: bool) {
25        if condition {
26            self.set(class, true);
27        }
28    }
29
30    /// Add the class if `present`, remove it otherwise.
31    #[inline]
32    pub(crate) fn set(&mut self, class: impl Into<ClassName>, present: bool) {
33        let class = class.into();
34        // Always retain and push again, since order of classes can matter.
35        self.classes.retain(|existing| existing != &class);
36        if present {
37            self.classes.push(class);
38        }
39    }
40
41    /// Extend the classes and deduplicate them.
42    ///
43    /// A class that is already present is moved to the end, since order can matter.
44    #[inline]
45    pub(crate) fn extend(&mut self, classes: impl IntoIterator<Item = impl Into<ClassName>>) {
46        for class in classes {
47            self.set(class, true);
48        }
49    }
50
51    /// Iterate over the classes, in order.
52    #[inline]
53    pub fn iter(&self) -> core::slice::Iter<'_, ClassName> {
54        self.classes.iter()
55    }
56
57    /// Return the classes as a slice
58    #[inline]
59    pub fn as_slice(&self) -> &[ClassName] {
60        self.classes.as_slice()
61    }
62}
63
64impl IntoIterator for Classes {
65    type Item = ClassName;
66    type IntoIter = smallvec::IntoIter<[ClassName; 5]>;
67
68    #[inline]
69    fn into_iter(self) -> Self::IntoIter {
70        self.classes.into_iter()
71    }
72}
73
74impl<'a> IntoIterator for &'a Classes {
75    type Item = &'a ClassName;
76    type IntoIter = core::slice::Iter<'a, ClassName>;
77
78    #[inline]
79    fn into_iter(self) -> Self::IntoIter {
80        self.classes.iter()
81    }
82}
83
84impl HasClasses for Classes {
85    fn classes(&self) -> &Classes {
86        self
87    }
88
89    fn classes_mut(&mut self) -> &mut Classes {
90        self
91    }
92}
93
94impl core::fmt::Display for Classes {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        for (i, class) in self.classes.iter().enumerate() {
97            if i > 0 {
98                f.write_str(" ")?;
99            }
100            f.write_str(class.as_str())?;
101        }
102        Ok(())
103    }
104}