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