1use std::{
2 any::Any,
3 collections::HashMap,
4 ops::{Deref, DerefMut, Range},
5};
6
7use glam::Vec2;
8use ori_graphics::{
9 Frame, ImageHandle, ImageSource, Quad, Rect, Renderer, TextHit, TextSection, WeakImageHandle,
10};
11
12use crate::{
13 BoxConstraints, EventSink, FromStyleAttribute, NodeState, RequestRedrawEvent, SendSync,
14 StyleAttribute, StyleSelectors, StyleSpecificity, Stylesheet, Unit,
15};
16
17#[derive(Clone, Debug, Default)]
18pub struct ImageCache {
19 images: HashMap<ImageSource, WeakImageHandle>,
20}
21
22impl ImageCache {
23 pub fn new() -> Self {
24 Self::default()
25 }
26
27 pub fn len(&self) -> usize {
28 self.images.len()
29 }
30
31 pub fn is_empty(&self) -> bool {
32 self.images.is_empty()
33 }
34
35 pub fn get(&self, source: &ImageSource) -> Option<ImageHandle> {
36 self.images.get(source)?.upgrade()
37 }
38
39 pub fn insert(&mut self, source: ImageSource, handle: ImageHandle) {
40 self.images.insert(source, handle.downgrade());
41 }
42
43 pub fn clear(&mut self) {
44 self.images.clear();
45 }
46
47 pub fn clean(&mut self) {
48 self.images.retain(|_, v| v.is_alive());
49 }
50}
51
52pub struct EventContext<'a> {
53 pub style: &'a Stylesheet,
54 pub state: &'a mut NodeState,
55 pub renderer: &'a dyn Renderer,
56 pub selectors: &'a StyleSelectors,
57 pub event_sink: &'a EventSink,
58 pub image_cache: &'a mut ImageCache,
59}
60
61pub struct LayoutContext<'a> {
62 pub style: &'a Stylesheet,
63 pub state: &'a mut NodeState,
64 pub renderer: &'a dyn Renderer,
65 pub selectors: &'a StyleSelectors,
66 pub event_sink: &'a EventSink,
67 pub image_cache: &'a mut ImageCache,
68}
69
70impl<'a> LayoutContext<'a> {
71 pub fn style_constraints(&mut self, bc: BoxConstraints) -> BoxConstraints {
72 let min_width = self.style_range_group("min-width", "width", bc.width());
73 let max_width = self.style_range_group("max-width", "width", bc.width());
74
75 let min_height = self.style_range_group("min-height", "height", bc.height());
76 let max_height = self.style_range_group("max-height", "height", bc.height());
77
78 let min_size = bc.constrain(Vec2::new(min_width, min_height));
79 let max_size = bc.constrain(Vec2::new(max_width, max_height));
80
81 BoxConstraints::new(min_size, max_size)
82 }
83
84 pub fn messure_text(&self, section: &TextSection) -> Option<Rect> {
85 self.renderer.messure_text(section)
86 }
87
88 pub fn hit_text(&self, section: &TextSection, pos: Vec2) -> Option<TextHit> {
89 self.renderer.hit_text(section, pos)
90 }
91}
92
93pub struct DrawLayer<'a, 'b> {
94 draw_context: &'b mut DrawContext<'a>,
95 depth: f32,
96 clip: Option<Rect>,
97}
98
99impl<'a, 'b> DrawLayer<'a, 'b> {
100 pub fn depth(mut self, depth: f32) -> Self {
101 self.depth = depth;
102 self
103 }
104
105 pub fn clip(mut self, clip: Rect) -> Self {
106 self.clip = Some(clip.round());
107 self
108 }
109
110 pub fn draw(self, f: impl FnOnce(&mut DrawContext)) {
111 let layer = self
112 .draw_context
113 .frame
114 .layer()
115 .depth(self.depth)
116 .clip(self.clip);
117
118 layer.draw(|frame| {
119 let mut child = DrawContext {
120 style: self.draw_context.style,
121 state: self.draw_context.state,
122 frame,
123 renderer: self.draw_context.renderer,
124 selectors: self.draw_context.selectors,
125 event_sink: self.draw_context.event_sink,
126 image_cache: self.draw_context.image_cache,
127 };
128
129 f(&mut child);
130 });
131 }
132}
133
134pub struct DrawContext<'a> {
135 pub style: &'a Stylesheet,
136 pub state: &'a mut NodeState,
137 pub frame: &'a mut Frame,
138 pub renderer: &'a dyn Renderer,
139 pub selectors: &'a StyleSelectors,
140 pub event_sink: &'a EventSink,
141 pub image_cache: &'a mut ImageCache,
142}
143
144impl<'a> DrawContext<'a> {
145 pub fn frame(&mut self) -> &mut Frame {
146 self.frame
147 }
148
149 pub fn layer<'b>(&'b mut self) -> DrawLayer<'a, 'b> {
150 DrawLayer {
151 draw_context: self,
152 depth: 1.0,
153 clip: None,
154 }
155 }
156
157 pub fn draw_layer(&mut self, f: impl FnOnce(&mut DrawContext)) {
161 self.layer().draw(f);
162 }
163
164 pub fn draw_quad(&mut self) {
176 let range = 0.0..self.rect().max.min_element() / 2.0;
177
178 let tl = "border-top-left-radius";
179 let tr = "border-top-right-radius";
180 let br = "border-bottom-right-radius";
181 let bl = "border-bottom-left-radius";
182
183 let tl = self.style_range_group(tl, "border-radius", range.clone());
184 let tr = self.style_range_group(tr, "border-radius", range.clone());
185 let br = self.style_range_group(br, "border-radius", range.clone());
186 let bl = self.style_range_group(bl, "border-radius", range.clone());
187
188 let quad = Quad {
189 rect: self.rect(),
190 background: self.style("background-color"),
191 border_radius: [tl, tr, br, bl],
192 border_width: self.style_range("border-width", range),
193 border_color: self.style("border-color"),
194 };
195
196 self.draw(quad);
197 }
198}
199
200impl<'a> Deref for DrawContext<'a> {
201 type Target = Frame;
202
203 fn deref(&self) -> &Self::Target {
204 self.frame
205 }
206}
207
208impl<'a> DerefMut for DrawContext<'a> {
209 fn deref_mut(&mut self) -> &mut Self::Target {
210 self.frame
211 }
212}
213
214pub trait Context {
215 fn stylesheet(&self) -> &Stylesheet;
216 fn state(&self) -> &NodeState;
217 fn state_mut(&mut self) -> &mut NodeState;
218 fn renderer(&self) -> &dyn Renderer;
219 fn selectors(&self) -> &StyleSelectors;
220 fn event_sink(&self) -> &EventSink;
221 fn image_cache(&self) -> &ImageCache;
222 fn image_cache_mut(&mut self) -> &mut ImageCache;
223
224 fn get_style_attribute(&self, key: &str) -> Option<StyleAttribute> {
225 if let Some(attribute) = self.state().style.attributes.get(key) {
226 return Some(attribute.clone());
227 }
228
229 let attribute = self.stylesheet().get_attribute(self.selectors(), key)?;
230 Some(attribute.clone())
231 }
232
233 fn get_style_attribute_specificity(
234 &self,
235 key: &str,
236 ) -> Option<(StyleAttribute, StyleSpecificity)> {
237 if let Some(attribute) = self.state().style.attributes.get(key) {
238 return Some((attribute.clone(), StyleSpecificity::INLINE));
239 }
240
241 let stylesheet = self.stylesheet();
242 let selectors = self.selectors();
243 let (attribute, specificity) = stylesheet.get_attribute_specificity(selectors, key)?;
244 Some((attribute.clone(), specificity))
245 }
246
247 fn get_style<T: FromStyleAttribute + 'static>(&mut self, key: &str) -> Option<T> {
248 let attribute = self.get_style_attribute(key)?;
249 let value = T::from_attribute(attribute.value)?;
250 let transition = attribute.transition;
251
252 Some(self.state_mut().transition(key, value, transition))
253 }
254
255 fn get_style_specificity<T: FromStyleAttribute + 'static>(
256 &mut self,
257 key: &str,
258 ) -> Option<(T, StyleSpecificity)> {
259 let (attribute, specificity) = self.get_style_attribute_specificity(key)?;
260 let value = T::from_attribute(attribute.value)?;
261 let transition = attribute.transition;
262
263 Some((
264 self.state_mut().transition(key, value, transition),
265 specificity,
266 ))
267 }
268
269 #[track_caller]
272 fn style<T: FromStyleAttribute + Default + 'static>(&mut self, key: &str) -> T {
273 self.get_style(key).unwrap_or_default()
274 }
275
276 fn style_group<T: FromStyleAttribute + Default + 'static>(
277 &mut self,
278 primary_key: &str,
279 secondary_key: &str,
280 ) -> T {
281 let primary = self.get_style_specificity(primary_key);
282 let secondary = self.get_style_specificity(secondary_key);
283
284 match (primary, secondary) {
285 (Some((primary, primary_specificity)), Some((secondary, secondary_specificity))) => {
286 if primary_specificity >= secondary_specificity {
287 primary
288 } else {
289 secondary
290 }
291 }
292 (Some((value, _)), None) | (None, Some((value, _))) => value,
293 _ => T::default(),
294 }
295 }
296
297 fn get_style_range(&mut self, key: &str, range: Range<f32>) -> Option<f32> {
298 let attribute = self.get_style_attribute(key)?;
299 let value = Unit::from_attribute(attribute.value)?;
300 let transition = attribute.transition;
301
302 let pixels = value.pixels(
303 range,
304 self.renderer().scale(),
305 self.renderer().window_size(),
306 );
307
308 Some((self.state_mut()).transition(key, pixels, transition))
309 }
310
311 fn get_style_range_specificity(
312 &mut self,
313 key: &str,
314 range: Range<f32>,
315 ) -> Option<(f32, StyleSpecificity)> {
316 let (attribute, specificity) = self.get_style_attribute_specificity(key)?;
317 let value = Unit::from_attribute(attribute.value)?;
318 let transition = attribute.transition;
319
320 let pixels = value.pixels(
321 range,
322 self.renderer().scale(),
323 self.renderer().window_size(),
324 );
325
326 Some((
327 (self.state_mut()).transition(key, pixels, transition),
328 specificity,
329 ))
330 }
331
332 #[track_caller]
338 fn style_range(&mut self, key: &str, range: Range<f32>) -> f32 {
339 self.get_style_range(key, range).unwrap_or_default()
340 }
341
342 fn style_range_group(
343 &mut self,
344 primary_key: &str,
345 secondary_key: &str,
346 range: Range<f32>,
347 ) -> f32 {
348 let primary = self.get_style_range_specificity(primary_key, range.clone());
349 let secondary = self.get_style_range_specificity(secondary_key, range);
350
351 match (primary, secondary) {
352 (Some((primary, primary_specificity)), Some((secondary, secondary_specificity))) => {
353 if primary_specificity >= secondary_specificity {
354 primary
355 } else {
356 secondary
357 }
358 }
359 (Some((value, _)), None) | (None, Some((value, _))) => value,
360 _ => 0.0,
361 }
362 }
363
364 fn downcast_renderer<T: Renderer>(&self) -> Option<&T> {
365 self.renderer().downcast_ref()
366 }
367
368 fn load_image(&mut self, source: &ImageSource) -> ImageHandle {
369 if let Some(handle) = self.image_cache().get(source) {
370 return handle;
371 }
372
373 let data = source.load();
374 let image = self.renderer().create_image(&data);
375 self.image_cache_mut().insert(source.clone(), image.clone());
376 image
377 }
378
379 fn active(&self) -> bool {
380 self.state().active
381 }
382
383 fn hovered(&self) -> bool {
384 self.state().hovered
385 }
386
387 fn focused(&self) -> bool {
388 self.state().focused
389 }
390
391 fn focus(&mut self) {
392 if self.focused() {
393 return;
394 }
395
396 self.state_mut().focused = true;
397 self.request_redraw();
398 }
399
400 fn unfocus(&mut self) {
401 if !self.focused() {
402 return;
403 }
404
405 self.state_mut().focused = false;
406 self.request_redraw();
407 }
408
409 fn activate(&mut self) {
410 if self.active() {
411 return;
412 }
413
414 self.state_mut().active = true;
415 self.request_redraw();
416 }
417
418 fn deactivate(&mut self) {
419 if !self.active() {
420 return;
421 }
422
423 self.state_mut().active = false;
424 self.request_redraw();
425 }
426
427 fn local_rect(&self) -> Rect {
428 self.state().local_rect
429 }
430
431 fn rect(&self) -> Rect {
432 self.state().global_rect
433 }
434
435 fn size(&self) -> Vec2 {
436 self.state().local_rect.size()
437 }
438
439 fn request_redraw(&mut self) {
440 self.send_event(RequestRedrawEvent);
441 }
442
443 fn send_event(&self, event: impl Any + SendSync) {
444 self.event_sink().send(event);
445 }
446
447 fn delta_time(&self) -> f32 {
448 self.state().delta()
449 }
450}
451
452macro_rules! context {
453 ($name:ident) => {
454 impl<'a> Context for $name<'a> {
455 fn stylesheet(&self) -> &Stylesheet {
456 self.style
457 }
458
459 fn state(&self) -> &NodeState {
460 self.state
461 }
462
463 fn state_mut(&mut self) -> &mut NodeState {
464 self.state
465 }
466
467 fn renderer(&self) -> &dyn Renderer {
468 self.renderer
469 }
470
471 fn selectors(&self) -> &StyleSelectors {
472 &self.selectors
473 }
474
475 fn event_sink(&self) -> &EventSink {
476 &self.event_sink
477 }
478
479 fn image_cache(&self) -> &ImageCache {
480 &self.image_cache
481 }
482
483 fn image_cache_mut(&mut self) -> &mut ImageCache {
484 &mut self.image_cache
485 }
486 }
487 };
488}
489
490context!(EventContext);
491context!(LayoutContext);
492context!(DrawContext);