cadmus_core/view/settings_editor/
setting_row.rs1use super::super::label::Label;
2use super::super::Align;
3use super::super::{Bus, Event, Hub, Id, RenderQueue, View, ID_FEEDER};
4use super::kinds::{SettingIdentity, SettingKind};
5use super::setting_value::SettingValue;
6use crate::context::Context;
7use crate::framebuffer::Framebuffer;
8use crate::geom::Rectangle;
9use crate::settings::Settings;
10
11pub struct SettingRow {
20 id: Id,
21 rect: Rectangle,
22 children: Vec<Box<dyn View>>,
23 identity: SettingIdentity,
25}
26
27impl SettingRow {
28 pub fn new(
29 kind: impl SettingKind + 'static,
30 rect: Rectangle,
31 settings: &Settings,
32 fonts: &mut crate::font::Fonts,
33 ) -> SettingRow {
34 let mut children = Vec::new();
35
36 let half_width = rect.width() as i32 / 2;
37 let label_rect = rect![rect.min.x, rect.min.y, rect.min.x + half_width, rect.max.y];
38 let value_rect = rect![rect.min.x + half_width, rect.min.y, rect.max.x, rect.max.y];
39
40 let label_text = kind.label(settings);
41 let identity = kind.identity();
42 let label = Label::new(label_rect, label_text, Align::Left(50));
43 children.push(Box::new(label) as Box<dyn View>);
44
45 let setting_value = SettingValue::new(kind, value_rect, settings, fonts);
46 children.push(Box::new(setting_value) as Box<dyn View>);
47
48 SettingRow {
49 id: ID_FEEDER.next(),
50 rect,
51 children,
52 identity,
53 }
54 }
55}
56
57impl View for SettingRow {
58 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, _bus, rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
59 fn handle_event(
60 &mut self,
61 evt: &Event,
62 _hub: &Hub,
63 _bus: &mut Bus,
64 rq: &mut RenderQueue,
65 _context: &mut Context,
66 ) -> bool {
67 match evt {
68 Event::UpdateLibrary(index, ref library) => {
69 if let SettingIdentity::LibraryInfo(our_index) = self.identity {
70 if *index == our_index {
71 if let Some(name_view) = self.children.get_mut(0) {
72 if let Some(name_label) = name_view.as_any_mut().downcast_mut::<Label>()
73 {
74 name_label.update(&library.name, rq);
75 return true;
76 }
77 }
78 }
79 }
80 false
81 }
82 _ => false,
83 }
84 }
85
86 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _fb, _fonts), fields(rect = ?_rect)))]
87 fn render(&self, _fb: &mut dyn Framebuffer, _rect: Rectangle, _fonts: &mut crate::font::Fonts) {
88 }
89
90 fn rect(&self) -> &Rectangle {
91 &self.rect
92 }
93
94 fn rect_mut(&mut self) -> &mut Rectangle {
95 &mut self.rect
96 }
97
98 fn children(&self) -> &Vec<Box<dyn View>> {
99 &self.children
100 }
101
102 fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
103 &mut self.children
104 }
105
106 fn id(&self) -> Id {
107 self.id
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::context::test_helpers::create_test_context;
115 use crate::settings::LibrarySettings;
116 use crate::view::settings_editor::kinds::library::LibraryInfo;
117 use std::collections::VecDeque;
118 use std::path::PathBuf;
119 use std::sync::mpsc::channel;
120
121 fn create_test_settings() -> Settings {
122 let mut settings = Settings::default();
123 settings.libraries.clear();
124 settings.libraries.push(LibrarySettings {
125 name: "Test Library 0".to_string(),
126 path: PathBuf::from("/tmp/lib0"),
127 ..Default::default()
128 });
129 settings.libraries.push(LibrarySettings {
130 name: "Test Library 1".to_string(),
131 path: PathBuf::from("/tmp/lib1"),
132 ..Default::default()
133 });
134 settings
135 }
136
137 #[test]
138 fn test_update_library_event_updates_matching_row() {
139 let mut context = create_test_context();
140 let settings = create_test_settings();
141 let rect = rect![0, 0, 400, 60];
142
143 let mut row = SettingRow::new(LibraryInfo(0), rect, &settings, &mut context.fonts);
144
145 let (hub, _receiver) = channel();
146 let mut bus = VecDeque::new();
147 let mut rq = RenderQueue::new();
148
149 let updated_library = LibrarySettings {
150 name: "Updated Library Name".to_string(),
151 path: PathBuf::from("/tmp/updated"),
152 ..Default::default()
153 };
154
155 let event = Event::UpdateLibrary(0, Box::new(updated_library));
156 let handled = row.handle_event(&event, &hub, &mut bus, &mut rq, &mut context);
157
158 assert!(handled);
159 assert!(!rq.is_empty());
160 }
161
162 #[test]
163 fn test_update_library_event_ignores_non_matching() {
164 let mut context = create_test_context();
165 let settings = create_test_settings();
166 let rect = rect![0, 0, 400, 60];
167
168 let mut row = SettingRow::new(LibraryInfo(0), rect, &settings, &mut context.fonts);
169
170 let (hub, _receiver) = channel();
171 let mut bus = VecDeque::new();
172 let mut rq = RenderQueue::new();
173
174 let updated_library = LibrarySettings {
175 name: "Updated Library 1".to_string(),
176 path: PathBuf::from("/tmp/lib1_updated"),
177 ..Default::default()
178 };
179
180 let event = Event::UpdateLibrary(1, Box::new(updated_library));
181 let handled = row.handle_event(&event, &hub, &mut bus, &mut rq, &mut context);
182
183 assert!(!handled);
184 assert!(rq.is_empty());
185 }
186}