makepad_widgets/
view.rs

1use {
2    crate::{makepad_derive_widget::*, makepad_draw::*, scroll_bars::ScrollBars, widget::*}, makepad_draw::event::FingerLongPressEvent, std::cell::RefCell
3};
4
5live_design! {
6    pub ViewBase = {{View}} {debug:None}
7}
8
9// maybe we should put an enum on the bools like
10
11#[derive(Live, LiveHook, Clone, Copy)]
12#[live_ignore]
13pub enum ViewOptimize {
14    #[pick]
15    None,
16    DrawList,
17    Texture,
18}
19
20impl Default for ViewOptimize {
21    fn default() -> Self {
22        Self::None
23    }
24}
25
26#[derive(Live)]
27#[live_ignore]
28pub enum ViewDebug {
29    #[pick]
30    None,
31    R,
32    G,
33    B,
34    M,
35    Margin,
36    P,
37    Padding,
38    A,
39    All,
40    #[live(Vec4::default())]
41    Color(Vec4),
42}
43
44impl LiveHook for ViewDebug {
45    fn skip_apply(
46        &mut self,
47        _cx: &mut Cx,
48        _apply: &mut Apply,
49        index: usize,
50        nodes: &[LiveNode],
51    ) -> Option<usize> {
52        match &nodes[index].value {
53            LiveValue::Vec4(v) => {
54                *self = Self::Color(*v);
55                Some(index + 1)
56            }
57            LiveValue::Color(v) => {
58                *self = Self::Color(Vec4::from_u32(*v));
59                Some(index + 1)
60            }
61            LiveValue::Bool(v) => {
62                if *v {
63                    *self = Self::R;
64                } else {
65                    *self = Self::None;
66                }
67                Some(index + 1)
68            }
69            LiveValue::Float64(v) => {
70                if *v != 0.0 {
71                    *self = Self::R;
72                } else {
73                    *self = Self::None;
74                }
75                Some(index + 1)
76            }
77            LiveValue::Int64(v) => {
78                if *v != 0 {
79                    *self = Self::R;
80                } else {
81                    *self = Self::None;
82                }
83                Some(index + 1)
84            }
85            _ => None,
86        }
87    }
88}
89
90#[derive(Live, LiveHook)]
91#[live_ignore]
92pub enum EventOrder {
93    Down,
94    #[pick]
95    Up,
96    #[live(Default::default())]
97    List(Vec<LiveId>),
98}
99
100impl ViewOptimize {
101    fn is_texture(&self) -> bool {
102        if let Self::Texture = self {
103            true
104        } else {
105            false
106        }
107    }
108    fn is_draw_list(&self) -> bool {
109        if let Self::DrawList = self {
110            true
111        } else {
112            false
113        }
114    }
115    fn needs_draw_list(&self) -> bool {
116        return self.is_texture() || self.is_draw_list();
117    }
118}
119
120#[derive(Live, LiveRegisterWidget, WidgetRef, WidgetSet)]
121pub struct View {
122    // draw info per UI element
123    #[live]
124    pub draw_bg: DrawColor,
125
126    #[live(false)]
127    pub show_bg: bool,
128
129    #[layout]
130    pub layout: Layout,
131
132    #[walk]
133    pub walk: Walk,
134
135    //#[live] use_cache: bool,
136    #[live]
137    dpi_factor: Option<f64>,
138
139    #[live]
140    optimize: ViewOptimize,
141    #[live]
142    debug: ViewDebug,
143    #[live]
144    event_order: EventOrder,
145
146    #[live(true)]
147    pub visible: bool,
148
149    #[live(true)]
150    grab_key_focus: bool,
151    #[live(false)]
152    block_signal_event: bool,
153    #[live]
154    cursor: Option<MouseCursor>,
155    #[live(false)]
156    capture_overload: bool,
157    #[live]
158    scroll_bars: Option<LivePtr>,
159    #[live(false)]
160    design_mode: bool,
161
162    #[rust]
163    find_cache: RefCell<SmallVec<[(u64, WidgetSet);3]>>,
164
165    #[rust]
166    scroll_bars_obj: Option<Box<ScrollBars>>,
167    #[rust]
168    view_size: Option<DVec2>,
169    
170    #[rust]
171    area: Area,
172    #[rust]
173    draw_list: Option<DrawList2d>,
174
175    #[rust]
176    texture_cache: Option<ViewTextureCache>,
177    #[rust]
178    defer_walks: SmallVec<[(LiveId, DeferWalk);1]>,
179    #[rust]
180    draw_state: DrawStateWrap<DrawState>,
181    #[rust]
182    children: SmallVec<[(LiveId, WidgetRef);2]>,
183    #[rust]
184    live_update_order: SmallVec<[LiveId;1]>,
185    //#[rust]
186    //draw_order: Vec<LiveId>,
187
188    #[animator]
189    animator: Animator,
190}
191
192struct ViewTextureCache {
193    pass: Pass,
194    _depth_texture: Texture,
195    color_texture: Texture,
196}
197
198impl LiveHook for View {
199    fn before_apply(
200        &mut self,
201        _cx: &mut Cx,
202        apply: &mut Apply,
203        _index: usize,
204        _nodes: &[LiveNode],
205    ) {
206        if let ApplyFrom::UpdateFromDoc { .. } = apply.from {
207            //self.draw_order.clear();
208            self.live_update_order.clear();
209            self.find_cache.get_mut().clear();
210        }
211    }
212
213    fn after_apply(
214        &mut self,
215        cx: &mut Cx,
216        apply: &mut Apply,
217        _index: usize,
218        _nodes: &[LiveNode],
219    ) {
220        if apply.from.is_update_from_doc(){//livecoding
221            // update/delete children list
222            for (idx, id) in self.live_update_order.iter().enumerate(){
223                // lets remove this id from the childlist
224                if let Some(pos) = self.children.iter().position(|(i,_v)| *i == *id){
225                    // alright so we have the position its in now, and the position it should be in
226                    self.children.swap(idx, pos);
227                }
228            }
229            // if we had more truncate
230            self.children.truncate(self.live_update_order.len());
231        }
232        if self.optimize.needs_draw_list() && self.draw_list.is_none() {
233            self.draw_list = Some(DrawList2d::new(cx));
234        }
235        if self.scroll_bars.is_some() {
236            if self.scroll_bars_obj.is_none() {
237                self.scroll_bars_obj =
238                    Some(Box::new(ScrollBars::new_from_ptr(cx, self.scroll_bars)));
239            }
240        }
241    }
242
243    fn apply_value_instance(
244        &mut self,
245        cx: &mut Cx,
246        apply: &mut Apply,
247        index: usize,
248        nodes: &[LiveNode],
249    ) -> usize { 
250
251        let id = nodes[index].id;
252        match apply.from {
253            ApplyFrom::Animate | ApplyFrom::Over => {
254                let node_id = nodes[index].id;
255                if let Some((_,component)) = self.children.iter_mut().find(|(id,_)| *id == node_id) {
256                    component.apply(cx, apply, index, nodes)
257                } else {
258                    nodes.skip_node(index)
259                }
260            }
261            ApplyFrom::NewFromDoc { .. } | ApplyFrom::UpdateFromDoc { .. } => {
262                if nodes[index].is_instance_prop() {
263                    if apply.from.is_update_from_doc(){//livecoding
264                        self.live_update_order.push(id);
265                    }
266                    //self.draw_order.push(id);
267                    if let Some((_,node)) = self.children.iter_mut().find(|(id2,_)| *id2 == id){
268                        node.apply(cx, apply, index, nodes)
269                    }
270                    else{
271                        self.children.push((id,WidgetRef::new(cx)));
272                        self.children.last_mut().unwrap().1.apply(cx, apply, index, nodes)
273                    }
274                } else {
275                    cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
276                    nodes.skip_node(index)
277                }
278            }
279            _ => nodes.skip_node(index),
280        }
281    }
282}
283
284#[derive(Clone, Debug, DefaultNone)]
285pub enum ViewAction {
286    None,
287    FingerDown(FingerDownEvent),
288    FingerUp(FingerUpEvent),
289    FingerLongPress(FingerLongPressEvent),
290    FingerMove(FingerMoveEvent),
291    FingerHoverIn(FingerHoverEvent),
292    FingerHoverOut(FingerHoverEvent),
293    KeyDown(KeyEvent),
294    KeyUp(KeyEvent),
295}
296
297impl ViewRef {
298    pub fn finger_down(&self, actions: &Actions) -> Option<FingerDownEvent> {
299        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
300            if let ViewAction::FingerDown(fd) = item.cast() {
301                return Some(fd);
302            }
303        }
304        None
305    }
306
307    pub fn finger_up(&self, actions: &Actions) -> Option<FingerUpEvent> {
308        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
309            if let ViewAction::FingerUp(fd) = item.cast() {
310                return Some(fd);
311            }
312        }
313        None
314    }
315
316    pub fn finger_move(&self, actions: &Actions) -> Option<FingerMoveEvent> {
317        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
318            if let ViewAction::FingerMove(fd) = item.cast() {
319                return Some(fd);
320            }
321        }
322        None
323    }
324
325    pub fn finger_hover_in(&self, actions: &Actions) -> Option<FingerHoverEvent> {
326        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
327            if let ViewAction::FingerHoverIn(fd) = item.cast() {
328                return Some(fd);
329            }
330        }
331        None
332    }
333
334    pub fn finger_hover_out(&self, actions: &Actions) -> Option<FingerHoverEvent> {
335        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
336            if let ViewAction::FingerHoverOut(fd) = item.cast() {
337                return Some(fd);
338            }
339        }
340        None
341    }
342
343    pub fn key_down(&self, actions: &Actions) -> Option<KeyEvent> {
344        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
345            if let ViewAction::KeyDown(fd) = item.cast() {
346                return Some(fd);
347            }
348        }
349        None
350    }
351
352    pub fn key_up(&self, actions: &Actions) -> Option<KeyEvent> {
353        if let Some(item) = actions.find_widget_action(self.widget_uid()) {
354            if let ViewAction::KeyUp(fd) = item.cast() {
355                return Some(fd);
356            }
357        }
358        None
359    }
360
361    pub fn animator_cut(&self, cx: &mut Cx, state: &[LiveId; 2]) {
362        if let Some(mut inner) = self.borrow_mut() {
363            inner.animator_cut(cx, state);
364        }
365    }
366
367    pub fn animator_play(&self, cx: &mut Cx, state: &[LiveId; 2]) {
368        if let Some(mut inner) = self.borrow_mut() {
369            inner.animator_play(cx, state);
370        }
371    }
372
373    pub fn toggle_state(
374        &self,
375        cx: &mut Cx,
376        is_state_1: bool,
377        animate: Animate,
378        state1: &[LiveId; 2],
379        state2: &[LiveId; 2],
380    ) {
381        if let Some(mut inner) = self.borrow_mut() {
382            inner.animator_toggle(cx, is_state_1, animate, state1, state2);
383        }
384    }
385
386    pub fn set_visible(&self, cx: &mut Cx, visible: bool) {
387        if let Some(mut inner) = self.borrow_mut() {
388            inner.set_visible(cx, visible)
389        }
390    }
391
392    pub fn visible(&self) -> bool {
393        if let Some(inner) = self.borrow() {
394            inner.visible()
395        } else {
396            false
397        }
398    }
399
400    pub fn set_texture(&self, slot: usize, texture: &Texture) {
401        if let Some(mut inner) = self.borrow_mut() {
402            inner.draw_bg.set_texture(slot, texture);
403        }
404    }
405
406    pub fn set_uniform(&self, cx: &Cx, uniform: &[LiveId], value: &[f32]) {
407        if let Some(mut inner) = self.borrow_mut() {
408            inner.draw_bg.set_uniform(cx, uniform, value);
409        }
410    }
411
412    pub fn set_scroll_pos(&self, cx: &mut Cx, v: DVec2) {
413        if let Some(mut inner) = self.borrow_mut() {
414            inner.set_scroll_pos(cx, v)
415        }
416    }
417
418    pub fn area(&self) -> Area {
419        if let Some(inner) = self.borrow_mut() {
420            inner.area
421        } else {
422            Area::Empty
423        }
424    }
425
426    pub fn child_count(&self) -> usize {
427        if let Some(inner) = self.borrow_mut() {
428            inner.children.len()
429        } else {
430            0
431        }
432    }
433
434    pub fn set_key_focus(&self, cx: &mut Cx) {
435        if let Some(inner) = self.borrow_mut() {
436            inner.set_key_focus(cx);
437        }
438    }
439}
440
441impl ViewSet {
442    pub fn animator_cut(&self, cx: &mut Cx, state: &[LiveId; 2]) {
443        for item in self.iter() {
444            item.animator_cut(cx, state)
445        }
446    }
447
448    pub fn animator_play(&self, cx: &mut Cx, state: &[LiveId; 2]) {
449        for item in self.iter() {
450            item.animator_play(cx, state);
451        }
452    }
453
454    pub fn toggle_state(
455        &self,
456        cx: &mut Cx,
457        is_state_1: bool,
458        animate: Animate,
459        state1: &[LiveId; 2],
460        state2: &[LiveId; 2],
461    ) {
462        for item in self.iter() {
463            item.toggle_state(cx, is_state_1, animate, state1, state2);
464        }
465    }
466
467    pub fn set_visible(&self, cx:&mut Cx, visible: bool) {
468        for item in self.iter() {
469            item.set_visible(cx, visible)
470        }
471    }
472
473    pub fn set_texture(&self, slot: usize, texture: &Texture) {
474        for item in self.iter() {
475            item.set_texture(slot, texture)
476        }
477    }
478
479    pub fn set_uniform(&self, cx: &Cx, uniform: &[LiveId], value: &[f32]) {
480        for item in self.iter() {
481            item.set_uniform(cx, uniform, value)
482        }
483    }
484
485    pub fn redraw(&self, cx: &mut Cx) {
486        for item in self.iter() {
487            item.redraw(cx);
488        }
489    }
490
491    pub fn finger_down(&self, actions: &Actions) -> Option<FingerDownEvent> {
492        for item in self.iter() {
493            if let Some(e) = item.finger_down(actions) {
494                return Some(e);
495            }
496        }
497        None
498    }
499
500    pub fn finger_up(&self, actions: &Actions) -> Option<FingerUpEvent> {
501        for item in self.iter() {
502            if let Some(e) = item.finger_up(actions) {
503                return Some(e);
504            }
505        }
506        None
507    }
508
509    pub fn finger_move(&self, actions: &Actions) -> Option<FingerMoveEvent> {
510        for item in self.iter() {
511            if let Some(e) = item.finger_move(actions) {
512                return Some(e);
513            }
514        }
515        None
516    }
517
518    pub fn key_down(&self, actions: &Actions) -> Option<KeyEvent> {
519        for item in self.iter() {
520            if let Some(e) = item.key_down(actions) {
521                return Some(e);
522            }
523        }
524        None
525    }
526
527    pub fn key_up(&self, actions: &Actions) -> Option<KeyEvent> {
528        for item in self.iter() {
529            if let Some(e) = item.key_up(actions) {
530                return Some(e);
531            }
532        }
533        None
534    }
535}
536
537impl WidgetNode for View {
538    fn walk(&mut self, _cx: &mut Cx) -> Walk {
539        self.walk
540    }
541    
542    fn area(&self)->Area{
543        self.area
544    }
545    
546    fn redraw(&mut self, cx: &mut Cx) {
547        self.area.redraw(cx);
548        for (_,child) in &mut self.children {
549            child.redraw(cx);
550        }
551    }
552    
553    fn uid_to_widget(&self, uid:WidgetUid)->WidgetRef{
554        for (_,child) in &self.children {
555            let x = child.uid_to_widget(uid);
556            if !x.is_empty(){return x}
557        }
558        WidgetRef::empty()
559    }
560
561    fn find_widgets(&self, path: &[LiveId], cached: WidgetCache, results: &mut WidgetSet) {
562        match cached {
563            WidgetCache::Yes | WidgetCache::Clear => {
564                if let WidgetCache::Clear = cached {
565                    self.find_cache.borrow_mut().clear();
566                    if path.len() == 0{
567                        return
568                    }
569                }
570                let mut hash = 0u64;
571                for i in 0..path.len() {
572                    hash ^= path[i].0
573                }
574                if let Some((_,widget_set)) = self.find_cache.borrow().iter().find(|(h,_v)| h == &hash) {
575                    results.extend_from_set(widget_set);
576                    /*#[cfg(not(ignore_query))]
577                    if results.0.len() == 0{
578                        log!("Widget query not found: {:?} on view {:?}", path, self.widget_uid());
579                    }
580                    #[cfg(panic_query)]
581                    if results.0.len() == 0{
582                        panic!("Widget query not found: {:?} on view {:?}", path, self.widget_uid());
583                    }*/
584                    return;
585                }
586                let mut local_results = WidgetSet::empty();
587                if let Some((_,child)) = self.children.iter().find(|(id,_)| *id == path[0]) {
588                    if path.len() > 1 {
589                        child.find_widgets(&path[1..], WidgetCache::No, &mut local_results);
590                    } else {
591                        local_results.push(child.clone());
592                    }
593                }
594                for (_,child) in &self.children {
595                    child.find_widgets(path, WidgetCache::No, &mut local_results);
596                }
597                if !local_results.is_empty() {
598                    results.extend_from_set(&local_results);
599                }
600               /* #[cfg(not(ignore_query))]
601                if local_results.0.len() == 0{
602                    log!("Widget query not found: {:?} on view {:?}", path, self.widget_uid());
603                }
604                #[cfg(panic_query)]
605                if local_results.0.len() == 0{
606                    panic!("Widget query not found: {:?} on view {:?}", path, self.widget_uid());
607                }*/
608                self.find_cache.borrow_mut().push((hash, local_results));
609            }
610            WidgetCache::No => {
611                 if let Some((_,child)) = self.children.iter().find(|(id,_)| *id == path[0]) {
612                    if path.len() > 1 {
613                        child.find_widgets(&path[1..], WidgetCache::No, results);
614                    } else {
615                        results.push(child.clone());
616                    }
617                }
618                for (_,child) in &self.children {
619                    child.find_widgets(path, WidgetCache::No, results);
620                }
621            }
622        }
623    }
624    
625    fn set_visible(&mut self, cx:&mut Cx, visible:bool) {
626        if self.visible != visible{
627            self.visible = visible;
628            self.redraw(cx);
629        }
630    }
631        
632    fn visible(&self) -> bool {
633        self.visible
634    }
635}
636
637impl Widget for View {
638    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
639                
640        if !self.visible && event.requires_visibility(){
641            return
642        }
643        
644        let uid = self.widget_uid();
645        if self.animator_handle_event(cx, event).must_redraw() {
646            self.redraw(cx);
647        }
648
649        if self.block_signal_event {
650            if let Event::Signal = event {
651                return;
652            }
653        }
654        if let Some(scroll_bars) = &mut self.scroll_bars_obj {
655            let mut actions = Vec::new();
656            scroll_bars.handle_main_event(cx, event, scope, &mut actions);
657            if actions.len() > 0 {
658                cx.redraw_area_and_children(self.area);
659            };
660        }
661
662        // If the UI tree has changed significantly (e.g. AdaptiveView varaints changed),
663        // we need to clear the cache and re-query widgets.
664        if cx.widget_query_invalidation_event.is_some() {
665            self.find_cache.borrow_mut().clear();
666        }
667
668        match &self.event_order {
669            EventOrder::Up => {
670                for (id, child) in self.children.iter_mut().rev() {
671                    scope.with_id(*id, |scope| {
672                        child.handle_event(cx, event, scope);
673                    });
674                }
675            }
676            EventOrder::Down => {
677                for (id, child) in self.children.iter_mut() {
678                    scope.with_id(*id, |scope| {
679                        child.handle_event(cx, event, scope);
680                    })
681                }
682            }
683            EventOrder::List(list) => {
684                for id in list {
685                    if let Some((_,child)) = self.children.iter_mut().find(|(id2,_)| id2 == id) {
686                        scope.with_id(*id, |scope| {
687                            child.handle_event(cx, event, scope);
688                        })
689                    }
690                }
691            }
692        }
693                
694        match event.hit_designer(cx, self.area()){
695            HitDesigner::DesignerPick(_e)=>{
696                cx.widget_action(uid, &scope.path, WidgetDesignAction::PickedBody)
697            }
698            _=>()
699        }
700        
701        if self.visible && self.cursor.is_some() || self.animator.live_ptr.is_some() {
702            match event.hits_with_capture_overload(cx, self.area(), self.capture_overload) {
703                Hit::FingerDown(e) => {
704                    if self.grab_key_focus {
705                        cx.set_key_focus(self.area());
706                    }
707                    cx.widget_action(uid, &scope.path, ViewAction::FingerDown(e));
708                    if self.animator.live_ptr.is_some() {
709                        self.animator_play(cx, id!(down.on));
710                    }
711                }
712                Hit::FingerMove(e) => cx.widget_action(uid, &scope.path, ViewAction::FingerMove(e)),
713                Hit::FingerLongPress(e) => cx.widget_action(uid, &scope.path, ViewAction::FingerLongPress(e)), 
714                Hit::FingerUp(e) => {
715                    cx.widget_action(uid, &scope.path, ViewAction::FingerUp(e));
716                    if self.animator.live_ptr.is_some() {
717                        self.animator_play(cx, id!(down.off));
718                    }
719                }
720                Hit::FingerHoverIn(e) => {
721                    cx.widget_action(uid, &scope.path, ViewAction::FingerHoverIn(e));
722                    if let Some(cursor) = &self.cursor {
723                        cx.set_cursor(*cursor);
724                    }
725                    if self.animator.live_ptr.is_some() {
726                        self.animator_play(cx, id!(hover.on));
727                    }
728                }
729                Hit::FingerHoverOut(e) => {
730                    cx.widget_action(uid, &scope.path, ViewAction::FingerHoverOut(e));
731                    if self.animator.live_ptr.is_some() {
732                        self.animator_play(cx, id!(hover.off));
733                    }
734                }
735                Hit::KeyDown(e) => cx.widget_action(uid, &scope.path, ViewAction::KeyDown(e)),
736                Hit::KeyUp(e) => cx.widget_action(uid, &scope.path, ViewAction::KeyUp(e)),
737                _ => (),
738            }
739        }
740
741        if let Some(scroll_bars) = &mut self.scroll_bars_obj {
742            scroll_bars.handle_scroll_event(cx, event, scope, &mut Vec::new());
743        }
744    }
745
746
747    fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
748        // the beginning state
749        if self.draw_state.begin(cx, DrawState::Drawing(0, false)) {
750            if !self.visible {
751                self.draw_state.end();
752                return DrawStep::done();
753            }
754
755            self.defer_walks.clear();
756
757            match self.optimize {
758                ViewOptimize::Texture => {
759                    let walk = self.walk_from_previous_size(walk);
760                    if !cx.will_redraw(self.draw_list.as_mut().unwrap(), walk) {
761                        if let Some(texture_cache) = &self.texture_cache {
762                            self.draw_bg
763                                .draw_vars
764                                .set_texture(0, &texture_cache.color_texture);
765                            let mut rect = cx.walk_turtle_with_area(&mut self.area, walk);
766                            // NOTE(eddyb) see comment lower below for why this is
767                            // disabled (it used to match `set_pass_scaled_area`).
768                            if false {
769                                rect.size *= 2.0 / self.dpi_factor.unwrap_or(1.0);
770                            }
771                            self.draw_bg.draw_abs(cx, rect);
772                            self.area = self.draw_bg.area();
773                            /*if false {
774                                // FIXME(eddyb) this was the previous logic,
775                                // but the only tested apps that use `CachedView`
776                                // are sized correctly (regardless of `dpi_factor`)
777                                // *without* extra scaling here.
778                                cx.set_pass_scaled_area(
779                                    &texture_cache.pass,
780                                    self.area,
781                                    2.0 / self.dpi_factor.unwrap_or(1.0),
782                                );
783                            } else {*/
784                                cx.set_pass_area(
785                                    &texture_cache.pass,
786                                    self.area,
787                                );
788                            //}
789                        }
790                        return DrawStep::done();
791                    }
792                    // lets start a pass
793                    if self.texture_cache.is_none() {
794                        self.texture_cache = Some(ViewTextureCache {
795                            pass: Pass::new(cx),
796                            _depth_texture: Texture::new(cx),
797                            color_texture: Texture::new(cx),
798                        });
799                        let texture_cache = self.texture_cache.as_mut().unwrap();
800                        //cache.pass.set_depth_texture(cx, &cache.depth_texture, PassClearDepth::ClearWith(1.0));
801                        texture_cache.color_texture = Texture::new_with_format(
802                            cx,
803                            TextureFormat::RenderBGRAu8 {
804                                size: TextureSize::Auto,
805                                initial: true,
806                            },
807                        );
808                        texture_cache.pass.set_color_texture(
809                            cx,
810                            &texture_cache.color_texture,
811                            PassClearColor::ClearWith(vec4(0.0, 0.0, 0.0, 0.0)),
812                        );
813                    }
814                    let texture_cache = self.texture_cache.as_mut().unwrap();
815                    cx.make_child_pass(&texture_cache.pass);
816                    cx.begin_pass(&texture_cache.pass, self.dpi_factor);
817                    self.draw_list.as_mut().unwrap().begin_always(cx)
818                }
819                ViewOptimize::DrawList => {
820                    let walk = self.walk_from_previous_size(walk);
821                    if self
822                        .draw_list
823                        .as_mut()
824                        .unwrap()
825                        .begin(cx, walk)
826                        .is_not_redrawing()
827                    {
828                        cx.walk_turtle_with_area(&mut self.area, walk);
829                        return DrawStep::done();
830                    }
831                }
832                _ => (),
833            }
834
835            // ok so.. we have to keep calling draw till we return LiveId(0)
836            let scroll = if let Some(scroll_bars) = &mut self.scroll_bars_obj {
837                scroll_bars.begin_nav_area(cx);
838                scroll_bars.get_scroll_pos()
839            } else {
840                self.layout.scroll
841            };
842
843            if self.show_bg {
844                /*if let Some(image_texture) = &self.image_texture {
845                    self.draw_bg.draw_vars.set_texture(0, image_texture);
846                }*/
847                self.draw_bg
848                    .begin(cx, walk, self.layout.with_scroll(scroll)); //.with_scale(2.0 / self.dpi_factor.unwrap_or(2.0)));
849            } else {
850                cx.begin_turtle(walk, self.layout.with_scroll(scroll)); //.with_scale(2.0 / self.dpi_factor.unwrap_or(2.0)));
851            }
852        }
853
854        while let Some(DrawState::Drawing(step, resume)) = self.draw_state.get() {
855            if step < self.children.len() {
856                //let id = self.draw_order[step];
857                if let Some((id,child)) = self.children.get_mut(step) {
858                    if child.visible() {
859                        let walk = child.walk(cx);
860                        if resume {
861                            scope.with_id(*id, |scope| child.draw_walk(cx, scope, walk))?;
862                        } else if let Some(fw) = cx.defer_walk(walk) {
863                            self.defer_walks.push((*id, fw));
864                        } else {
865                            self.draw_state.set(DrawState::Drawing(step, true));
866                            scope.with_id(*id, |scope| child.draw_walk(cx, scope, walk))?;
867                        }
868                    }
869                }
870                self.draw_state.set(DrawState::Drawing(step + 1, false));
871            } else {
872                self.draw_state.set(DrawState::DeferWalk(0));
873            }
874        }
875
876        while let Some(DrawState::DeferWalk(step)) = self.draw_state.get() {
877            if step < self.defer_walks.len() {
878                let (id, dw) = &mut self.defer_walks[step];
879                if let Some((id, child)) = self.children.iter_mut().find(|(id2,_)|id2 == id) {
880                    let walk = dw.resolve(cx);
881                    scope.with_id(*id, |scope| child.draw_walk(cx, scope, walk))?;
882                }
883                self.draw_state.set(DrawState::DeferWalk(step + 1));
884            } else {
885                if let Some(scroll_bars) = &mut self.scroll_bars_obj {
886                    scroll_bars.draw_scroll_bars(cx);
887                };
888
889                if self.show_bg {
890                    if self.optimize.is_texture() {
891                        panic!("dont use show_bg and texture caching at the same time");
892                    }
893                    self.draw_bg.end(cx);
894                    self.area = self.draw_bg.area();
895                } else {
896                    cx.end_turtle_with_area(&mut self.area);
897                };
898
899                if let Some(scroll_bars) = &mut self.scroll_bars_obj {
900                    scroll_bars.set_area(self.area);
901                    scroll_bars.end_nav_area(cx);
902                };
903
904                if self.optimize.needs_draw_list() {
905                    let rect = self.area.rect(cx);
906                    self.view_size = Some(rect.size);
907                    self.draw_list.as_mut().unwrap().end(cx);
908
909                    if self.optimize.is_texture() {
910                        let texture_cache = self.texture_cache.as_mut().unwrap();
911                        cx.end_pass(&texture_cache.pass);
912                        /*if cache.pass.id_equals(4){
913                            self.draw_bg.draw_vars.set_uniform(cx, id!(marked),&[1.0]);
914                        }
915                        else{
916                            self.draw_bg.draw_vars.set_uniform(cx, id!(marked),&[0.0]);
917                        }*/
918                        self.draw_bg
919                            .draw_vars
920                            .set_texture(0, &texture_cache.color_texture);
921                        self.draw_bg.draw_abs(cx, rect);
922                        let area = self.draw_bg.area();
923                        let texture_cache = self.texture_cache.as_mut().unwrap();
924                       /* if false {
925                            // FIXME(eddyb) this was the previous logic,
926                            // but the only tested apps that use `CachedView`
927                            // are sized correctly (regardless of `dpi_factor`)
928                            // *without* extra scaling here.
929                            cx.set_pass_scaled_area(
930                                &texture_cache.pass,
931                                area,
932                                2.0 / self.dpi_factor.unwrap_or(1.0),
933                            );
934                        } else {*/
935                            cx.set_pass_area(
936                                &texture_cache.pass,
937                                area,
938                            );
939                        //}
940                    }
941                }
942                self.draw_state.end();
943            }
944        }
945        match &self.debug {
946            ViewDebug::None => {}
947            ViewDebug::Color(c) => {
948                cx.debug.area(self.area, *c);
949            }
950            ViewDebug::R => {
951                cx.debug.area(self.area, Vec4::R);
952            }
953            ViewDebug::G => {
954                cx.debug.area(self.area, Vec4::G);
955            }
956            ViewDebug::B => {
957                cx.debug.area(self.area, Vec4::B);
958            }
959            ViewDebug::M | ViewDebug::Margin => {
960                let tl = dvec2(self.walk.margin.left, self.walk.margin.top);
961                let br = dvec2(self.walk.margin.right, self.walk.margin.bottom);
962                cx.debug.area_offset(self.area, tl, br, Vec4::B);
963                cx.debug.area(self.area, Vec4::R);
964            }
965            ViewDebug::P | ViewDebug::Padding => {
966                let tl = dvec2(-self.layout.padding.left, -self.walk.margin.top);
967                let br = dvec2(-self.layout.padding.right, -self.layout.padding.bottom);
968                cx.debug.area_offset(self.area, tl, br, Vec4::G);
969                cx.debug.area(self.area, Vec4::R);
970            }
971            ViewDebug::All | ViewDebug::A => {
972                let tl = dvec2(self.walk.margin.left, self.walk.margin.top);
973                let br = dvec2(self.walk.margin.right, self.walk.margin.bottom);
974                cx.debug.area_offset(self.area, tl, br, Vec4::B);
975                let tl = dvec2(-self.layout.padding.left, -self.walk.margin.top);
976                let br = dvec2(-self.layout.padding.right, -self.layout.padding.bottom);
977                cx.debug.area_offset(self.area, tl, br, Vec4::G);
978                cx.debug.area(self.area, Vec4::R);
979            }
980        }
981        DrawStep::done()
982    }
983}
984
985#[derive(Clone)]
986enum DrawState {
987    Drawing(usize, bool),
988    DeferWalk(usize),
989}
990
991impl View {
992    pub fn swap_child(&mut self, pos_a: usize, pos_b: usize){
993        self.children.swap(pos_a, pos_b);
994    }
995    
996    pub fn child_index(&mut self, comp:&WidgetRef)->Option<usize>{
997        if let Some(pos) = self.children.iter().position(|(_,w)|{w == comp}){
998            Some(pos)
999        }
1000        else{
1001            None
1002        }
1003    }
1004    
1005    pub fn child_at_index(&mut self, index:usize)->Option<&WidgetRef>{
1006        if let Some(f) = self.children.get(index){
1007            Some(&f.1)
1008        }
1009        else{
1010            None
1011        }
1012    }
1013    
1014    pub fn set_scroll_pos(&mut self, cx: &mut Cx, v: DVec2) {
1015        if let Some(scroll_bars) = &mut self.scroll_bars_obj {
1016            scroll_bars.set_scroll_pos(cx, v);
1017        } else {
1018            self.layout.scroll = v;
1019        }
1020    }
1021
1022    pub fn area(&self) -> Area {
1023        self.area
1024    }
1025
1026    pub fn walk_from_previous_size(&self, walk: Walk) -> Walk {
1027        let view_size = self.view_size.unwrap_or(DVec2::default());
1028        Walk {
1029            abs_pos: walk.abs_pos,
1030            width: if walk.width.is_fill() {
1031                walk.width
1032            } else {
1033                Size::Fixed(view_size.x)
1034            },
1035            height: if walk.height.is_fill() {
1036                walk.height
1037            } else {
1038                Size::Fixed(view_size.y)
1039            },
1040            margin: walk.margin,
1041        }
1042    }
1043
1044    pub fn child_count(&self) -> usize {
1045        self.children.len()
1046    }
1047    
1048    pub fn debug_print_children(&self){
1049        log!("Debug print view children {:?}", self.children.len());
1050        for i in 0..self.children.len(){
1051            log!("Child: {}",self.children[i].0)
1052        }
1053    }
1054
1055    pub fn set_key_focus(&self, cx: &mut Cx) {
1056        cx.set_key_focus(self.draw_bg.area());
1057    }
1058}