makepad_draw/
cx_draw.rs

1use {
2    std::{
3        cell::RefCell,
4        ops::Deref,
5        ops::DerefMut,
6        rc::Rc,
7    },
8    crate::{
9        makepad_math::{DVec2,dvec2},
10        makepad_platform::{
11            DrawEvent,
12            Area,
13            DrawListId,
14            WindowId,
15            PassId,
16            Pass,
17            CxPassParent,
18            CxPassRect,
19            Cx
20        },
21        nav::CxNavTreeRc,
22        icon_atlas::CxIconAtlasRc,
23        draw_list_2d::DrawList2d,
24        text::{loader::FontFamilyDefinition, fonts::Fonts, layouter},
25    },
26    makepad_rustybuzz::UnicodeBuffer,
27};
28
29pub struct PassStackItem {
30    pub pass_id: PassId,
31    dpi_factor: f64,
32    draw_list_stack_len: usize,
33    //turtles_len: usize
34}
35
36
37pub struct CxDraw<'a> {
38    pub cx: &'a mut Cx,
39    pub draw_event: &'a DrawEvent,
40    pub (crate) pass_stack: Vec<PassStackItem>,
41    pub draw_list_stack: Vec<DrawListId>,
42    pub fonts: Rc<RefCell<Fonts>>,
43    pub icon_atlas_rc: CxIconAtlasRc,
44    pub nav_tree_rc: CxNavTreeRc,
45    pub rustybuzz_buffer: Option<UnicodeBuffer>, 
46}
47
48impl<'a> Deref for CxDraw<'a> {type Target = Cx; fn deref(&self) -> &Self::Target {self.cx}}
49impl<'a> DerefMut for CxDraw<'a> {fn deref_mut(&mut self) -> &mut Self::Target {self.cx}}
50
51impl<'a> Drop for CxDraw<'a> {
52    fn drop(&mut self) {
53        if !self.fonts.borrow_mut().prepare_textures(&mut self.cx) {
54            self.cx.redraw_all();
55        }
56        self.draw_icon_atlas();
57    }
58}
59
60impl<'a> CxDraw<'a> {
61    pub fn new(cx: &'a mut Cx, draw_event: &'a DrawEvent) -> Self {
62        Self::lazy_construct_fonts(cx);
63        Self::lazy_construct_nav_tree(cx);
64        Self::lazy_construct_icon_atlas(cx);
65        cx.redraw_id += 1;
66        let fonts = cx.get_global::<Rc<RefCell<Fonts>>>().clone();
67        fonts.borrow_mut().prepare_atlases_if_needed(cx);
68        let nav_tree_rc = cx.get_global::<CxNavTreeRc>().clone();
69        let icon_atlas_rc = cx.get_global::<CxIconAtlasRc>().clone();
70        Self{
71            fonts,
72            cx: cx,
73            draw_event,
74            pass_stack: Vec::new(),
75            draw_list_stack: Vec::with_capacity(64),
76            nav_tree_rc,
77            icon_atlas_rc,
78            rustybuzz_buffer: Some(UnicodeBuffer::new()),
79        }
80    }
81}
82
83impl<'a> CxDraw<'a>{
84     
85    pub fn lazy_construct_fonts(cx: &mut Cx) -> bool {
86        if cx.has_global::<Rc<RefCell<Fonts>>>() {
87            return false;
88        }
89        let mut fonts = Fonts::new(
90            cx,
91            layouter::Settings::default(),
92        );
93        fonts.define_font_family(0.into(), FontFamilyDefinition {
94            font_ids: vec![]
95        });
96        cx.set_global(Rc::new(RefCell::new(fonts)));
97        true
98    }   
99    
100    pub fn get_current_window_id(&self)->Option<WindowId>{
101        self.cx.get_pass_window_id(self.pass_stack.last().unwrap().pass_id)
102    }
103    
104    pub fn current_dpi_factor(&self) -> f64 {
105        self.pass_stack.last().unwrap().dpi_factor
106    }
107        
108    pub fn inside_pass(&self) -> bool {
109        self.pass_stack.len()>0
110    }
111        
112    pub fn make_child_pass(&mut self, pass: &Pass) {
113        let pass_id = self.pass_stack.last().unwrap().pass_id;
114        let cxpass = &mut self.passes[pass.pass_id()];
115        cxpass.parent = CxPassParent::Pass(pass_id);
116    }
117        
118    pub fn begin_pass(&mut self, pass: &Pass, dpi_override: Option<f64>) {
119        let cxpass = &mut self.passes[pass.pass_id()];
120        cxpass.main_draw_list_id = None;
121        let dpi_factor = if let Some(dpi_override) = dpi_override {dpi_override}
122        else {
123            match cxpass.parent {
124                CxPassParent::Window(window_id) => {
125                    self.passes[pass.pass_id()].pass_rect = Some(CxPassRect::Size(self.windows[window_id].get_inner_size()));
126                    self.get_delegated_dpi_factor(pass.pass_id())
127                }
128                CxPassParent::Pass(pass_id) => {
129                    self.passes[pass.pass_id()].pass_rect = self.passes[pass_id].pass_rect.clone();
130                    self.get_delegated_dpi_factor(pass_id)
131                }
132                _ => {
133                    1.0
134                }
135            }
136        };
137        self.passes[pass.pass_id()].dpi_factor = Some(dpi_factor);
138                
139        self.pass_stack.push(PassStackItem {
140            dpi_factor,
141            draw_list_stack_len: self.draw_list_stack.len(),
142            //turtles_len: self.turtles.len(),
143            pass_id: pass.pass_id()
144        });
145    }
146        
147    pub fn end_pass(&mut self, pass: &Pass) {
148        let stack_item = self.pass_stack.pop().unwrap();
149        if stack_item.pass_id != pass.pass_id() {
150            panic!();
151        }
152                
153        if self.draw_list_stack.len() != stack_item.draw_list_stack_len {
154            panic!("Draw list stack disaligned, forgot an end_view(cx)");
155        }
156        //if self.turtles.len() != stack_item.turtles_len {
157        //    panic!("Turtle stack disaligned, forgot an end_turtle()");
158        //}
159    }
160        
161    pub fn set_pass_area(&mut self, pass: &Pass, area: Area) {
162        self.passes[pass.pass_id()].pass_rect = Some(CxPassRect::Area(area));
163    }
164            
165    pub fn set_pass_area_with_origin(&mut self, pass: &Pass, area: Area, origin:DVec2) {
166        self.passes[pass.pass_id()].pass_rect = Some(CxPassRect::AreaOrigin(area, origin));
167    }
168            
169    pub fn set_pass_shift_scale(&mut self, pass: &Pass, shift: DVec2, scale: DVec2) {
170        self.passes[pass.pass_id()].view_shift = shift;
171        self.passes[pass.pass_id()].view_scale = scale;
172    }
173        
174    /*
175    pub fn set_pass_scaled_area(&mut self, pass: &Pass, area: Area, scale:f64) {
176        self.passes[pass.pass_id()].pass_rect = Some(CxPassRect::ScaledArea(area, scale));
177    }   */
178    
179    pub fn current_pass_size(&self) -> DVec2 {
180        self.cx.get_pass_rect(
181            self.pass_stack.last().unwrap().pass_id, 
182            self.current_dpi_factor()
183        ).map(|v| v.size).unwrap_or(dvec2(0.0,0.0))
184    }
185        
186    pub fn append_sub_draw_list(&mut self, draw_list_2d: &DrawList2d)  {
187        let dl = &mut self.cx.draw_lists[*self.draw_list_stack.last().unwrap()];
188        dl.append_sub_list(self.cx.redraw_id, draw_list_2d.id());
189    }
190    
191    /*pub fn set_sweep_lock(&mut self, lock:Area){
192        *self.overlay_sweep_lock.as_ref().unwrap().borrow_mut() = lock;
193    }
194    
195    pub fn clear_sweep_lock(&mut self, lock:Area){
196        let mut sweep_lock = self.overlay_sweep_lock.as_ref().unwrap().borrow_mut();
197        if *sweep_lock == lock{
198            *sweep_lock = Area::Empty
199        }
200    }*/
201        
202}