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::default(),
455 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
456 controller: GameController::new()
457 .map_err(|e| GraphicsError::ControllerInit(e.to_string()))?,
458 })
459 }
460}
461
462impl<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> System for SceneHost<SR, SN> {
463 fn window_prefs(&mut self) -> Option<WindowPreferences> {
464 self.window_prefs.clone()
465 }
466
467 fn update(&mut self, timing: &Timing, window: &Window) {
468 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
469 self.pre_post.pre_update(
470 timing,
471 &self.mouse,
472 &self.held_keys,
473 &mut self.scenes,
474 &self.controller,
475 window,
476 );
477 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
478 self.pre_post.pre_update(
479 timing,
480 &self.mouse,
481 &self.held_keys,
482 &mut self.scenes,
483 window,
484 );
485 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
486 self.controller.update();
487 if let Some(scene) = self.scenes.last_mut() {
488 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
489 let result = scene.update(
490 timing,
491 &self.mouse,
492 &self.held_keys,
493 &self.controller,
494 window,
495 );
496 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
497 let result = scene.update(timing, &self.mouse, &self.held_keys, window);
498 match result {
499 SceneUpdateResult::Nothing => {}
500 SceneUpdateResult::Push(pop_current, name) => {
501 if pop_current {
502 self.scenes.pop();
503 }
504 (self.scene_switcher)(&self.style, &mut self.scenes, name);
505 }
506 SceneUpdateResult::Pop(result) => {
507 self.scenes.pop();
508 if let Some(previous) = self.scenes.last_mut() {
509 previous.resuming(result);
510 }
511 }
512 }
513 }
514 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
515 self.pre_post.post_update(
516 timing,
517 &self.mouse,
518 &self.held_keys,
519 &mut self.scenes,
520 &self.controller,
521 window,
522 );
523 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
524 self.pre_post.post_update(
525 timing,
526 &self.mouse,
527 &self.held_keys,
528 &mut self.scenes,
529 window,
530 );
531 if self.scenes.is_empty() {
532 self.should_exit = true;
533 }
534 }
535
536 fn render(&mut self, graphics: &mut Graphics) {
537 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
538 self.pre_post.pre_render(
539 graphics,
540 &self.mouse,
541 &self.held_keys,
542 &mut self.scenes,
543 &self.controller,
544 );
545 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
546 self.pre_post
547 .pre_render(graphics, &self.mouse, &self.held_keys, &mut self.scenes);
548 if let Some(active) = self.scenes.last() {
549 if active.is_dialog() {
550 match self.scenes.iter().rposition(|scn| !scn.is_dialog()) {
551 None => graphics.clear(BLACK),
552 Some(i) => {
553 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
554 self.scenes[i].render(
555 graphics,
556 &self.mouse,
557 &self.held_keys,
558 &self.controller,
559 );
560 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
561 self.scenes[i].render(graphics, &self.mouse, &self.held_keys);
562 }
563 }
564 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
565 active.render(graphics, &self.mouse, &self.held_keys, &self.controller);
566 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
567 active.render(graphics, &self.mouse, &self.held_keys);
568 } else {
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 }
574 }
575 #[cfg(any(feature = "controller", feature = "controller_xinput"))]
576 self.pre_post.post_render(
577 graphics,
578 &self.mouse,
579 &self.held_keys,
580 &mut self.scenes,
581 &self.controller,
582 );
583 #[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
584 self.pre_post
585 .post_render(graphics, &self.mouse, &self.held_keys, &mut self.scenes);
586 }
587
588 fn on_mouse_move(&mut self, mouse_data: &MouseData) {
589 self.mouse = mouse_data.clone();
590 if self.mouse.any_held() {
591 if let Some(active) = self.scenes.last_mut() {
592 active.on_mouse_drag(&self.mouse, &self.held_keys)
593 }
594 }
595 }
596
597 fn on_mouse_down(&mut self, mouse: &MouseData, button: MouseButton) {
598 self.mouse = mouse.clone();
599 self.mouse.add_down(self.mouse.xy, button);
600 if let Some(active) = self.scenes.last_mut() {
601 active.on_mouse_down(&self.mouse, button, &self.held_keys);
602 }
603 }
604
605 fn on_mouse_up(&mut self, mouse: &MouseData, button: MouseButton) {
606 self.mouse = mouse.clone();
607 if let Some(active) = self.scenes.last_mut() {
608 active.on_mouse_up(&self.mouse, button, &self.held_keys);
609 if let Some(down) = self.mouse.is_down(button) {
610 active.on_mouse_click(down, &self.mouse, button, &self.held_keys);
611 }
612 self.mouse.add_up(button);
613 }
614 }
615
616 fn on_scroll(&mut self, mouse: &MouseData, x_diff: isize, y_diff: isize) {
617 self.mouse = mouse.clone();
618 if let Some(active) = self.scenes.last_mut() {
619 active.on_scroll(&self.mouse, x_diff, y_diff, &self.held_keys);
620 }
621 }
622
623 fn on_key_down(&mut self, keys: Vec<KeyCode>) {
624 for key in keys {
625 self.held_keys.insert(key);
626 if let Some(active) = self.scenes.last_mut() {
627 active.on_key_down(key, &self.mouse, &self.held_keys);
628 }
629 }
630 }
631
632 fn on_key_up(&mut self, keys: Vec<KeyCode>) {
633 for key in keys {
634 self.held_keys.remove(&key);
635 if let Some(active) = self.scenes.last_mut() {
636 active.on_key_up(key, &self.mouse, &self.held_keys);
637 }
638 }
639 }
640
641 fn should_exit(&mut self) -> bool {
642 self.should_exit
643 }
644}