rosace_widgets/tree/
material.rs1use rosace_shader::ShaderMaterial;
19use rosace_theme::ThemeData;
20
21pub trait MaterialKey: std::any::Any + Send + Sync + 'static {
29 fn material(&self) -> &ShaderMaterial;
30}
31
32pub fn resolve_material<K: MaterialKey>(
37 theme: &ThemeData,
38 explicit: Option<&ShaderMaterial>,
39) -> Option<ShaderMaterial> {
40 explicit
41 .cloned()
42 .or_else(|| theme.ext::<K>().map(|k| k.material().clone()))
43}
44
45pub struct ContainerMaterial(pub ShaderMaterial);
47impl MaterialKey for ContainerMaterial {
48 fn material(&self) -> &ShaderMaterial { &self.0 }
49}
50
51pub struct CardMaterial(pub ShaderMaterial);
53impl MaterialKey for CardMaterial {
54 fn material(&self) -> &ShaderMaterial { &self.0 }
55}
56
57pub struct DialogMaterial(pub ShaderMaterial);
59impl MaterialKey for DialogMaterial {
60 fn material(&self) -> &ShaderMaterial { &self.0 }
61}
62
63pub struct SheetMaterial(pub ShaderMaterial);
65impl MaterialKey for SheetMaterial {
66 fn material(&self) -> &ShaderMaterial { &self.0 }
67}
68
69pub struct DrawerMaterial(pub ShaderMaterial);
71impl MaterialKey for DrawerMaterial {
72 fn material(&self) -> &ShaderMaterial { &self.0 }
73}
74
75pub struct AppBarMaterial(pub ShaderMaterial);
77impl MaterialKey for AppBarMaterial {
78 fn material(&self) -> &ShaderMaterial { &self.0 }
79}
80
81pub struct BottomNavMaterial(pub ShaderMaterial);
83impl MaterialKey for BottomNavMaterial {
84 fn material(&self) -> &ShaderMaterial { &self.0 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use rosace_shader::PipelineId;
91
92 struct TestKey(ShaderMaterial);
93 impl MaterialKey for TestKey {
94 fn material(&self) -> &ShaderMaterial { &self.0 }
95 }
96
97 fn mat(id: u64) -> ShaderMaterial {
98 ShaderMaterial::new(PipelineId::user(0x1000 + id), vec![id as u8])
99 }
100
101 #[test]
102 fn instance_material_wins_over_theme() {
103 let theme = rosace_theme::built_in::dark_theme().with_ext(TestKey(mat(1)));
104 let explicit = mat(2);
105 let resolved = resolve_material::<TestKey>(&theme, Some(&explicit));
106 assert_eq!(resolved, Some(mat(2)), "explicit instance material must win");
107 }
108
109 #[test]
110 fn theme_material_used_when_no_instance() {
111 let theme = rosace_theme::built_in::dark_theme().with_ext(TestKey(mat(3)));
112 let resolved = resolve_material::<TestKey>(&theme, None);
113 assert_eq!(resolved, Some(mat(3)), "theme default applies with no instance override");
114 }
115
116 #[test]
117 fn none_when_neither_set() {
118 let theme = rosace_theme::built_in::dark_theme();
119 let resolved = resolve_material::<TestKey>(&theme, None);
120 assert!(resolved.is_none(), "no material anywhere → render normally");
121 }
122
123 #[test]
124 fn distinct_keys_hold_independent_materials() {
125 struct OtherKey(ShaderMaterial);
126 impl MaterialKey for OtherKey {
127 fn material(&self) -> &ShaderMaterial { &self.0 }
128 }
129 let theme = rosace_theme::built_in::dark_theme()
132 .with_ext(TestKey(mat(5)))
133 .with_ext(OtherKey(mat(6)));
134 assert_eq!(resolve_material::<TestKey>(&theme, None), Some(mat(5)));
135 assert_eq!(resolve_material::<OtherKey>(&theme, None), Some(mat(6)));
136 }
137}