use crate::integration::softbuffer_winit::run;
use crate::prelude::*;
use crate::ui::styles::UiStyle;
use rustc_hash::FxHashSet;
use std::fmt::Debug;
use winit::event::MouseButton;
use winit::keyboard::KeyCode;
use winit::window::Window;
#[allow(clippy::too_many_arguments)]
pub fn run_scenes<
SR: Clone + PartialEq + Debug + 'static,
SN: Clone + PartialEq + Debug + 'static,
>(
width: usize,
height: usize,
title: &str,
window_prefs: Option<WindowPreferences>,
scene_switcher: SceneSwitcher<SR, SN>,
init_scene: Box<dyn Scene<SR, SN>>,
options: Options,
pre_post: Box<dyn PrePost<SR, SN>>,
) -> Result<(), GraphicsError> {
let system = Box::new(SceneHost::new(
init_scene,
window_prefs,
scene_switcher,
options.style.clone(),
pre_post,
)?);
run(width, height, title, system, options)?;
Ok(())
}
pub type SceneSwitcher<SR, SN> =
fn(style: &UiStyle, scenes: &mut Vec<Box<dyn Scene<SR, SN>>>, new_scene: SN);
#[derive(Debug, Clone, PartialEq)]
pub enum SceneUpdateResult<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> {
Nothing,
Push(bool, SN),
Pop(Option<SR>),
}
pub trait Scene<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> {
fn id(&self) -> u32 {
0
}
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
#[allow(unused_variables)]
fn render(
&self,
graphics: &mut Graphics,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
controller: &GameController,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
#[allow(unused_variables)]
fn render(&self, graphics: &mut Graphics, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
#[allow(unused_variables)]
fn on_key_down(&mut self, key: KeyCode, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
#[allow(unused_variables)]
fn on_key_up(&mut self, key: KeyCode, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
#[allow(unused_variables)]
fn on_mouse_down(
&mut self,
mouse: &MouseData,
mouse_button: MouseButton,
held_keys: &FxHashSet<KeyCode>,
) {
}
#[allow(unused_variables)]
fn on_mouse_up(
&mut self,
mouse: &MouseData,
mouse_button: MouseButton,
held_keys: &FxHashSet<KeyCode>,
) {
}
#[allow(unused_variables)]
fn on_mouse_click(
&mut self,
down_at: Coord,
mouse: &MouseData,
mouse_button: MouseButton,
held_keys: &FxHashSet<KeyCode>,
) {
}
#[allow(unused_variables)]
fn on_mouse_drag(&mut self, mouse: &MouseData, held_keys: &FxHashSet<KeyCode>) {}
#[allow(unused_variables)]
fn on_scroll(
&mut self,
mouse: &MouseData,
x_diff: isize,
y_diff: isize,
held_keys: &FxHashSet<KeyCode>,
) {
}
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
fn update(
&mut self,
timing: &Timing,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
controller: &GameController,
window: &Window,
) -> SceneUpdateResult<SR, SN>;
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
fn update(
&mut self,
timing: &Timing,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
window: &Window,
) -> SceneUpdateResult<SR, SN>;
#[allow(unused_variables)]
fn resuming(&mut self, result: Option<SR>) {}
fn is_dialog(&self) -> bool {
false
}
}
pub trait PrePost<SR, SN> {
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
fn pre_render(
&mut self,
graphics: &mut Graphics,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
fn post_render(
&mut self,
graphics: &mut Graphics,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
);
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
fn pre_render(
&mut self,
graphics: &mut Graphics,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
controller: &GameController,
);
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
fn post_render(
&mut self,
graphics: &mut Graphics,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
controller: &GameController,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
fn pre_update(
&mut self,
timing: &Timing,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
window: &Window,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
fn post_update(
&mut self,
timing: &Timing,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
window: &Window,
);
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
fn pre_update(
&mut self,
timing: &Timing,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
controller: &GameController,
window: &Window,
);
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
fn post_update(
&mut self,
timing: &Timing,
mouse: &MouseData,
held_keys: &FxHashSet<KeyCode>,
scenes: &mut [Box<dyn Scene<SR, SN>>],
controller: &GameController,
window: &Window,
);
}
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
pub fn empty_pre_post<SR, SN>() -> Box<dyn PrePost<SR, SN>> {
struct Empty {}
impl<SR, SN> PrePost<SR, SN> for Empty {
fn pre_render(
&mut self,
_: &mut Graphics,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
_: &GameController,
) {
}
fn post_render(
&mut self,
_: &mut Graphics,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
_: &GameController,
) {
}
fn pre_update(
&mut self,
_: &Timing,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
_: &GameController,
_: &Window,
) {
}
fn post_update(
&mut self,
_: &Timing,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
_: &GameController,
_: &Window,
) {
}
}
Box::new(Empty {})
}
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
pub fn empty_pre_post<SR, SN>() -> Box<dyn PrePost<SR, SN>> {
struct Empty {}
impl<SR, SN> PrePost<SR, SN> for Empty {
fn pre_render(
&mut self,
_: &mut Graphics,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
) {
}
fn post_render(
&mut self,
_: &mut Graphics,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
) {
}
fn pre_update(
&mut self,
_: &Timing,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
_: &Window,
) {
}
fn post_update(
&mut self,
_: &Timing,
_: &MouseData,
_: &FxHashSet<KeyCode>,
_: &mut [Box<dyn Scene<SR, SN>>],
_: &Window,
) {
}
}
Box::new(Empty {})
}
struct SceneHost<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> {
should_exit: bool,
held_keys: FxHashSet<KeyCode>,
scenes: Vec<Box<dyn Scene<SR, SN>>>,
window_prefs: Option<WindowPreferences>,
scene_switcher: SceneSwitcher<SR, SN>,
style: UiStyle,
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
controller: GameController,
mouse: MouseData,
pre_post: Box<dyn PrePost<SR, SN>>,
}
impl<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> SceneHost<SR, SN> {
pub fn new(
init_scene: Box<dyn Scene<SR, SN>>,
window_prefs: Option<WindowPreferences>,
scene_switcher: SceneSwitcher<SR, SN>,
style: UiStyle,
pre_post: Box<dyn PrePost<SR, SN>>,
) -> Result<Self, GraphicsError> {
Ok(Self {
pre_post,
should_exit: false,
held_keys: FxHashSet::default(),
scenes: vec![init_scene],
window_prefs,
scene_switcher,
style,
mouse: MouseData {
xy: Default::default(),
buttons: Default::default(),
},
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
controller: GameController::new()
.map_err(|e| GraphicsError::ControllerInit(e.to_string()))?,
})
}
}
impl<SR: Clone + PartialEq + Debug, SN: Clone + PartialEq + Debug> System for SceneHost<SR, SN> {
fn window_prefs(&mut self) -> Option<WindowPreferences> {
self.window_prefs.clone()
}
fn update(&mut self, timing: &Timing, window: &Window) {
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
self.pre_post.pre_update(
timing,
&self.mouse,
&self.held_keys,
&mut self.scenes,
&self.controller,
window,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
self.pre_post.pre_update(
timing,
&self.mouse,
&self.held_keys,
&mut self.scenes,
window,
);
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
self.controller.update();
if let Some(scene) = self.scenes.last_mut() {
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
let result = scene.update(
timing,
&self.mouse,
&self.held_keys,
&self.controller,
window,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
let result = scene.update(timing, &self.mouse, &self.held_keys, window);
match result {
SceneUpdateResult::Nothing => {}
SceneUpdateResult::Push(pop_current, name) => {
if pop_current {
self.scenes.pop();
}
(self.scene_switcher)(&self.style, &mut self.scenes, name);
}
SceneUpdateResult::Pop(result) => {
self.scenes.pop();
if let Some(previous) = self.scenes.last_mut() {
previous.resuming(result);
}
}
}
}
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
self.pre_post.post_update(
timing,
&self.mouse,
&self.held_keys,
&mut self.scenes,
&self.controller,
window,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
self.pre_post.post_update(
timing,
&self.mouse,
&self.held_keys,
&mut self.scenes,
window,
);
if self.scenes.is_empty() {
self.should_exit = true;
}
}
fn render(&mut self, graphics: &mut Graphics) {
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
self.pre_post.pre_render(
graphics,
&self.mouse,
&self.held_keys,
&mut self.scenes,
&self.controller,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
self.pre_post
.pre_render(graphics, &self.mouse, &self.held_keys, &mut self.scenes);
if let Some(active) = self.scenes.last() {
if active.is_dialog() {
match self.scenes.iter().rposition(|scn| !scn.is_dialog()) {
None => graphics.clear(BLACK),
Some(i) => {
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
self.scenes[i].render(
graphics,
&self.mouse,
&self.held_keys,
&self.controller,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
self.scenes[i].render(graphics, &self.mouse, &self.held_keys);
}
}
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
active.render(graphics, &self.mouse, &self.held_keys, &self.controller);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
active.render(graphics, &self.mouse, &self.held_keys);
} else {
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
active.render(graphics, &self.mouse, &self.held_keys, &self.controller);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
active.render(graphics, &self.mouse, &self.held_keys);
}
}
#[cfg(any(feature = "controller", feature = "controller_xinput"))]
self.pre_post.post_render(
graphics,
&self.mouse,
&self.held_keys,
&mut self.scenes,
&self.controller,
);
#[cfg(not(any(feature = "controller", feature = "controller_xinput")))]
self.pre_post
.post_render(graphics, &self.mouse, &self.held_keys, &mut self.scenes);
}
fn on_mouse_move(&mut self, mouse: &MouseData) {
self.mouse.xy = mouse.xy;
if self.mouse.any_held() {
if let Some(active) = self.scenes.last_mut() {
active.on_mouse_drag(&self.mouse, &self.held_keys)
}
}
}
fn on_mouse_down(&mut self, mouse: &MouseData, button: MouseButton) {
self.mouse.xy = mouse.xy;
self.mouse.add_down(self.mouse.xy, button);
if let Some(active) = self.scenes.last_mut() {
active.on_mouse_down(&self.mouse, button, &self.held_keys);
}
}
fn on_mouse_up(&mut self, mouse: &MouseData, button: MouseButton) {
self.mouse.xy = mouse.xy;
if let Some(active) = self.scenes.last_mut() {
active.on_mouse_up(&self.mouse, button, &self.held_keys);
if let Some(down) = self.mouse.is_down(button) {
active.on_mouse_click(down, &self.mouse, button, &self.held_keys);
}
self.mouse.add_up(button);
}
}
fn on_scroll(&mut self, mouse: &MouseData, x_diff: isize, y_diff: isize) {
self.mouse.xy = mouse.xy;
if let Some(active) = self.scenes.last_mut() {
active.on_scroll(&self.mouse, x_diff, y_diff, &self.held_keys);
}
}
fn on_key_down(&mut self, keys: Vec<KeyCode>) {
for key in keys {
self.held_keys.insert(key);
if let Some(active) = self.scenes.last_mut() {
active.on_key_down(key, &self.mouse, &self.held_keys);
}
}
}
fn on_key_up(&mut self, keys: Vec<KeyCode>) {
for key in keys {
self.held_keys.remove(&key);
if let Some(active) = self.scenes.last_mut() {
active.on_key_up(key, &self.mouse, &self.held_keys);
}
}
}
fn should_exit(&mut self) -> bool {
self.should_exit
}
}