1use crate::dirty::Dirty;
2use crate::event::{Command, Event, EventPhase};
3use crate::geom::{Rect, Size};
4use crate::layout::Constraint;
5use crate::node::Node;
6use crate::render::RenderCx;
7use crate::style::Style;
8
9pub trait Component {
11 fn render(&self, cx: &mut RenderCx);
13
14 fn event(&mut self, _event: &Event, _cx: &mut EventCx) {}
16
17 fn style(&self) -> Style {
19 Style::default()
20 }
21
22 fn measure(&self, constraint: Constraint, _cx: &mut MeasureCx) -> Size {
26 Size {
27 width: constraint.max.width,
28 height: 1,
29 }
30 }
31
32 fn layout(&mut self, _rect: Rect, _cx: &mut LayoutCx) {}
36
37 fn mount(&mut self, _cx: &mut EventCx) {}
39 fn unmount(&mut self, _cx: &mut EventCx) {}
41 fn update(&mut self, _cx: &mut EventCx) {}
43
44 fn type_name(&self) -> &str {
46 std::any::type_name::<Self>()
47 .split("::")
48 .last()
49 .unwrap_or("Unknown")
50 }
51
52 fn id(&self) -> Option<&str> {
54 None
55 }
56
57 fn class(&self) -> Option<&str> {
59 None
60 }
61
62 fn focusable(&self) -> bool {
64 true
65 }
66
67 fn for_each_child(&self, _f: &mut dyn FnMut(&Node)) {}
69
70 fn for_each_child_mut(&mut self, _f: &mut dyn FnMut(&mut Node)) {}
72}
73
74pub struct EventCx<'a> {
79 pub(crate) node_dirty: &'a mut Dirty,
80 pub(crate) global_dirty: &'a mut Dirty,
81 pub(crate) quit: &'a mut bool,
82 pub(crate) phase: EventPhase,
83 pub(crate) propagation_stopped: &'a mut bool,
84 pub(crate) task_sender: Option<std::sync::mpsc::Sender<String>>,
85 pub(crate) current_node_id: crate::node::NodeId,
87}
88
89impl<'a> EventCx<'a> {
90 pub(crate) fn new(
91 node_dirty: &'a mut Dirty,
92 global_dirty: &'a mut Dirty,
93 quit: &'a mut bool,
94 phase: EventPhase,
95 propagation_stopped: &'a mut bool,
96 ) -> Self {
97 Self {
98 node_dirty,
99 global_dirty,
100 quit,
101 phase,
102 propagation_stopped,
103 task_sender: None,
104 current_node_id: crate::node::NodeId::ROOT,
105 }
106 }
107
108 pub(crate) fn with_task_sender(
109 node_dirty: &'a mut Dirty,
110 global_dirty: &'a mut Dirty,
111 quit: &'a mut bool,
112 phase: EventPhase,
113 propagation_stopped: &'a mut bool,
114 task_sender: Option<std::sync::mpsc::Sender<String>>,
115 ) -> Self {
116 Self {
117 node_dirty,
118 global_dirty,
119 quit,
120 phase,
121 propagation_stopped,
122 task_sender,
123 current_node_id: crate::node::NodeId::ROOT,
124 }
125 }
126
127 pub fn phase(&self) -> EventPhase {
129 self.phase
130 }
131
132 pub fn stop_propagation(&mut self) {
134 *self.propagation_stopped = true;
135 }
136
137 pub fn invalidate_paint(&mut self) {
139 *self.node_dirty |= Dirty::PAINT;
140 *self.global_dirty |= Dirty::PAINT;
141 }
142
143 pub fn invalidate_layout(&mut self) {
145 *self.node_dirty |= Dirty::LAYOUT | Dirty::PAINT;
146 *self.global_dirty |= Dirty::LAYOUT | Dirty::PAINT;
147 }
148
149 pub fn invalidate(&mut self) {
151 self.invalidate_layout();
152 }
153
154 pub fn invalidate_tree(&mut self) {
156 *self.node_dirty |= Dirty::TREE | Dirty::LAYOUT | Dirty::PAINT;
157 *self.global_dirty |= Dirty::TREE | Dirty::LAYOUT | Dirty::PAINT;
158 }
159
160 pub fn copy_to_clipboard(&self, text: &str) {
165 use std::io::Write;
166 let seq = crate::clipboard::copy_to_clipboard_sequence(text);
167 let _ = std::io::stdout().write_all(seq.as_bytes());
168 let _ = std::io::stdout().flush();
169 }
170
171 pub fn quit(&mut self) {
173 *self.quit = true;
174 }
175
176 pub fn dispatch(&mut self, cmd: Command) {
178 crate::runtime::COMMAND_QUEUE.with(|q| {
179 q.borrow_mut().push(cmd);
180 });
181 }
182
183 pub fn toggle_debug() {
185 crate::runtime::DEBUG_MODE.with(|d| {
186 let current = *d.borrow();
187 *d.borrow_mut() = !current;
188 });
189 }
190
191 pub fn spawn<F>(&mut self, task: F)
193 where
194 F: FnOnce() -> String + Send + 'static,
195 {
196 if let Some(tx) = self.task_sender.clone() {
197 std::thread::spawn(move || {
198 let result = task();
199 let _ = tx.send(result);
200 });
201 }
202 }
203
204 pub fn spawn_worker<F>(&mut self, task: F) -> crate::event::WorkerId
206 where
207 F: FnOnce() -> String + Send + 'static,
208 {
209 use crate::event::WorkerId;
210 use crate::runtime::WORKER_REGISTRY;
211 use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
212
213 let id = WORKER_REGISTRY.with(|r| {
214 let mut r = r.borrow_mut();
215 let id = WorkerId(r.next_id);
216 r.next_id += 1;
217 id
218 });
219
220 let cancel_flag = Arc::new(AtomicBool::new(false));
221 WORKER_REGISTRY.with(|r| {
222 r.borrow_mut().flags.insert(id, cancel_flag.clone());
223 });
224
225 if let Some(tx) = self.task_sender.clone() {
226 let flag = cancel_flag.clone();
227 std::thread::spawn(move || {
228 if flag.load(Ordering::Relaxed) {
229 let _ = tx.send(format!("__worker_cancelled__{}", id.0));
230 return;
231 }
232 let result = task();
233 if flag.load(Ordering::Relaxed) {
234 let _ = tx.send(format!("__worker_cancelled__{}", id.0));
235 return;
236 }
237 let _ = tx.send(format!("__worker_done__{}__{}", id.0, result));
238 });
239 }
240
241 id
242 }
243
244 pub fn cancel_worker(&mut self, id: crate::event::WorkerId) {
246 use std::sync::atomic::Ordering;
247 crate::runtime::WORKER_REGISTRY.with(|r| {
248 let r = r.borrow();
249 if let Some(flag) = r.flags.get(&id) {
250 flag.store(true, Ordering::Relaxed);
251 }
252 });
253 }
254
255 pub fn set_timer(&mut self, duration_ms: u64) -> u64 {
259 crate::runtime::TIMER_QUEUE.with(|q| {
260 let mut q = q.borrow_mut();
261 let id = q.next_id;
262 q.next_id += 1;
263 q.requests.push(crate::runtime::TimerRequest {
264 action: crate::runtime::TimerAction::SetOneShot { id, duration_ms },
265 owner: self.current_node_id,
266 });
267 id
268 })
269 }
270
271 pub fn set_interval(&mut self, interval_ms: u64) -> u64 {
276 crate::runtime::TIMER_QUEUE.with(|q| {
277 let mut q = q.borrow_mut();
278 let id = q.next_id;
279 q.next_id += 1;
280 q.requests.push(crate::runtime::TimerRequest {
281 action: crate::runtime::TimerAction::SetInterval { id, interval_ms },
282 owner: self.current_node_id,
283 });
284 id
285 })
286 }
287
288 pub fn cancel_timer(&mut self, timer_id: u64) {
291 crate::runtime::TIMER_QUEUE.with(|q| {
292 q.borrow_mut().requests.push(crate::runtime::TimerRequest {
293 action: crate::runtime::TimerAction::Cancel { id: timer_id },
294 owner: self.current_node_id,
295 });
296 })
297 }
298}
299
300pub struct MeasureCx {
302 pub constraint: Constraint,
303}
304
305pub struct LayoutCx<'a> {
307 children: &'a mut Vec<Node>,
308}
309
310impl<'a> LayoutCx<'a> {
311 pub(crate) fn new(children: &'a mut Vec<Node>) -> Self {
312 Self { children }
313 }
314
315 pub fn child_count(&self) -> usize {
317 self.children.len()
318 }
319
320 pub fn child_style(&self, index: usize) -> Option<Style> {
322 self.children.get(index).map(|n| n.component.style())
323 }
324
325 pub fn layout_child(&mut self, index: usize, rect: Rect) {
327 if let Some(child) = self.children.get_mut(index) {
328 child.layout(rect);
329 }
330 }
331
332 pub fn for_each_child(&mut self, mut f: impl FnMut(usize, &mut Node)) {
334 for (i, child) in self.children.iter_mut().enumerate() {
335 f(i, child);
336 }
337 }
338}