1use crate::styles::{
31 SharedAvatarStyle, SharedBadgeStyle, SharedBannerStyle, SharedButtonStyle, SharedCalendarStyle,
32 SharedCardStyle, SharedChartStyle, SharedCheckboxStyle, SharedColorPickerStyle,
33 SharedComboBoxStyle, SharedDateEditStyle, SharedDialogStyle, SharedDropTargetStyle,
34 SharedDropZoneStyle, SharedGridViewStyle, SharedIconButtonStyle, SharedLinkStyle,
35 SharedListContainerStyle, SharedMenuItemStyle, SharedPanelStyle, SharedPopoverStyle,
36 SharedProgressBarStyle, SharedRadioStyle, SharedRadioTileStyle, SharedRichTextEditorStyle,
37 SharedScrollBarStyle, SharedSearchFieldStyle, SharedSegmentedControlStyle, SharedSliderStyle,
38 SharedSnackbarStyle, SharedSpinBoxStyle, SharedSplitButtonStyle, SharedSplitterStyle,
39 SharedStandardItemStyle, SharedTabStyle, SharedTableStyle, SharedTextInputStyle,
40 SharedTextSelectionStyle, SharedToastStyle, SharedToggleStyle, SharedTooltipStyle,
41 SharedWebViewStyle,
42};
43
44#[derive(Default, Clone)]
48pub struct ComponentStyleSlots {
49 pub button: Option<SharedButtonStyle>,
50 pub split_button: Option<SharedSplitButtonStyle>,
51 pub splitter: Option<SharedSplitterStyle>,
52 pub icon_button: Option<SharedIconButtonStyle>,
53 pub toggle: Option<SharedToggleStyle>,
54 pub checkbox: Option<SharedCheckboxStyle>,
55 pub radio: Option<SharedRadioStyle>,
56 pub radio_tile: Option<SharedRadioTileStyle>,
57 pub slider: Option<SharedSliderStyle>,
58 pub text_input: Option<SharedTextInputStyle>,
59 pub combo_box: Option<SharedComboBoxStyle>,
60 pub menu_item: Option<SharedMenuItemStyle>,
61 pub panel: Option<SharedPanelStyle>,
62 pub card: Option<SharedCardStyle>,
63 pub chart: Option<SharedChartStyle>,
64 pub popover: Option<SharedPopoverStyle>,
65 pub tooltip: Option<SharedTooltipStyle>,
66 pub scroll_bar: Option<SharedScrollBarStyle>,
67 pub standard_item: Option<SharedStandardItemStyle>,
68 pub tab: Option<SharedTabStyle>,
69 pub dialog: Option<SharedDialogStyle>,
70 pub snackbar: Option<SharedSnackbarStyle>,
71 pub toast: Option<SharedToastStyle>,
72 pub banner: Option<SharedBannerStyle>,
73 pub badge: Option<SharedBadgeStyle>,
74 pub progress_bar: Option<SharedProgressBarStyle>,
75 pub link: Option<SharedLinkStyle>,
76 pub segmented_control: Option<SharedSegmentedControlStyle>,
77 pub avatar: Option<SharedAvatarStyle>,
78 pub calendar: Option<SharedCalendarStyle>,
79 pub color_picker: Option<SharedColorPickerStyle>,
80 pub spin_box: Option<SharedSpinBoxStyle>,
81 pub date_edit: Option<SharedDateEditStyle>,
82 pub search_field: Option<SharedSearchFieldStyle>,
83 pub rich_text_editor: Option<SharedRichTextEditorStyle>,
84 pub table: Option<SharedTableStyle>,
85 pub list_container: Option<SharedListContainerStyle>,
86 pub drop_zone: Option<SharedDropZoneStyle>,
87 pub drop_target: Option<SharedDropTargetStyle>,
88 pub grid_view: Option<SharedGridViewStyle>,
89 pub web_view: Option<SharedWebViewStyle>,
90 pub text_selection: Option<SharedTextSelectionStyle>,
93}
94
95macro_rules! for_every_slot {
104 ($probe:ident) => {
105 $probe!(
106 button,
107 split_button,
108 splitter,
109 icon_button,
110 toggle,
111 checkbox,
112 radio,
113 radio_tile,
114 slider,
115 text_input,
116 combo_box,
117 menu_item,
118 panel,
119 card,
120 chart,
121 popover,
122 tooltip,
123 scroll_bar,
124 standard_item,
125 tab,
126 dialog,
127 snackbar,
128 toast,
129 banner,
130 badge,
131 progress_bar,
132 link,
133 segmented_control,
134 avatar,
135 calendar,
136 color_picker,
137 spin_box,
138 date_edit,
139 search_field,
140 rich_text_editor,
141 table,
142 list_container,
143 drop_zone,
144 drop_target,
145 grid_view,
146 web_view,
147 text_selection
148 )
149 };
150}
151
152impl ComponentStyleSlots {
153 pub fn installed(&self) -> Vec<&'static str> {
165 macro_rules! probe {
166 ($($name:ident),* $(,)?) => {{
167 let Self { $($name),* } = self;
168 let mut out = Vec::new();
169 $(if $name.is_some() {
170 out.push(stringify!($name));
171 })*
172 out
173 }};
174 }
175 for_every_slot!(probe)
176 }
177
178 pub fn unchanged_against(&self, other: &Self) -> Vec<&'static str> {
200 fn same<T: ?Sized>(a: &Option<std::rc::Rc<T>>, b: &Option<std::rc::Rc<T>>) -> bool {
201 matches!((a, b), (Some(x), Some(y)) if std::rc::Rc::ptr_eq(x, y))
202 }
203 macro_rules! probe {
204 ($($name:ident),* $(,)?) => {{
205 let Self { $($name),* } = self;
209 let mut out = Vec::new();
210 $(if same($name, &other.$name) {
211 out.push(stringify!($name));
212 })*
213 out
214 }};
215 }
216 for_every_slot!(probe)
217 }
218
219 pub fn is_empty(&self) -> bool {
222 self.installed().is_empty()
223 }
224}
225
226impl std::fmt::Debug for ComponentStyleSlots {
227 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228 f.debug_struct("ComponentStyleSlots")
232 .field("button", &self.button.is_some())
233 .field("split_button", &self.split_button.is_some())
234 .field("splitter", &self.splitter.is_some())
235 .field("icon_button", &self.icon_button.is_some())
236 .field("toggle", &self.toggle.is_some())
237 .field("checkbox", &self.checkbox.is_some())
238 .field("radio", &self.radio.is_some())
239 .field("radio_tile", &self.radio_tile.is_some())
240 .field("slider", &self.slider.is_some())
241 .field("text_input", &self.text_input.is_some())
242 .field("combo_box", &self.combo_box.is_some())
243 .field("menu_item", &self.menu_item.is_some())
244 .field("panel", &self.panel.is_some())
245 .field("card", &self.card.is_some())
246 .field("chart", &self.chart.is_some())
247 .field("popover", &self.popover.is_some())
248 .field("tooltip", &self.tooltip.is_some())
249 .field("scroll_bar", &self.scroll_bar.is_some())
250 .field("standard_item", &self.standard_item.is_some())
251 .field("tab", &self.tab.is_some())
252 .field("dialog", &self.dialog.is_some())
253 .field("snackbar", &self.snackbar.is_some())
254 .field("toast", &self.toast.is_some())
255 .field("banner", &self.banner.is_some())
256 .field("badge", &self.badge.is_some())
257 .field("progress_bar", &self.progress_bar.is_some())
258 .field("link", &self.link.is_some())
259 .field("segmented_control", &self.segmented_control.is_some())
260 .field("avatar", &self.avatar.is_some())
261 .field("calendar", &self.calendar.is_some())
262 .field("color_picker", &self.color_picker.is_some())
263 .field("spin_box", &self.spin_box.is_some())
264 .field("date_edit", &self.date_edit.is_some())
265 .field("search_field", &self.search_field.is_some())
266 .field("rich_text_editor", &self.rich_text_editor.is_some())
267 .field("table", &self.table.is_some())
268 .field("list_container", &self.list_container.is_some())
269 .field("drop_zone", &self.drop_zone.is_some())
270 .field("drop_target", &self.drop_target.is_some())
271 .field("grid_view", &self.grid_view.is_some())
272 .field("web_view", &self.web_view.is_some())
273 .field("text_selection", &self.text_selection.is_some())
274 .finish()
275 }
276}
277
278impl PartialEq for ComponentStyleSlots {
279 fn eq(&self, other: &Self) -> bool {
280 fn rc_eq<T: ?Sized>(a: &Option<std::rc::Rc<T>>, b: &Option<std::rc::Rc<T>>) -> bool {
284 match (a, b) {
285 (None, None) => true,
286 (Some(x), Some(y)) => std::rc::Rc::ptr_eq(x, y),
287 _ => false,
288 }
289 }
290 rc_eq(&self.button, &other.button)
291 && rc_eq(&self.radio_tile, &other.radio_tile)
292 && rc_eq(&self.split_button, &other.split_button)
293 && rc_eq(&self.splitter, &other.splitter)
294 && rc_eq(&self.icon_button, &other.icon_button)
295 && rc_eq(&self.toggle, &other.toggle)
296 && rc_eq(&self.checkbox, &other.checkbox)
297 && rc_eq(&self.radio, &other.radio)
298 && rc_eq(&self.slider, &other.slider)
299 && rc_eq(&self.text_input, &other.text_input)
300 && rc_eq(&self.combo_box, &other.combo_box)
301 && rc_eq(&self.menu_item, &other.menu_item)
302 && rc_eq(&self.panel, &other.panel)
303 && rc_eq(&self.card, &other.card)
304 && rc_eq(&self.chart, &other.chart)
305 && rc_eq(&self.popover, &other.popover)
306 && rc_eq(&self.tooltip, &other.tooltip)
307 && rc_eq(&self.scroll_bar, &other.scroll_bar)
308 && rc_eq(&self.standard_item, &other.standard_item)
309 && rc_eq(&self.tab, &other.tab)
310 && rc_eq(&self.dialog, &other.dialog)
311 && rc_eq(&self.snackbar, &other.snackbar)
312 && rc_eq(&self.toast, &other.toast)
313 && rc_eq(&self.banner, &other.banner)
314 && rc_eq(&self.badge, &other.badge)
315 && rc_eq(&self.progress_bar, &other.progress_bar)
316 && rc_eq(&self.link, &other.link)
317 && rc_eq(&self.segmented_control, &other.segmented_control)
318 && rc_eq(&self.avatar, &other.avatar)
319 && rc_eq(&self.calendar, &other.calendar)
320 && rc_eq(&self.color_picker, &other.color_picker)
321 && rc_eq(&self.spin_box, &other.spin_box)
322 && rc_eq(&self.date_edit, &other.date_edit)
323 && rc_eq(&self.search_field, &other.search_field)
324 && rc_eq(&self.rich_text_editor, &other.rich_text_editor)
325 && rc_eq(&self.table, &other.table)
326 && rc_eq(&self.list_container, &other.list_container)
327 && rc_eq(&self.drop_zone, &other.drop_zone)
328 && rc_eq(&self.drop_target, &other.drop_target)
329 && rc_eq(&self.grid_view, &other.grid_view)
330 && rc_eq(&self.web_view, &other.web_view)
331 && rc_eq(&self.text_selection, &other.text_selection)
332 }
333}