1use crate::{
2 app::{AppData},
3 makepad_widgets::*,
4 makepad_platform::os::cx_stdin::*,
5 build_manager::build_manager::BuildManager,
6};
7
8live_design!{
9 use link::shaders::*;
10
11 pub RunView = {{RunView}} {
12 draw_app: {
13 texture tex: texture2d
14 instance recompiling: 0.0
15 instance started: 0.0
16 instance tex_scale: vec2(0.0, 0.0),
17 instance tex_size: vec2(0.0, 0.0),
18 fn pixel(self) -> vec4 {
19 let tp1 = sample2d_rt(self.tex, vec2(0.5/self.tex_size.x,0.5/self.tex_size.y))
21 let tp2 = sample2d_rt(self.tex, vec2(1.5/self.tex_size.x,0.5/self.tex_size.y));
22 let tp = vec2(tp1.r*65280.0 + tp1.b*255.0,tp2.r*65280.0 + tp2.b*255.0);
23 let counter = (self.rect_size * self.dpi_factor) / tp;
25 let tex_scale = tp / self.tex_size;
26 let fb = sample2d_rt(self.tex, self.pos * tex_scale * counter)
27 if fb.r == 1.0 && fb.g == 0.0 && fb.b == 1.0 {
28 return #2
29 }
30 return mix(fb, #4, self.recompiling * 0.4);
31 }
32 }
33 animator: {
34 started = {
35 default: off,
36 off = {
37 from: {all: Forward {duration: 0.05}}
38 apply: {draw_app: {started: 0.0}}
39 }
40 on = {
41 from: {all: Forward {duration: 0.05}}
42 apply: {draw_app: {started: 1.0}}
43 }
44 }
45 recompiling = {
46 default: off,
47 off = {
48 from: {all: Forward {duration: 0.05}}
49 apply: {draw_app: {recompiling: 0.0}}
50 }
51 on = {
52 from: {all: Forward {duration: 0.05}}
53 apply: {draw_app: {recompiling: 1.0}}
54 }
55 }
56 }
57 }
58}
59
60
61#[derive(Live, Widget)]
62pub struct RunView {
63 #[walk] walk: Walk,
64 #[animator] animator: Animator,
65 #[redraw] #[live] draw_app: DrawQuad,
66 #[rust] last_rect: Rect,
68 #[rust(100usize)] redraw_countdown: usize,
69 #[rust] started: bool,
72 #[rust] pub build_id: Option<LiveId>,
73 #[rust] pub window_id: usize,
74 #[rust(WindowKindId::Main)] pub kind_id: WindowKindId,
75}
76
77impl LiveHook for RunView {
78 fn after_new_from_doc(&mut self, cx: &mut Cx) {
79 self.draw_app.set_texture(0, &cx.null_texture());
82 }
83
84 fn after_apply(&mut self, cx: &mut Cx, apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
85 if let ApplyFrom::UpdateFromDoc{..} = apply.from{
86 self.last_rect = Default::default();
87 self.animator_cut(cx, id!(started.on));
88 }
89 }
90}
91
92impl RunView {
93 pub fn draw_complete_and_flip(&mut self, cx: &mut Cx, presentable_draw: &PresentableDraw, manager: &mut BuildManager){
124 let window_id = self.window_id;
125 if self.build_id.is_none(){
126 return
127 }
128 if let Some(v) = manager.active.builds.get_mut(self.build_id.as_ref().unwrap()){
129 let mut try_present_through = |swapchain: &Option<Swapchain<Texture>>| {
134 let swapchain = swapchain.as_ref()?;
135 let drawn = swapchain.get_image(presentable_draw.target_id)?;
136
137 self.draw_app.set_texture(0, &drawn.image);
138 self.draw_app.draw_vars.set_var_instance(cx, id!(tex_scale), &[
139 (presentable_draw.width as f32) / (swapchain.alloc_width as f32),
140 (presentable_draw.height as f32) / (swapchain.alloc_height as f32),
141 ]);
142 self.draw_app.draw_vars.set_var_instance(cx, id!(tex_size), &[
143 (swapchain.alloc_width as f32),
144 (swapchain.alloc_height as f32),
145 ]);
146
147 if !self.started {
148 self.started = true;
149 self.animator_play(cx, id!(started.on));
150 }
151 self.redraw_countdown = 20;
152 self.redraw(cx);
153 Some(())
154 };
155
156 if try_present_through(&v.swapchain_mut(window_id)).is_some() {
157 *v.last_swapchain_with_completed_draws_mut(window_id) = None;
160 } else {
161 try_present_through(&v.last_swapchain_with_completed_draws_mut(window_id));
165 }
166 }
167 }
168
169 pub fn ready_to_start(&mut self, cx: &mut Cx){
170 self.animator_play(cx, id!(recompiling.off));
171 self.last_rect = Default::default();
173 self.redraw(cx);
174 }
175
176 pub fn recompile_started(&mut self, cx: &mut Cx) {
177 self.animator_play(cx, id!(recompiling.on));
178 }
179
180 pub fn redraw(&mut self, cx: &mut Cx) {
181 self.draw_app.redraw(cx);
182 }
183
184
185 pub fn resend_framebuffer(&mut self, _cx: &mut Cx) {
186 self.last_rect = Default::default();
187 }
188
189 pub fn draw_run_view(&mut self, cx: &mut Cx2d, run_view_id: LiveId, manager: &mut BuildManager, walk:Walk) {
190 if self.build_id.is_none(){
191 return
192 }
193 let dpi_factor = cx.current_dpi_factor();
196 let rect = cx.walk_turtle(walk).dpi_snap(dpi_factor);
197 if self.redraw_countdown > 0{
199 self.redraw_countdown -= 1;
200 self.redraw(cx);
201 }
202 if self.last_rect != rect{
203 manager.send_host_to_stdin(run_view_id, HostToStdin::WindowGeomChange {
204 window_id: self.window_id,
205 dpi_factor,
206 left: rect.pos.x,
207 top: rect.pos.y,
208 width: rect.size.x,
209 height: rect.size.y,
210 });
211 }
212 if self.last_rect.size != rect.size {
213
214 let min_width = ((rect.size.x * dpi_factor).ceil() as u32).max(1);
215 let min_height = ((rect.size.y * dpi_factor).ceil() as u32).max(1);
216
217 let active_build_needs_new_swapchain = manager.active.builds
218 .get_mut(&run_view_id)
219 .filter(|v| {
220 v.aux_chan_host_endpoint.is_some()
221 })
222 .filter(|v| {
223 v.swapchain(self.window_id).map(|swapchain| {
224 min_width > swapchain.alloc_width || min_height > swapchain.alloc_height
225 }).unwrap_or(true)
226 });
227
228 if let Some(v) = active_build_needs_new_swapchain {
229
230 if v.last_swapchain_with_completed_draws(self.window_id).is_none() {
235 let chain = v.swapchain_mut(self.window_id).take();
236 *v.last_swapchain_with_completed_draws_mut(self.window_id) = chain;
237 }
238
239 if let Some(swapchain) = v.swapchain_mut(self.window_id) {
243 for pi in &mut swapchain.presentable_images {
244 pi.id = cx_stdin::PresentableImageId::alloc();
245 }
246 }
247
248 let alloc_width = min_width.max(64).next_power_of_two();
251 let alloc_height = min_height.max(64).next_power_of_two();
252
253 let swapchain = v.swapchain_mut(self.window_id).get_or_insert_with(|| {
254 Swapchain::new(self.window_id, alloc_width, alloc_height).images_map(|pi| {
255 Texture::new_with_format(cx, TextureFormat::SharedBGRAu8 {
257 id: pi.id,
258 width: alloc_width as usize,
259 height: alloc_height as usize,
260 initial: true,
261 })
262 })
263 });
264
265 let shared_swapchain = swapchain.images_as_ref().images_map(|pi| {
266 cx.share_texture_for_presentable_image(&pi.image)
267 });
268
269 let shared_swapchain = {
270 #[cfg(target_os = "linux")] {
273 shared_swapchain.images_map(|pi| {
274 pi.send_fds_to_aux_chan(v.aux_chan_host_endpoint.as_ref().unwrap())
275 .map(|pi| pi.image)
276 })
277 }
278 #[cfg(not(target_os = "linux"))] {
279 shared_swapchain.images_map(|pi| std::io::Result::Ok(pi.image))
280 }
281 };
282
283 let mut any_errors = false;
284 for pi in &shared_swapchain.presentable_images {
285 if let Err(err) = &pi.image {
286 error!("failed to send swapchain image to client: {:?}", err);
289 any_errors = true;
290 }
291 }
292
293 if !any_errors {
294 manager.send_host_to_stdin(run_view_id, HostToStdin::Swapchain(
299 shared_swapchain.images_map(|pi| pi.image.unwrap()),
300 ));
301 }
302 }
303 }
304 self.last_rect = rect;
305 self.draw_app.draw_abs(cx, rect);
306 if let Some(ab) = manager.active.builds.get_mut(&run_view_id){
308 ab.app_area.insert(self.window_id, self.draw_app.area());
309 }
310
311 }
312}
313
314impl Widget for RunView {
315
316 fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
317 let run_view_id = scope.path.last().sub(self.window_id as u64);
318 let manager = &mut scope.data.get_mut::<AppData>().unwrap().build_manager;
319 self.draw_run_view(cx, run_view_id, manager, walk);
320 DrawStep::done()
321 }
322
323 fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope){
324 let run_view_id = scope.path.last().sub(self.window_id as u64);
325 let manager = &scope.data.get::<AppData>().unwrap().build_manager;
326
327 self.animator_handle_event(cx, event);
328 match event.hits(cx, self.draw_app.area()) {
330 Hit::FingerDown(_) => {
331 cx.set_key_focus(self.draw_app.area());
332 }
333 Hit::TextInput(e) => {
334 manager.send_host_to_stdin(run_view_id, HostToStdin::TextInput(e));
335 }
336 Hit::KeyDown(e) => {
337 manager.send_host_to_stdin(run_view_id, HostToStdin::KeyDown(e));
338 }
339 Hit::KeyUp(e) => {
340 manager.send_host_to_stdin(run_view_id, HostToStdin::KeyUp(e));
341 }
342 _ => ()
343 }
344
345 }
346
347}