makepad_draw/
cx_2d.rs

1use {
2    std::{
3        ops::Deref,
4        ops::DerefMut
5    },
6    crate::{
7        makepad_math::DVec2,
8        makepad_platform::{
9            DrawEvent,
10            Area,
11            DrawListId,
12            PassId,
13            Pass,
14            CxPassParent,
15            CxPassRect,
16            Cx
17        },
18        nav::CxNavTreeRc,
19        icon_atlas::CxIconAtlasRc,
20        font_atlas::CxFontsAtlasRc,
21        draw_list_2d::DrawList2d,
22        turtle::{Turtle, TurtleWalk, Walk, AlignEntry},
23    }
24};
25
26pub struct PassStackItem {
27    pub pass_id: PassId,
28    dpi_factor: f64,
29    draw_list_stack_len: usize,
30    turtles_len: usize
31}
32
33
34pub struct Cx2d<'a> {
35    pub cx: &'a mut Cx,
36    pub (crate) draw_event: &'a DrawEvent,
37    pub (crate) pass_stack: Vec<PassStackItem>,
38    pub (crate) overlay_id: Option<DrawListId>,
39    //pub (crate) overlay_sweep_lock: Option<Rc<RefCell<Area>>>,
40    pub draw_list_stack: Vec<DrawListId>,
41    pub (crate) turtles: Vec<Turtle>,
42    pub (crate) turtle_walks: Vec<TurtleWalk>,
43    pub (crate) turtle_clips: Vec<(DVec2, DVec2)>,
44    pub (crate) align_list: Vec<AlignEntry>,
45    pub fonts_atlas_rc: CxFontsAtlasRc,
46    pub icon_atlas_rc: CxIconAtlasRc,
47    pub nav_tree_rc: CxNavTreeRc,
48}
49
50impl<'a> Deref for Cx2d<'a> {type Target = Cx; fn deref(&self) -> &Self::Target {self.cx}}
51impl<'a> DerefMut for Cx2d<'a> {fn deref_mut(&mut self) -> &mut Self::Target {self.cx}}
52
53impl<'a> Drop for Cx2d<'a> {
54    fn drop(&mut self) {
55        self.draw_font_atlas();
56        self.draw_icon_atlas();
57    }
58}
59
60impl<'a> Cx2d<'a> {
61    
62    /*pub fn set_sweep_lock(&mut self, lock:Area){
63        *self.overlay_sweep_lock.as_ref().unwrap().borrow_mut() = lock;
64    }
65    
66    pub fn clear_sweep_lock(&mut self, lock:Area){
67        let mut sweep_lock = self.overlay_sweep_lock.as_ref().unwrap().borrow_mut();
68        if *sweep_lock == lock{
69            *sweep_lock = Area::Empty
70        }
71    }*/
72    
73    pub fn new(cx: &'a mut Cx, draw_event: &'a DrawEvent) -> Self {
74        Self::lazy_construct_font_atlas(cx);
75        Self::lazy_construct_nav_tree(cx);
76        Self::lazy_construct_icon_atlas(cx);
77        cx.redraw_id += 1;
78        let fonts_atlas_rc = cx.get_global::<CxFontsAtlasRc>().clone();
79        let nav_tree_rc = cx.get_global::<CxNavTreeRc>().clone();
80        let icon_atlas_rc = cx.get_global::<CxIconAtlasRc>().clone();
81        Self {
82            overlay_id: None,
83            fonts_atlas_rc,
84            cx: cx,
85            draw_event,
86            // overlay_sweep_lock: None,
87            pass_stack: Vec::new(),
88            draw_list_stack: Vec::new(),
89            turtle_clips: Vec::new(),
90            turtle_walks: Vec::new(),
91            turtles: Vec::new(),
92            align_list: Vec::new(),
93            nav_tree_rc,
94            icon_atlas_rc
95        }
96    }
97    
98    pub fn current_dpi_factor(&self) -> f64 {
99        self.pass_stack.last().unwrap().dpi_factor
100    }
101    
102    pub fn inside_pass(&self) -> bool {
103        self.pass_stack.len()>0
104    }
105    
106    pub fn make_child_pass(&mut self, pass: &Pass) {
107        let pass_id = self.pass_stack.last().unwrap().pass_id;
108        let cxpass = &mut self.passes[pass.pass_id()];
109        cxpass.parent = CxPassParent::Pass(pass_id);
110    }
111    
112    pub fn begin_pass(&mut self, pass: &Pass, dpi_override: Option<f64>) {
113        let cxpass = &mut self.passes[pass.pass_id()];
114        
115        cxpass.main_draw_list_id = None;
116        
117        let dpi_factor = if let Some(dpi_override) = dpi_override {dpi_override}
118        else {
119            match cxpass.parent {
120                CxPassParent::Window(window_id) => {
121                    self.passes[pass.pass_id()].pass_rect = Some(CxPassRect::Size(self.windows[window_id].get_inner_size()));
122                    self.get_delegated_dpi_factor(pass.pass_id())
123                }
124                CxPassParent::Pass(pass_id) => {
125                    self.passes[pass.pass_id()].pass_rect = self.passes[pass_id].pass_rect.clone();
126                    self.get_delegated_dpi_factor(pass_id)
127                }
128                _ => {
129                    1.0
130                }
131            }
132        };
133        self.passes[pass.pass_id()].dpi_factor = Some(dpi_factor);
134        
135        self.pass_stack.push(PassStackItem {
136            dpi_factor,
137            draw_list_stack_len: self.draw_list_stack.len(),
138            turtles_len: self.turtles.len(),
139            pass_id: pass.pass_id()
140        });
141    }
142    
143    pub fn end_pass(&mut self, pass: &Pass) {
144        let stack_item = self.pass_stack.pop().unwrap();
145        if stack_item.pass_id != pass.pass_id() {
146            panic!();
147        }
148        
149        if self.draw_list_stack.len() != stack_item.draw_list_stack_len {
150            panic!("Draw list stack disaligned, forgot an end_view(cx)");
151        }
152        if self.turtles.len() != stack_item.turtles_len {
153            panic!("Turtle stack disaligned, forgot an end_turtle()");
154        }
155    }
156    
157    pub fn set_pass_area(&mut self, pass: &Pass, area: Area) {
158        self.passes[pass.pass_id()].pass_rect = Some(CxPassRect::Area(area));
159    }
160
161    pub fn set_pass_scaled_area(&mut self, pass: &Pass, area: Area, scale:f64) {
162        self.passes[pass.pass_id()].pass_rect = Some(CxPassRect::ScaledArea(area, scale));
163    }   
164
165    pub fn current_pass_size(&self) -> DVec2 {
166        self.cx.get_pass_rect(self.pass_stack.last().unwrap().pass_id, self.current_dpi_factor()).unwrap().size
167    }
168    
169    pub fn will_redraw(&self, draw_list_2d: &mut DrawList2d, walk: Walk) -> bool {
170        // ok so we need to check if our turtle position has changed since last time.
171        // if it did, we redraw
172        let rect = self.peek_walk_turtle(walk);
173        if draw_list_2d.dirty_check_rect != rect {
174            draw_list_2d.dirty_check_rect = rect;
175            return true;
176        }
177        self.draw_event.draw_list_will_redraw(self, draw_list_2d.draw_list.id())
178    }
179}