1use {
2 std::collections::hash_map::HashMap,
3 crate::{
4 makepad_derive_widget::*,
5 makepad_draw::*,
6 widget::*,
7 scroll_bars::ScrollBars,
8 },
9};
10
11live_design!{
12 ViewBase = {{View}} {}
13}
14
15#[derive(Live, LiveHook)]
18#[live_ignore]
19pub enum ViewOptimize {
20 #[pick] None,
21 DrawList,
22 Texture
23}
24
25
26#[derive(Live, LiveHook)]
27#[live_ignore]
28pub enum EventOrder {
29 Down,
30 #[pick] Up,
31 #[live(Default::default())] List(Vec<LiveId>),
32}
33
34
35impl ViewOptimize {
36 fn is_texture(&self) -> bool {
37 if let Self::Texture = self {true} else {false}
38 }
39 fn is_draw_list(&self) -> bool {
40 if let Self::DrawList = self {true} else {false}
41 }
42 fn needs_draw_list(&self) -> bool {
43 return self.is_texture() || self.is_draw_list()
44 }
45}
46
47#[derive(Live)]
48pub struct View { #[live] draw_bg: DrawColor,
50
51 #[live(false)] show_bg: bool,
52
53 #[layout] layout: Layout,
54
55 #[walk] walk: Walk,
56
57 #[live] dpi_factor: Option<f64>,
59
60 #[live] optimize: ViewOptimize,
61 #[live] event_order: EventOrder,
62
63 #[live(true)] visible: bool,
64
65 #[live(true)] grab_key_focus: bool,
66 #[live(false)] block_signal_event: bool,
67 #[live] cursor: Option<MouseCursor>,
68 #[live] scroll_bars: Option<LivePtr>,
69 #[live(false)] design_mode: bool,
70
71 #[rust] find_cache: HashMap<u64, WidgetSet>,
72
73 #[rust] scroll_bars_obj: Option<Box<ScrollBars >>,
74 #[rust] view_size: Option<DVec2>,
75
76 #[rust] area: Area,
77 #[rust] draw_list: Option<DrawList2d>,
78
79 #[rust] texture_cache: Option<ViewTextureCache>,
80 #[rust] defer_walks: Vec<(LiveId, DeferWalk)>,
81 #[rust] draw_state: DrawStateWrap<DrawState>,
82 #[rust] children: ComponentMap<LiveId, WidgetRef>,
83 #[rust] draw_order: Vec<LiveId>,
84
85 #[animator] animator: Animator,
86}
87
88struct ViewTextureCache {
89 pass: Pass,
90 _depth_texture: Texture,
91 color_texture: Texture,
92}
93
94impl LiveHook for View {
95 fn before_live_design(cx: &mut Cx) {
96 register_widget!(cx, View)
97 }
98
99 fn before_apply(&mut self, _cx: &mut Cx, from: ApplyFrom, _index: usize, _nodes: &[LiveNode]) {
100 if let ApplyFrom::UpdateFromDoc {..} = from {
101 self.draw_order.clear();
103 self.find_cache.clear();
104 }
105 }
106
107 fn after_apply(&mut self, cx: &mut Cx, _from: ApplyFrom, _index: usize, _nodes: &[LiveNode]) {
108 if self.optimize.needs_draw_list() && self.draw_list.is_none() {
109 self.draw_list = Some(DrawList2d::new(cx));
110 }
111 if self.scroll_bars.is_some() {
112 if self.scroll_bars_obj.is_none() {
113 self.scroll_bars_obj = Some(Box::new(ScrollBars::new_from_ptr(cx, self.scroll_bars)));
114 }
115 }
116 }
129
130 fn apply_value_instance(&mut self, cx: &mut Cx, from: ApplyFrom, index: usize, nodes: &[LiveNode]) -> usize {
131 let id = nodes[index].id;
137 match from {
138 ApplyFrom::Animate | ApplyFrom::ApplyOver => {
139 if let Some(component) = self.children.get_mut(&nodes[index].id) {
140 component.apply(cx, from, index, nodes)
141 }
142 else {
143 nodes.skip_node(index)
144 }
145 }
146 ApplyFrom::NewFromDoc {..} | ApplyFrom::UpdateFromDoc {..} => {
147 if nodes[index].origin.has_prop_type(LivePropType::Instance) {
148 self.draw_order.push(id);
149 return self.children.get_or_insert(cx, id, | cx | {
150 WidgetRef::new(cx)
151 })
152 .apply(cx, from, index, nodes);
153 }
154 else {
155 cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
156 nodes.skip_node(index)
157 }
158 }
159 _ => {
160 nodes.skip_node(index)
161 }
162 }
163 }
164}
165
166#[derive(Clone, PartialEq, WidgetRef)]
167pub struct ViewRef(WidgetRef);
168
169
170#[derive(Clone, WidgetSet)]
171pub struct ViewSet(WidgetSet);
172
173#[derive(Clone, WidgetAction)]
174pub enum ViewAction {
175 None,
176 FingerDown(FingerDownEvent),
177 FingerUp(FingerUpEvent),
178 FingerMove(FingerMoveEvent),
179 KeyDown(KeyEvent),
180 KeyUp(KeyEvent),
181}
182
183impl ViewRef {
184 pub fn finger_down(&self, actions: &WidgetActions) -> Option<FingerDownEvent> {
185 if let Some(item) = actions.find_single_action(self.widget_uid()) {
186 if let ViewAction::FingerDown(fd) = item.action() {
187 return Some(fd)
188 }
189 }
190 None
191 }
192
193 pub fn finger_up(&self, actions: &WidgetActions) -> Option<FingerUpEvent> {
194 if let Some(item) = actions.find_single_action(self.widget_uid()) {
195 if let ViewAction::FingerUp(fd) = item.action() {
196 return Some(fd)
197 }
198 }
199 None
200 }
201
202 pub fn finger_move(&self, actions: &WidgetActions) -> Option<FingerMoveEvent> {
203 if let Some(item) = actions.find_single_action(self.widget_uid()) {
204 if let ViewAction::FingerMove(fd) = item.action() {
205 return Some(fd)
206 }
207 }
208 None
209 }
210
211 pub fn key_down(&self, actions: &WidgetActions) -> Option<KeyEvent> {
212 if let Some(item) = actions.find_single_action(self.widget_uid()) {
213 if let ViewAction::KeyDown(fd) = item.action() {
214 return Some(fd)
215 }
216 }
217 None
218 }
219
220 pub fn key_up(&self, actions: &WidgetActions) -> Option<KeyEvent> {
221 if let Some(item) = actions.find_single_action(self.widget_uid()) {
222 if let ViewAction::KeyUp(fd) = item.action() {
223 return Some(fd)
224 }
225 }
226 None
227 }
228
229 pub fn cut_state(&self, cx: &mut Cx, state: &[LiveId; 2]) {
230 if let Some(mut inner) = self.borrow_mut() {
231 inner.animator_cut(cx, state);
232 }
233 }
234
235 pub fn animator_play(&self, cx: &mut Cx, state: &[LiveId; 2]) {
236 if let Some(mut inner) = self.borrow_mut() {
237 inner.animator_play(cx, state);
238 }
239 }
240
241 pub fn toggle_state(&self, cx: &mut Cx, is_state_1: bool, animate: Animate, state1: &[LiveId; 2], state2: &[LiveId; 2]) {
242 if let Some(mut inner) = self.borrow_mut() {
243 inner.animator_toggle(cx, is_state_1, animate, state1, state2);
244 }
245 }
246
247 pub fn set_visible(&self, visible: bool) {
248 if let Some(mut inner) = self.borrow_mut() {
249 inner.visible = visible
250 }
251 }
252
253
254 pub fn set_visible_and_redraw(&self, cx: &mut Cx, visible: bool) {
255 if let Some(mut inner) = self.borrow_mut() {
256 inner.visible = visible;
257 inner.redraw(cx);
258 }
259 }
260
261 pub fn visible(&self) -> bool {
262 if let Some(inner) = self.borrow() {
263 inner.visible
264 }
265 else {
266 false
267 }
268 }
269
270 pub fn set_texture(&self, slot: usize, texture: &Texture) {
271 if let Some(mut inner) = self.borrow_mut() {
272 inner.draw_bg.set_texture(slot, texture);
273 }
274 }
275
276 pub fn set_uniform(&self, cx: &Cx, uniform: &[LiveId], value: &[f32]) {
277 if let Some(mut inner) = self.borrow_mut() {
278 inner.draw_bg.set_uniform(cx, uniform, value);
279 }
280 }
281
282 pub fn set_scroll_pos(&self, cx: &mut Cx, v: DVec2) {
283 if let Some(mut inner) = self.borrow_mut() {
284 inner.set_scroll_pos(cx, v)
285 }
286 }
287
288 pub fn area(&self) -> Area {
289 if let Some(inner) = self.borrow_mut() {
290 inner.area
291 }
292 else {
293 Area::Empty
294 }
295 }
296
297 pub fn child_count(&self) -> usize {
298 if let Some(inner) = self.borrow_mut() {
299 inner.draw_order.len()
300 }
301 else {
302 0
303 }
304 }
305}
306
307impl ViewSet {
308
309 pub fn cut_state(&mut self, cx: &mut Cx, state: &[LiveId; 2]) {
310 for item in self.iter() {
311 item.cut_state(cx, state)
312 }
313 }
314
315 pub fn animator_play(&mut self, cx: &mut Cx, state: &[LiveId; 2]) {
316 for item in self.iter() {
317 item.animator_play(cx, state);
318 }
319 }
320
321 pub fn toggle_state(&mut self, cx: &mut Cx, is_state_1: bool, animate: Animate, state1: &[LiveId; 2], state2: &[LiveId; 2]) {
322 for item in self.iter() {
323 item.toggle_state(cx, is_state_1, animate, state1, state2);
324 }
325 }
326
327 pub fn set_visible(&self, visible: bool) {
328 for item in self.iter() {
329 item.set_visible(visible)
330 }
331 }
332
333 pub fn set_texture(&self, slot: usize, texture: &Texture) {
334 for item in self.iter() {
335 item.set_texture(slot, texture)
336 }
337 }
338
339 pub fn set_uniform(&self, cx: &Cx, uniform: &[LiveId], value: &[f32]) {
340 for item in self.iter() {
341 item.set_uniform(cx, uniform, value)
342 }
343 }
344
345 pub fn redraw(&self, cx: &mut Cx) {
346 for item in self.iter() {
347 item.redraw(cx);
348 }
349 }
350
351 pub fn finger_down(&self, actions: &WidgetActions) -> Option<FingerDownEvent> {
352 for item in self.iter() {
353 if let Some(e) = item.finger_down(actions) {
354 return Some(e)
355 }
356 }
357 None
358 }
359
360 pub fn finger_up(&self, actions: &WidgetActions) -> Option<FingerUpEvent> {
361 for item in self.iter() {
362 if let Some(e) = item.finger_up(actions) {
363 return Some(e)
364 }
365 }
366 None
367 }
368
369
370 pub fn finger_move(&self, actions: &WidgetActions) -> Option<FingerMoveEvent> {
371 for item in self.iter() {
372 if let Some(e) = item.finger_move(actions) {
373 return Some(e)
374 }
375 }
376 None
377 }
378
379 pub fn key_down(&self, actions: &WidgetActions) -> Option<KeyEvent> {
380 for item in self.iter() {
381 if let Some(e) = item.key_down(actions) {
382 return Some(e)
383 }
384 }
385 None
386 }
387
388 pub fn key_up(&self, actions: &WidgetActions) -> Option<KeyEvent> {
389 for item in self.iter() {
390 if let Some(e) = item.key_up(actions) {
391 return Some(e)
392 }
393 }
394 None
395 }
396}
397
398impl Widget for View {
399 fn handle_widget_event_with(
400 &mut self,
401 cx: &mut Cx,
402 event: &Event,
403 dispatch_action: &mut dyn FnMut(&mut Cx, WidgetActionItem)
404 ) {
405 let uid = self.widget_uid();
406 if self.animator_handle_event(cx, event).must_redraw() {
407 self.redraw(cx);
408 }
409
410 if self.block_signal_event {
411 if let Event::Signal = event {
412 return
413 }
414 }
415 if let Some(scroll_bars) = &mut self.scroll_bars_obj {
416 let mut redraw = false;
417 scroll_bars.handle_main_event(cx, event, &mut | _, _ | {
418 redraw = true;
420 });
421 if redraw {
422 cx.redraw_area_and_children(self.area);
423 }
424 }
425
426 match &self.event_order {
427 EventOrder::Up => {
428 for id in self.draw_order.iter().rev() {
429 if let Some(child) = self.children.get_mut(id) {
430 if child.is_visible() || !event.requires_visibility() {
431 child.handle_widget_event_with(cx, event, dispatch_action);
432 }
433 }
434 }
435 }
436 EventOrder::Down => {
437 for id in self.draw_order.iter() {
438 if let Some(child) = self.children.get_mut(id) {
439 if child.is_visible() || !event.requires_visibility() {
440 child.handle_widget_event_with(cx, event, dispatch_action);
441 }
442 }
443 }
444 }
445 EventOrder::List(list) => {
446 for id in list {
447 if let Some(child) = self.children.get_mut(id) {
448 if child.is_visible() || !event.requires_visibility() {
449 child.handle_widget_event_with(cx, event, dispatch_action);
450 }
451 }
452 }
453 }
454 }
455
456
457 if self.visible && self.cursor.is_some() || self.animator.live_ptr.is_some() {
458 match event.hits(cx, self.area()) {
459 Hit::FingerDown(e) => {
460 if self.grab_key_focus {
461 cx.set_key_focus(self.area());
462 }
463 dispatch_action(cx, ViewAction::FingerDown(e).into_action(uid));
464 if self.animator.live_ptr.is_some() {
465 self.animator_play(cx, id!(down.on));
466 }
467 }
468 Hit::FingerMove(e) => {
469 dispatch_action(cx, ViewAction::FingerMove(e).into_action(uid))
470 }
471 Hit::FingerUp(e) => {
472 dispatch_action(cx, ViewAction::FingerUp(e).into_action(uid));
473 if self.animator.live_ptr.is_some() {
474 self.animator_play(cx, id!(down.off));
475 }
476 }
477 Hit::FingerHoverIn(_) => {
478 if let Some(cursor) = &self.cursor {
479 cx.set_cursor(*cursor);
480 }
481 if self.animator.live_ptr.is_some() {
482 self.animator_play(cx, id!(hover.on));
483 }
484 }
485 Hit::FingerHoverOut(_) => {
486 if self.animator.live_ptr.is_some() {
487 self.animator_play(cx, id!(hover.off));
488 }
489 }
490 Hit::KeyDown(e) => {
491 dispatch_action(cx, ViewAction::KeyDown(e).into_action(uid))
492 }
493 Hit::KeyUp(e) => {
494 dispatch_action(cx, ViewAction::KeyUp(e).into_action(uid))
495 }
496 _ => ()
497 }
498 }
499
500 if let Some(scroll_bars) = &mut self.scroll_bars_obj {
501 scroll_bars.handle_scroll_event(cx, event, &mut | _, _ | {});
502 }
503 }
504
505 fn is_visible(&self) -> bool {
506 self.visible
507 }
508
509 fn walk(&mut self, _cx: &mut Cx) -> Walk {
510 self.walk
511 }
512
513 fn draw_walk_widget(&mut self, cx: &mut Cx2d, walk: Walk) -> WidgetDraw {
514 self.draw_walk(cx, walk)
515 }
516
517 fn redraw(&mut self, cx: &mut Cx) {
518 self.area.redraw(cx);
519 for child in self.children.values_mut() {
520 child.redraw(cx);
521 }
522 }
523
524 fn find_widgets(&mut self, path: &[LiveId], cached: WidgetCache, results: &mut WidgetSet) {
525 match cached {
526 WidgetCache::Yes | WidgetCache::Clear => {
527 if let WidgetCache::Clear = cached {
528 self.find_cache.clear();
529 }
530 let mut hash = 0u64;
531 for i in 0..path.len() {
532 hash ^= path[i].0
533 }
534 if let Some(widget_set) = self.find_cache.get(&hash) {
535 results.extend_from_set(widget_set);
536 return
537 }
538 let mut local_results = WidgetSet::empty();
539 if let Some(child) = self.children.get_mut(&path[0]) {
540 if path.len()>1 {
541 child.find_widgets(&path[1..], WidgetCache::No, &mut local_results);
542 }
543 else {
544 local_results.push(child.clone());
545 }
546 }
547 for child in self.children.values_mut() {
548 child.find_widgets(path, WidgetCache::No, &mut local_results);
549 }
550 if !local_results.is_empty() {
551 results.extend_from_set(&local_results);
552 }
553 self.find_cache.insert(hash, local_results);
554 }
555 WidgetCache::No => {
556 if let Some(child) = self.children.get_mut(&path[0]) {
557 if path.len()>1 {
558 child.find_widgets(&path[1..], WidgetCache::No, results);
559 }
560 else {
561 results.push(child.clone());
562 }
563 }
564 for child in self.children.values_mut() {
565 child.find_widgets(path, WidgetCache::No, results);
566 }
567 }
568 }
569 }
570}
571
572#[derive(Clone)]
573enum DrawState {
574 Drawing(usize, bool),
575 DeferWalk(usize)
576}
577
578impl View {
579
580 pub fn set_scroll_pos(&mut self, cx: &mut Cx, v: DVec2) {
581 if let Some(scroll_bars) = &mut self.scroll_bars_obj {
582 scroll_bars.set_scroll_pos(cx, v);
583 }
584 else {
585 self.layout.scroll = v;
586 }
587 }
588
589 pub fn area(&self) -> Area {
590 self.area
591 }
592
593 pub fn walk_from_previous_size(&self, walk: Walk) -> Walk {
594 let view_size = self.view_size.unwrap_or(DVec2::default());
595 Walk {
596 abs_pos: walk.abs_pos,
597 width: if walk.width.is_fill() {walk.width}else {Size::Fixed(view_size.x)},
598 height: if walk.height.is_fill() {walk.height}else {Size::Fixed(view_size.y)},
599 margin: walk.margin
600 }
601 }
602
603 pub fn draw_walk(&mut self, cx: &mut Cx2d, walk: Walk) -> WidgetDraw {
604 if self.draw_state.begin(cx, DrawState::Drawing(0, false)) {
606 if !self.visible {
607 self.draw_state.end();
608 return WidgetDraw::done()
609 }
610
611 self.defer_walks.clear();
612
613 match self.optimize {
614 ViewOptimize::Texture => {
615 let walk = self.walk_from_previous_size(walk);
616 if !cx.will_redraw(self.draw_list.as_mut().unwrap(), walk) {
617 if let Some(texture_cache) = &self.texture_cache {
618 self.draw_bg.draw_vars.set_texture(0, &texture_cache.color_texture);
619 let mut rect = cx.walk_turtle_with_area(&mut self.area, walk);
620 rect.size *= 2.0 / self.dpi_factor.unwrap_or(1.0);
621 self.draw_bg.draw_abs(cx, rect);
622 self.area = self.draw_bg.area();
623 cx.set_pass_scaled_area(&texture_cache.pass, self.area, 2.0 / self.dpi_factor.unwrap_or(1.0));
624 }
625 return WidgetDraw::done()
626 }
627 if self.texture_cache.is_none() {
629 self.texture_cache = Some(ViewTextureCache {
630 pass: Pass::new(cx),
631 _depth_texture: Texture::new(cx),
632 color_texture: Texture::new(cx)
633 });
634 let texture_cache = self.texture_cache.as_mut().unwrap();
635 texture_cache.pass.add_color_texture(cx, &texture_cache.color_texture, PassClearColor::ClearWith(vec4(0.0, 0.0, 0.0, 0.0)));
637 }
638 let texture_cache = self.texture_cache.as_mut().unwrap();
639 cx.make_child_pass(&texture_cache.pass);
640 cx.begin_pass(&texture_cache.pass, self.dpi_factor);
641 self.draw_list.as_mut().unwrap().begin_always(cx)
642 }
643 ViewOptimize::DrawList => {
644 let walk = self.walk_from_previous_size(walk);
645 if self.draw_list.as_mut().unwrap().begin(cx, walk).is_not_redrawing() {
646 cx.walk_turtle_with_area(&mut self.area, walk);
647 return WidgetDraw::done()
648 }
649 }
650 _ => ()
651 }
652
653
654 let scroll = if let Some(scroll_bars) = &mut self.scroll_bars_obj {
656 scroll_bars.begin_nav_area(cx);
657 scroll_bars.get_scroll_pos()
658 }
659 else {
660 self.layout.scroll
661 };
662
663 if self.show_bg {
664 self.draw_bg.begin(cx, walk, self.layout.with_scroll(scroll)); }
669 else {
670 cx.begin_turtle(walk, self.layout.with_scroll(scroll)); }
672 }
673
674 while let Some(DrawState::Drawing(step, resume)) = self.draw_state.get() {
675 if step < self.draw_order.len() {
676 let id = self.draw_order[step];
677 if let Some(child) = self.children.get_mut(&id) {
678 if child.is_visible() {
679 let walk = child.walk(cx);
680 if resume {
681 child.draw_walk_widget(cx, walk) ?;
682 }
683 else if let Some(fw) = cx.defer_walk(walk) {
684 self.defer_walks.push((id, fw));
685 }
686 else {
687 self.draw_state.set(DrawState::Drawing(step, true));
688 child.draw_walk_widget(cx, walk) ?;
689 }
690 }
691 }
692 self.draw_state.set(DrawState::Drawing(step + 1, false));
693 }
694 else {
695 self.draw_state.set(DrawState::DeferWalk(0));
696 }
697 }
698
699 while let Some(DrawState::DeferWalk(step)) = self.draw_state.get() {
700 if step < self.defer_walks.len() {
701 let (id, dw) = &mut self.defer_walks[step];
702 if let Some(child) = self.children.get_mut(&id) {
703 let walk = dw.resolve(cx);
704 child.draw_walk_widget(cx, walk) ?;
705 }
706 self.draw_state.set(DrawState::DeferWalk(step + 1));
707 }
708 else {
709 if let Some(scroll_bars) = &mut self.scroll_bars_obj {
710 scroll_bars.draw_scroll_bars(cx);
711 };
712
713 if self.show_bg {
714 if self.optimize.is_texture() {
715 panic!("dont use show_bg and texture cazching at the same time");
716 }
717 self.draw_bg.end(cx);
718 self.area = self.draw_bg.area();
719 }
720 else {
721 cx.end_turtle_with_area(&mut self.area);
722 };
723
724 if let Some(scroll_bars) = &mut self.scroll_bars_obj {
725 scroll_bars.set_area(self.area);
726 scroll_bars.end_nav_area(cx);
727 };
728
729 if self.optimize.needs_draw_list() {
730 let rect = self.area.get_rect(cx);
731 self.view_size = Some(rect.size);
732 self.draw_list.as_mut().unwrap().end(cx);
733
734 if self.optimize.is_texture() {
735 let texture_cache = self.texture_cache.as_mut().unwrap();
736 cx.end_pass(&texture_cache.pass);
737 self.draw_bg.draw_vars.set_texture(0, &texture_cache.color_texture);
744 self.draw_bg.draw_abs(cx, rect);
745 let area = self.draw_bg.area();
746 let texture_cache = self.texture_cache.as_mut().unwrap();
747 cx.set_pass_scaled_area(&texture_cache.pass, area, 2.0 / self.dpi_factor.unwrap_or(1.0));
748 }
749 }
750 self.draw_state.end();
751 }
752 }
753 WidgetDraw::done()
754 }
755
756 pub fn child_count(&self) -> usize {
757 self.draw_order.len()
758 }
759}
760