1use crate::integration::softbuffer_winit::run;
2use crate::prelude::*;
3use crate::ui::styles::UiStyle;
4use rustc_hash::FxHashSet;
5use std::fmt::Debug;
6use winit::event::MouseButton;
7use winit::keyboard::KeyCode;
8use winit::window::Window;
9
10#[allow(clippy::too_many_arguments)]
23pub fn run_scenes<
24 SR: Clone + PartialEq + Debug + 'static,
25 SN: Clone + PartialEq + Debug + 'static,
26>(
27 width: usize,
28 height: usize,
29 title: &str,
30 window_prefs: Option<WindowPreferences>,
31 scene_switcher: SceneSwitcher<SR, SN>,
32 init_scene: Box<dyn Scene<SR, SN>>,
33 options: Options,
34 pre_post: Box<dyn PrePost<SR, SN>>,
35) -> Result<(), GraphicsError> {
36 let system = Box::new(SceneHost::new(
37 init_scene,
38 window_prefs,
39 scene_switcher,
40 options.style.clone(),
41 pre_post,
42 )?);
43 run(width, height, title, system, options)?;
44 Ok(())
45}
46
47pub type SceneSwitcher<SR, SN> =
57 fn(style: &UiStyle, scenes: &mut Vec<Box<dyn Scene<SR, SN>>>, new_scene: SN);
58
59#[derive(Debug, Clone, PartialEq)]
61pub enum SceneUpdateResult<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> {
62 Nothing,
64 Push(bool, SN),
69 Pop(Option<SR>),
71}
72
73pub trait Scene<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> {
85 fn id(&self) -> u32 {
86 0
87 }
88
89 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
96 #[allow(unused_variables)]
97 fn render(
98 &self,
99 graphics: &mut Graphics,
100 mouse: &MouseData,
101 held_keys: &FxHashSet<KeyCode>,
102 controller: &GameController,
103 );
104 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
111 #[allow(unused_variables)]
112 fn render(&self, graphics: &mut Graphics, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
113 #[allow(unused_variables)]
120 fn on_key_down(&mut self, key: KeyCode, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
121 #[allow(unused_variables)]
128 fn on_key_up(&mut self, key: KeyCode, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
129 #[allow(unused_variables)]
136 fn on_mouse_down(
137 &mut self,
138 mouse: &MouseData,
139 mouse_button: MouseButton,
140 held_keys: &FxHashSet<KeyCode>,
141 ) {
142 }
143 #[allow(unused_variables)]
152 fn on_mouse_up(
153 &mut self,
154 mouse: &MouseData,
155 mouse_button: MouseButton,
156 held_keys: &FxHashSet<KeyCode>,
157 ) {
158 }
159 #[allow(unused_variables)]
169 fn on_mouse_click(
170 &mut self,
171 down_at: Coord,
172 mouse: &MouseData,
173 mouse_button: MouseButton,
174 held_keys: &FxHashSet<KeyCode>,
175 ) {
176 }
177 #[allow(unused_variables)]
183 fn on_mouse_drag(&mut self, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
184 #[allow(unused_variables)]
192 fn on_scroll(
193 &mut self,
194 mouse: &MouseData,
195 x_diff: isize,
196 y_diff: isize,
197 held_keys: &FxHashSet<KeyCode>,
198 ) {
199 }
200 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
215 fn update(
216 &mut self,
217 timing: &Timing,
218 mouse: &MouseData,
219 held_keys: &FxHashSet<KeyCode>,
220 controller: &GameController,
221 window: &Window,
222 ) -> SceneUpdateResult<SR, SN>;
223 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
238 fn update(
239 &mut self,
240 timing: &Timing,
241 mouse: &MouseData,
242 held_keys: &FxHashSet<KeyCode>,
243 window: &Window,
244 ) -> SceneUpdateResult<SR, SN>;
245 #[allow(unused_variables)]
250 fn resuming(&mut self, result: Option<SR>) {}
251 fn is_dialog(&self) -> bool {
254 false
255 }
256}
257
258pub trait PrePost<SR, SN> {
259 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
260 fn pre_render(
261 &mut self,
262 graphics: &mut Graphics,
263 mouse: &MouseData,
264 held_keys: &FxHashSet<KeyCode>,
265 scenes: &mut [Box<dyn Scene<SR, SN>>],
266 );
267 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
268 fn post_render(
269 &mut self,
270 graphics: &mut Graphics,
271 mouse: &MouseData,
272 held_keys: &FxHashSet<KeyCode>,
273 scenes: &mut [Box<dyn Scene<SR, SN>>],
274 );
275 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
276 fn pre_render(
277 &mut self,
278 graphics: &mut Graphics,
279 mouse: &MouseData,
280 held_keys: &FxHashSet<KeyCode>,
281 scenes: &mut [Box<dyn Scene<SR, SN>>],
282 controller: &GameController,
283 );
284 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
285 fn post_render(
286 &mut self,
287 graphics: &mut Graphics,
288 mouse: &MouseData,
289 held_keys: &FxHashSet<KeyCode>,
290 scenes: &mut [Box<dyn Scene<SR, SN>>],
291 controller: &GameController,
292 );
293 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
294 fn pre_update(
295 &mut self,
296 timing: &Timing,
297 mouse: &MouseData,
298 held_keys: &FxHashSet<KeyCode>,
299 scenes: &mut [Box<dyn Scene<SR, SN>>],
300 window: &Window,
301 );
302 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
303 fn post_update(
304 &mut self,
305 timing: &Timing,
306 mouse: &MouseData,
307 held_keys: &FxHashSet<KeyCode>,
308 scenes: &mut [Box<dyn Scene<SR, SN>>],
309 window: &Window,
310 );
311 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
312 fn pre_update(
313 &mut self,
314 timing: &Timing,
315 mouse: &MouseData,
316 held_keys: &FxHashSet<KeyCode>,
317 scenes: &mut [Box<dyn Scene<SR, SN>>],
318 controller: &GameController,
319 window: &Window,
320 );
321 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
322 fn post_update(
323 &mut self,
324 timing: &Timing,
325 mouse: &MouseData,
326 held_keys: &FxHashSet<KeyCode>,
327 scenes: &mut [Box<dyn Scene<SR, SN>>],
328 controller: &GameController,
329 window: &Window,
330 );
331}
332#[cfg(any(feature = "controller", feature = "controller_xinput"))]
333pub fn empty_pre_post<SR, SN>() -> Box<dyn PrePost<SR, SN>> {
334 struct Empty {}
335 impl<SR, SN> PrePost<SR, SN> for Empty {
336 fn pre_render(
337 &mut self,
338 _: &mut Graphics,
339 _: &MouseData,
340 _: &FxHashSet<KeyCode>,
341 _: &mut [Box<dyn Scene<SR, SN>>],
342 _: &GameController,
343 ) {
344 }
345
346 fn post_render(
347 &mut self,
348 _: &mut Graphics,
349 _: &MouseData,
350 _: &FxHashSet<KeyCode>,
351 _: &mut [Box<dyn Scene<SR, SN>>],
352 _: &GameController,
353 ) {
354 }
355
356 fn pre_update(
357 &mut self,
358 _: &Timing,
359 _: &MouseData,
360 _: &FxHashSet<KeyCode>,
361 _: &mut [Box<dyn Scene<SR, SN>>],
362 _: &GameController,
363 _: &Window,
364 ) {
365 }
366
367 fn post_update(
368 &mut self,
369 _: &Timing,
370 _: &MouseData,
371 _: &FxHashSet<KeyCode>,
372 _: &mut [Box<dyn Scene<SR, SN>>],
373 _: &GameController,
374 _: &Window,
375 ) {
376 }
377 }
378 Box::new(Empty {})
379}
380#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
381pub fn empty_pre_post<SR, SN>() -> Box<dyn PrePost<SR, SN>> {
382 struct Empty {}
383 impl<SR, SN> PrePost<SR, SN> for Empty {
384 fn pre_render(
385 &mut self,
386 _: &mut Graphics,
387 _: &MouseData,
388 _: &FxHashSet<KeyCode>,
389 _: &mut [Box<dyn Scene<SR, SN>>],
390 ) {
391 }
392
393 fn post_render(
394 &mut self,
395 _: &mut Graphics,
396 _: &MouseData,
397 _: &FxHashSet<KeyCode>,
398 _: &mut [Box<dyn Scene<SR, SN>>],
399 ) {
400 }
401
402 fn pre_update(
403 &mut self,
404 _: &Timing,
405 _: &MouseData,
406 _: &FxHashSet<KeyCode>,
407 _: &mut [Box<dyn Scene<SR, SN>>],
408 _: &Window,
409 ) {
410 }
411
412 fn post_update(
413 &mut self,
414 _: &Timing,
415 _: &MouseData,
416 _: &FxHashSet<KeyCode>,
417 _: &mut [Box<dyn Scene<SR, SN>>],
418 _: &Window,
419 ) {
420 }
421 }
422 Box::new(Empty {})
423}
424
425struct SceneHost<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> {
426 should_exit: bool,
427 held_keys: FxHashSet<KeyCode>,
428 scenes: Vec<Box<dyn Scene<SR, SN>>>,
429 window_prefs: Option<WindowPreferences>,
430 scene_switcher: SceneSwitcher<SR, SN>,
431 style: UiStyle,
432 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
433 controller: GameController,
434 mouse: MouseData,
435 pre_post: Box<dyn PrePost<SR, SN>>,
436}
437
438impl<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> SceneHost<SR, SN> {
439 pub fn new(
440 init_scene: Box<dyn Scene<SR, SN>>,
441 window_prefs: Option<WindowPreferences>,
442 scene_switcher: SceneSwitcher<SR, SN>,
443 style: UiStyle,
444 pre_post: Box<dyn PrePost<SR, SN>>,
445 ) -> Result<Self, GraphicsError> {
446 Ok(Self {
447 pre_post,
448 should_exit: false,
449 held_keys: FxHashSet::default(),
450 scenes: vec![init_scene],
451 window_prefs,
452 scene_switcher,
453 style,
454 mouse: MouseData {
455 xy: Default::default(),
456 buttons: Default::default(),
457 },
458 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
459 controller: GameController::new()
460 .map_err(|e| GraphicsError::ControllerInit(e.to_string()))?,
461 })
462 }
463}
464
465impl<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> System for SceneHost<SR, SN> {
466 fn window_prefs(&mut self) -> Option<WindowPreferences> {
467 self.window_prefs.clone()
468 }
469
470 fn update(&mut self, timing: &Timing, window: &Window) {
471 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
472 self.pre_post.pre_update(
473 timing,
474 &self.mouse,
475 &self.held_keys,
476 &mut self.scenes,
477 &self.controller,
478 window,
479 );
480 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
481 self.pre_post.pre_update(
482 timing,
483 &self.mouse,
484 &self.held_keys,
485 &mut self.scenes,
486 window,
487 );
488 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
489 self.controller.update();
490 if let Some(scene) = self.scenes.last_mut() {
491 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
492 let result = scene.update(
493 timing,
494 &self.mouse,
495 &self.held_keys,
496 &self.controller,
497 window,
498 );
499 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
500 let result = scene.update(timing, &self.mouse, &self.held_keys, window);
501 match result {
502 SceneUpdateResult::Nothing => {}
503 SceneUpdateResult::Push(pop_current, name) => {
504 if pop_current {
505 self.scenes.pop();
506 }
507 (self.scene_switcher)(&self.style, &mut self.scenes, name);
508 }
509 SceneUpdateResult::Pop(result) => {
510 self.scenes.pop();
511 if let Some(previous) = self.scenes.last_mut() {
512 previous.resuming(result);
513 }
514 }
515 }
516 }
517 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
518 self.pre_post.post_update(
519 timing,
520 &self.mouse,
521 &self.held_keys,
522 &mut self.scenes,
523 &self.controller,
524 window,
525 );
526 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
527 self.pre_post.post_update(
528 timing,
529 &self.mouse,
530 &self.held_keys,
531 &mut self.scenes,
532 window,
533 );
534 if self.scenes.is_empty() {
535 self.should_exit = true;
536 }
537 }
538
539 fn render(&mut self, graphics: &mut Graphics) {
540 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
541 self.pre_post.pre_render(
542 graphics,
543 &self.mouse,
544 &self.held_keys,
545 &mut self.scenes,
546 &self.controller,
547 );
548 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
549 self.pre_post
550 .pre_render(graphics, &self.mouse, &self.held_keys, &mut self.scenes);
551 if let Some(active) = self.scenes.last() {
552 if active.is_dialog() {
553 match self.scenes.iter().rposition(|scn| !scn.is_dialog()) {
554 None => graphics.clear(BLACK),
555 Some(i) => {
556 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
557 self.scenes[i].render(
558 graphics,
559 &self.mouse,
560 &self.held_keys,
561 &self.controller,
562 );
563 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
564 self.scenes[i].render(graphics, &self.mouse, &self.held_keys);
565 }
566 }
567 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
568 active.render(graphics, &self.mouse, &self.held_keys, &self.controller);
569 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
570 active.render(graphics, &self.mouse, &self.held_keys);
571 } else {
572 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
573 active.render(graphics, &self.mouse, &self.held_keys, &self.controller);
574 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
575 active.render(graphics, &self.mouse, &self.held_keys);
576 }
577 }
578 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
579 self.pre_post.post_render(
580 graphics,
581 &self.mouse,
582 &self.held_keys,
583 &mut self.scenes,
584 &self.controller,
585 );
586 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
587 self.pre_post
588 .post_render(graphics, &self.mouse, &self.held_keys, &mut self.scenes);
589 }
590
591 fn on_mouse_move(&mut self, mouse: &MouseData) {
592 self.mouse.xy = mouse.xy;
593 if self.mouse.any_held() {
594 if let Some(active) = self.scenes.last_mut() {
595 active.on_mouse_drag(&self.mouse, &self.held_keys)
596 }
597 }
598 }
599
600 fn on_mouse_down(&mut self, mouse: &MouseData, button: MouseButton) {
601 self.mouse.xy = mouse.xy;
602 self.mouse.add_down(self.mouse.xy, button);
603 if let Some(active) = self.scenes.last_mut() {
604 active.on_mouse_down(&self.mouse, button, &self.held_keys);
605 }
606 }
607
608 fn on_mouse_up(&mut self, mouse: &MouseData, button: MouseButton) {
609 self.mouse.xy = mouse.xy;
610 if let Some(active) = self.scenes.last_mut() {
611 active.on_mouse_up(&self.mouse, button, &self.held_keys);
612 if let Some(down) = self.mouse.is_down(button) {
613 active.on_mouse_click(down, &self.mouse, button, &self.held_keys);
614 }
615 self.mouse.add_up(button);
616 }
617 }
618
619 fn on_scroll(&mut self, mouse: &MouseData, x_diff: isize, y_diff: isize) {
620 self.mouse.xy = mouse.xy;
621 if let Some(active) = self.scenes.last_mut() {
622 active.on_scroll(&self.mouse, x_diff, y_diff, &self.held_keys);
623 }
624 }
625
626 fn on_key_down(&mut self, keys: Vec<KeyCode>) {
627 for key in keys {
628 self.held_keys.insert(key);
629 if let Some(active) = self.scenes.last_mut() {
630 active.on_key_down(key, &self.mouse, &self.held_keys);
631 }
632 }
633 }
634
635 fn on_key_up(&mut self, keys: Vec<KeyCode>) {
636 for key in keys {
637 self.held_keys.remove(&key);
638 if let Some(active) = self.scenes.last_mut() {
639 active.on_key_up(key, &self.mouse, &self.held_keys);
640 }
641 }
642 }
643
644 fn should_exit(&mut self) -> bool {
645 self.should_exit
646 }
647}