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