native_theme/model/
icon_sizes.rs1use native_theme_derive::ThemeFields;
4use serde::{Deserialize, Serialize};
5
6#[serde_with::skip_serializing_none]
11#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, ThemeFields)]
12#[serde(default)]
13pub struct IconSizes {
14 #[serde(rename = "toolbar_px")]
16 pub toolbar: Option<f32>,
17 #[serde(rename = "small_px")]
19 pub small: Option<f32>,
20 #[serde(rename = "large_px")]
22 pub large: Option<f32>,
23 #[serde(rename = "dialog_px")]
25 pub dialog: Option<f32>,
26 #[serde(rename = "panel_px")]
28 pub panel: Option<f32>,
29}
30
31impl_merge!(IconSizes {
32 option { toolbar, small, large, dialog, panel }
33});
34
35#[cfg(test)]
36#[allow(clippy::unwrap_used, clippy::expect_used)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn icon_sizes_default_is_empty() {
42 assert!(IconSizes::default().is_empty());
43 }
44
45 #[test]
46 fn icon_sizes_not_empty_when_toolbar_set() {
47 let s = IconSizes {
48 toolbar: Some(24.0),
49 ..Default::default()
50 };
51 assert!(!s.is_empty());
52 }
53
54 #[test]
55 fn icon_sizes_not_empty_when_any_field_set() {
56 for sizes in [
57 IconSizes {
58 toolbar: Some(24.0),
59 ..Default::default()
60 },
61 IconSizes {
62 small: Some(16.0),
63 ..Default::default()
64 },
65 IconSizes {
66 large: Some(32.0),
67 ..Default::default()
68 },
69 IconSizes {
70 dialog: Some(22.0),
71 ..Default::default()
72 },
73 IconSizes {
74 panel: Some(20.0),
75 ..Default::default()
76 },
77 ] {
78 assert!(!sizes.is_empty());
79 }
80 }
81
82 #[test]
83 fn icon_sizes_merge_overlay_wins() {
84 let mut base = IconSizes {
85 toolbar: Some(24.0),
86 small: Some(16.0),
87 large: None,
88 dialog: None,
89 panel: None,
90 };
91 let overlay = IconSizes {
92 toolbar: None,
93 small: Some(18.0),
94 large: Some(32.0),
95 dialog: None,
96 panel: None,
97 };
98 base.merge(&overlay);
99 assert_eq!(base.toolbar, Some(24.0)); assert_eq!(base.small, Some(18.0)); assert_eq!(base.large, Some(32.0)); assert_eq!(base.dialog, None);
103 assert_eq!(base.panel, None);
104 }
105
106 #[test]
107 fn icon_sizes_merge_none_preserves_base() {
108 let mut base = IconSizes {
109 toolbar: Some(24.0),
110 small: Some(16.0),
111 large: Some(32.0),
112 dialog: Some(22.0),
113 panel: Some(20.0),
114 };
115 let overlay = IconSizes::default();
116 base.merge(&overlay);
117 assert_eq!(base.toolbar, Some(24.0));
118 assert_eq!(base.small, Some(16.0));
119 assert_eq!(base.large, Some(32.0));
120 assert_eq!(base.dialog, Some(22.0));
121 assert_eq!(base.panel, Some(20.0));
122 }
123
124 #[test]
125 fn icon_sizes_toml_round_trip() {
126 let sizes = IconSizes {
127 toolbar: Some(24.0),
128 small: Some(16.0),
129 large: Some(32.0),
130 dialog: Some(22.0),
131 panel: Some(20.0),
132 };
133 let toml_str = toml::to_string(&sizes).unwrap();
134 let deserialized: IconSizes = toml::from_str(&toml_str).unwrap();
135 assert_eq!(deserialized, sizes);
136 }
137
138 #[test]
139 fn icon_sizes_toml_partial_round_trip() {
140 let sizes = IconSizes {
141 toolbar: Some(24.0),
142 ..Default::default()
143 };
144 let toml_str = toml::to_string(&sizes).unwrap();
145 let deserialized: IconSizes = toml::from_str(&toml_str).unwrap();
146 assert_eq!(deserialized, sizes);
147 assert!(deserialized.small.is_none());
148 }
149}