1use std::sync::{
39 Arc,
40 atomic::{AtomicBool, Ordering},
41};
42
43use crate::{
44 buffer::Buffer,
45 context::Handle,
46 data::{Pass, RwData},
47 form,
48 hook::{self, BufferPrinted, FocusedOn, OnMouseEvent, UnfocusedFrom},
49 mode::{ToggleEvent, TwoPointsPlace},
50 opts::PrintOpts,
51 session::UiMouseEvent,
52 text::{Text, TextMut},
53 ui::{PrintInfo, RwArea},
54};
55
56#[allow(unused)]
66pub trait Widget: Send + 'static {
67 fn text(&self) -> &Text;
69
70 fn text_mut(&mut self) -> TextMut<'_>;
72
73 fn print_opts(&self) -> PrintOpts {
80 PrintOpts::new()
81 }
82}
83
84#[derive(Clone)]
86pub(crate) struct Node {
87 handle: Handle<dyn Widget>,
88 print: Arc<dyn Fn(&mut Pass, &Handle<dyn Widget>) + Send + Sync>,
89 on_focus: Arc<dyn Fn(&mut Pass, Handle<dyn Widget>) + Send + Sync>,
90 on_unfocus: Arc<dyn Fn(&mut Pass, Handle<dyn Widget>) + Send + Sync>,
91 on_mouse_event: Arc<dyn Fn(&mut Pass, UiMouseEvent) + Send + Sync>,
92}
93
94impl Node {
95 pub(crate) fn new<W: Widget>(
97 widget: RwData<W>,
98 area: RwArea,
99 master: Option<Handle<dyn Widget>>,
100 is_closed: Arc<AtomicBool>,
101 ) -> Self {
102 Self::from_handle(Handle::new(widget, area, master, is_closed))
103 }
104
105 pub(crate) fn from_handle<W: Widget>(handle: Handle<W>) -> Self {
107 Self {
108 handle: handle.to_dyn(),
109 print: if let Some(buffer) = handle.try_downcast::<Buffer>() {
110 let handle = handle.clone();
111
112 Arc::new(move |pa, orig_handle| {
113 Buffer::update(pa, &buffer);
114
115 handle.area.print(
116 pa,
117 handle.text(pa),
118 handle.opts(pa),
119 form::painter_with_widget::<W>(),
120 );
121
122 hook::trigger(pa, BufferPrinted(buffer.clone()));
123 orig_handle.declare_as_read();
124 orig_handle.area().0.declare_as_read();
125 })
126 } else {
127 let handle = handle.clone();
128 Arc::new(move |pa, _| {
129 handle.area.print(
130 pa,
131 handle.text(pa),
132 handle.opts(pa),
133 form::painter_with_widget::<W>(),
134 );
135 })
136 },
137 on_focus: Arc::new({
138 let handle = handle.clone();
139 move |pa, old| _ = hook::trigger(pa, FocusedOn((old, handle.clone())))
140 }),
141 on_unfocus: Arc::new({
142 let handle = handle.clone();
143 move |pa, new| _ = hook::trigger(pa, UnfocusedFrom((handle.clone(), new)))
144 }),
145 on_mouse_event: Arc::new({
146 let handle = handle.clone();
147 let dyn_handle = handle.to_dyn();
148 move |pa, event| {
149 let opts = handle.opts(pa);
150 let text = handle.text(pa);
151
152 let points = handle.area().points_at_coord(pa, text, event.coord, opts);
153
154 hook::trigger(pa, OnMouseEvent {
155 handle: dyn_handle.clone(),
156 points,
157 coord: event.coord,
158 kind: event.kind,
159 modifiers: event.modifiers,
160 });
161 hook::trigger(pa, OnMouseEvent {
162 handle: handle.clone(),
163 points,
164 coord: event.coord,
165 kind: event.kind,
166 modifiers: event.modifiers,
167 });
168
169 if let Some(TwoPointsPlace::Within(points)) = points {
170 let event = ToggleEvent {
171 handle: &dyn_handle,
172 points,
173 coord: event.coord,
174 kind: event.kind,
175 modifiers: event.modifiers,
176 };
177 let toggles = handle.text(pa).toggles_surrounding(points.real);
178
179 crate::utils::catch_panic(|| {
180 for (range, toggle_fn) in toggles {
181 toggle_fn.lock().unwrap()(pa, event, range);
182 }
183 });
184 }
185 }
186 }),
187 }
188 }
189
190 pub(crate) fn read_as<'a, W: Widget>(&'a self, pa: &'a Pass) -> Option<&'a W> {
193 self.handle.read_as(pa)
194 }
195
196 pub(crate) fn widget(&self) -> &RwData<dyn Widget> {
198 self.handle.widget()
199 }
200
201 pub(crate) fn area(&self) -> &RwArea {
203 self.handle.area()
204 }
205
206 pub(crate) fn try_downcast<W: Widget>(&self) -> Option<Handle<W>> {
208 self.handle.try_downcast()
209 }
210
211 pub(crate) fn handle(&self) -> &Handle<dyn Widget> {
213 &self.handle
214 }
215
216 pub(crate) fn data_is<W: 'static>(&self) -> bool {
220 self.handle.widget().is::<W>()
221 }
222
223 pub(crate) fn ptr_eq<W: ?Sized>(&self, other: &RwData<W>) -> bool {
225 self.handle.ptr_eq(other)
226 }
227
228 pub(crate) fn needs_update(&self, pa: &Pass) -> bool {
230 self.handle.update_requested.load(Ordering::Relaxed)
231 || self.handle.widget().has_changed()
232 || self.handle.area.has_changed(pa)
233 }
234
235 pub(crate) fn print(&self, pa: &mut Pass, win: usize) {
239 self.handle.update_requested.store(false, Ordering::Relaxed);
240
241 crate::context::windows().cleanup_despawned(pa);
242 if self.handle().is_closed() {
243 return;
244 }
245
246 let print_info = self.handle.area().get_print_info(pa);
247 let (widget, _) = self.handle.write_with_area(pa);
248
249 if print_info != PrintInfo::default() {
250 widget.text_mut().update_bounds();
251 }
252
253 let widgets_to_spawn = widget.text_mut().get_widget_spawns();
254 for (_, spawn) in widgets_to_spawn {
255 spawn(pa, win, self.handle.clone());
256 }
257
258 (self.print)(pa, &self.handle);
259 }
260
261 pub(crate) fn on_focus(&self, pa: &mut Pass, old: Handle<dyn Widget>) {
263 self.handle.area().set_as_active(pa);
264 (self.on_focus)(pa, old)
265 }
266
267 pub(crate) fn on_unfocus(&self, pa: &mut Pass, new: Handle<dyn Widget>) {
269 (self.on_unfocus)(pa, new)
270 }
271
272 pub(crate) fn on_mouse_event(&self, pa: &mut Pass, mouse_event: UiMouseEvent) {
273 (self.on_mouse_event)(pa, mouse_event);
274 }
275}
276
277impl std::fmt::Debug for Node {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 f.debug_struct("Node")
280 .field("handle", &self.handle)
281 .finish_non_exhaustive()
282 }
283}