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 }
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 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 }
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 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 }