makepad_studio/build_manager/
run_view.rs1use crate::{
2 makepad_draw::*,
3 makepad_widgets::*,
4 makepad_platform::os::cx_stdin::*,
5 build_manager::build_manager::BuildManager,
6};
7
8live_design!{
9 import makepad_draw::shader::std::*;
10
11 RunView = {{RunView}} {
12 frame_delta: 0.008,
13 draw_app: {
14 texture tex: texture2d
15 instance recompiling: 0.0
16 instance started: 0.0
17 instance tex_scale: vec2(0.0, 0.0),
18 fn pixel(self) -> vec4 {
19 let fb = sample2d_rt(self.tex, self.pos * self.tex_scale)
21 if fb.r == 1.0 && fb.g == 0.0 && fb.b == 1.0 {
22 return #2
23 }
24 return mix(#2,mix(fb, #4, self.recompiling * 0.4),self.started);
25 }
26 }
27 animator: {
28 started = {
29 default: off,
30 off = {
31 from: {all: Forward {duration: 0.05}}
32 apply: {draw_app: {started: 0.0}}
33 }
34 on = {
35 from: {all: Forward {duration: 0.05}}
36 apply: {draw_app: {started: 1.0}}
37 }
38 }
39 recompiling = {
40 default: off,
41 off = {
42 from: {all: Forward {duration: 0.05}}
43 apply: {draw_app: {recompiling: 0.0}}
44 }
45 on = {
46 from: {all: Forward {duration: 0.05}}
47 apply: {draw_app: {recompiling: 1.0}}
48 }
49 }
50 }
51 }
52}
53
54
55#[derive(Live)]
56pub struct RunView {
57 #[walk] walk: Walk,
58 #[rust] draw_state: DrawStateWrap<Walk>,
59 #[animator] animator: Animator,
60 #[live] tex_scale: Vec2,
61 #[live] draw_app: DrawQuad,
62 #[live] frame_delta: f64,
63 #[rust] last_size: DVec2,
64 #[rust] tick: NextFrame,
65 #[rust] timer: Timer,
66 #[rust(100usize)] redraw_countdown: usize,
67 #[rust] time: f64,
68 #[rust] frame: u64,
69 #[rust] started: bool,
70}
71
72
73impl LiveHook for RunView {
74 fn before_live_design(cx: &mut Cx) {
75 register_widget!(cx, RunView)
76 }
77
78 fn after_new_from_doc(&mut self, cx: &mut Cx) {
79 self.tick = cx.new_next_frame(); self.time = 0.0;
81 self.draw_app.set_texture(0, &cx.null_texture());
82 }
83}
84
85impl RunView {
86
87 pub fn run_tick(&mut self, cx: &mut Cx, time: f64, run_view_id: LiveId, manager: &mut BuildManager) {
88 self.frame += 1;
89 manager.send_host_to_stdin(run_view_id, HostToStdin::Tick {
90 buffer_id: run_view_id.0,
91 frame: 0,
92 time: time
93 });
94 if self.redraw_countdown>0 {
95 self.redraw_countdown -= 1;
96 self.redraw(cx);
97 self.tick = cx.new_next_frame();
98 }
99 else {
100 self.timer = cx.start_timeout(0.008);
101 }
102 }
103
104 pub fn pump_event_loop(&mut self, cx: &mut Cx, event: &Event, run_view_id: LiveId, manager: &mut BuildManager) {
105
106 self.animator_handle_event(cx, event);
107 if let Some(te) = self.timer.is_event(event) {
108 self.run_tick(cx, te.time.unwrap_or(0.0), run_view_id, manager)
109 }
110 if let Some(te) = self.tick.is_event(event) {
111 self.run_tick(cx, te.time, run_view_id, manager)
112 }
113 }
114
115 pub fn handle_event(&mut self, cx: &mut Cx, event: &Event, run_view_id: LiveId, manager: &mut BuildManager) {
116
117 self.animator_handle_event(cx, event);
118
119 match event.hits(cx, self.draw_app.area()) {
121 Hit::FingerDown(_) => {
122 cx.set_key_focus(self.draw_app.area());
123 }
124 Hit::KeyDown(e) => {
125 manager.send_host_to_stdin(run_view_id, HostToStdin::KeyDown(e));
126 }
127 Hit::KeyUp(e) => {
128 manager.send_host_to_stdin(run_view_id, HostToStdin::KeyUp(e));
129 }
130 _ => ()
131 }
132 let rect = self.draw_app.area().get_rect(cx);
133 match event {
134 Event::MouseDown(e) => {
135 let rel = e.abs - rect.pos;
136 manager.send_host_to_stdin(run_view_id, HostToStdin::MouseDown(StdinMouseDown {
137 time: e.time,
138 x: rel.x,
139 y: rel.y,
140 button: e.button,
141 }));
142 }
143 Event::MouseMove(e) => {
144 let rel = e.abs - rect.pos;
145 manager.send_host_to_stdin(run_view_id, HostToStdin::MouseMove(StdinMouseMove {
146 time: e.time,
147 x: rel.x,
148 y: rel.y,
149 }));
150 }
151 Event::MouseUp(e) => {
152 let rel = e.abs - rect.pos;
153 manager.send_host_to_stdin(run_view_id, HostToStdin::MouseUp(StdinMouseUp {
154 time: e.time,
155 button: e.button,
156 x: rel.x,
157 y: rel.y,
158 }));
159 }
160 Event::Scroll(e) => {
161 let rel = e.abs - rect.pos;
162 manager.send_host_to_stdin(run_view_id, HostToStdin::Scroll(StdinScroll {
163 is_mouse: e.is_mouse,
164 time: e.time,
165 x: rel.x,
166 y: rel.y,
167 sx: e.scroll.x,
168 sy: e.scroll.y
169 }));
170 }
171 _ => ()
172 }
173 }
174
175 pub fn handle_stdin_to_host(&mut self, cx: &mut Cx, msg: &StdinToHost, run_view_id: LiveId, manager: &mut BuildManager) {
176 match msg {
177
178 StdinToHost::SetCursor(cursor) => {
179 cx.set_cursor(*cursor)
180 }
181 StdinToHost::ReadyToStart => {
182 self.animator_play(cx, id!(recompiling.off));
183 self.last_size = Default::default();
185 self.redraw(cx);
186 }
187 &StdinToHost::DrawCompleteAndFlip(presentable_draw) => {
188 if let Some(v) = manager.active.builds.values_mut().find(|v| v.run_view_id == run_view_id) {
189 let mut try_present_through = |swapchain: &Option<Swapchain<Texture>>| {
194 let swapchain = swapchain.as_ref()?;
195 let drawn = swapchain.get_image(presentable_draw.target_id)?;
196 self.draw_app.set_texture(0, &drawn.image);
197 self.draw_app.draw_vars.set_var_instance(cx, id!(tex_scale), &[
198 (presentable_draw.width as f32) / (swapchain.alloc_width as f32),
199 (presentable_draw.height as f32) / (swapchain.alloc_height as f32),
200 ]);
201
202 if !self.started {
203 self.started = true;
204 self.animator_play(cx, id!(started.on));
205 }
206 self.redraw_countdown = 20;
207
208 Some(())
209 };
210
211 if try_present_through(&v.swapchain).is_some() {
212 v.last_swapchain_with_completed_draws = None;
215 } else {
216 try_present_through(&v.last_swapchain_with_completed_draws);
220 }
221 }
222 }
223 }
224 }
225
226 pub fn redraw(&mut self, cx: &mut Cx) {
227 self.draw_app.redraw(cx);
228 }
229
230
231 pub fn resend_framebuffer(&mut self, _cx: &mut Cx) {
232 self.last_size = dvec2(0.0,0.0);
233 }
234
235
236 pub fn draw(&mut self, cx: &mut Cx2d, run_view_id: LiveId, manager: &mut BuildManager) {
237
238 let dpi_factor = cx.current_dpi_factor();
241 let walk = if let Some(walk) = self.draw_state.get() {walk}else {panic!()};
242 let rect = cx.walk_turtle(walk).dpi_snap(dpi_factor);
243 if self.last_size != rect.size {
246 self.last_size = rect.size;
247 self.redraw_countdown = 20;
248
249 let DVec2 { x: inner_width, y: inner_height } = self.last_size;
252
253 manager.send_host_to_stdin(run_view_id, HostToStdin::WindowGeomChange {
257 dpi_factor,
258 inner_width,
259 inner_height,
260 });
261
262 let min_width = ((inner_width * dpi_factor).ceil() as u32).max(1);
263 let min_height = ((inner_height * dpi_factor).ceil() as u32).max(1);
264 let active_build_needs_new_swapchain = manager.active.builds.values_mut()
265 .find(|v| v.run_view_id == run_view_id)
266 .filter(|v| v.aux_chan_host_endpoint.is_some())
267 .filter(|v| {
268 v.swapchain.as_ref().map(|swapchain| {
269 min_width > swapchain.alloc_width || min_height > swapchain.alloc_height
270 }).unwrap_or(true)
271 });
272 if let Some(v) = active_build_needs_new_swapchain {
273 if v.last_swapchain_with_completed_draws.is_none() {
278 v.last_swapchain_with_completed_draws = v.swapchain.take();
279 }
280
281 if let Some(swapchain) = &mut v.swapchain {
285 for pi in &mut swapchain.presentable_images {
286 pi.id = cx_stdin::PresentableImageId::alloc();
287 }
288 }
289 let swapchain = v.swapchain.get_or_insert_with(|| {
290 Swapchain::new(0, 0).images_map(|_| Texture::new(cx))
291 });
292
293 swapchain.alloc_width = min_width.max(64).next_power_of_two();
296 swapchain.alloc_height = min_height.max(64).next_power_of_two();
297
298 let shared_swapchain = swapchain.images_as_ref().images_map(|pi| {
300 pi.image.set_desc(cx, TextureDesc {
301 format: TextureFormat::SharedBGRA(pi.id),
302 width: Some(swapchain.alloc_width as usize),
303 height: Some(swapchain.alloc_height as usize),
304 });
305 cx.share_texture_for_presentable_image(&pi.image)
306 });
307
308 let shared_swapchain = {
309 #[cfg(target_os = "linux")] {
312 shared_swapchain.images_map(|pi| {
313 pi.send_fds_to_aux_chan(v.aux_chan_host_endpoint.as_ref().unwrap())
314 .map(|pi| pi.image)
315 })
316 }
317 #[cfg(not(target_os = "linux"))] {
318 shared_swapchain.images_map(|pi| std::io::Result::Ok(pi.image))
319 }
320 };
321
322 let mut any_errors = false;
323 for pi in &shared_swapchain.presentable_images {
324 if let Err(err) = &pi.image {
325 error!("failed to send swapchain image to client: {:?}", err);
328 any_errors = true;
329 }
330 }
331
332 if !any_errors {
333 manager.send_host_to_stdin(run_view_id, HostToStdin::Swapchain(
337 shared_swapchain.images_map(|pi| pi.image.unwrap()),
338 ));
339 }
340 }
341 }
342
343 self.draw_app.draw_abs(cx, rect);
344 }
345}
346
347impl Widget for RunView {
348 fn walk(&mut self, _cx: &mut Cx) -> Walk {
349 self.walk
350 }
351
352 fn redraw(&mut self, cx: &mut Cx) {
353 self.draw_app.redraw(cx)
354 }
355
356 fn draw_walk_widget(&mut self, cx: &mut Cx2d, walk: Walk) -> WidgetDraw {
357 if self.draw_state.begin(cx, walk) {
358 return WidgetDraw::hook_above();
359 }
360 self.draw_state.end();
361 WidgetDraw::done()
362 }
363}
364
365#[derive(Clone, PartialEq, WidgetRef)]
366pub struct RunViewRef(WidgetRef);
367
368impl RunViewRef {
369
370 pub fn recompile_started(&self, cx: &mut Cx) {
371 if let Some(mut inner) = self.borrow_mut() {
372 inner.animator_play(cx, id!(recompiling.on));
373 }
374 }
375
376}