From 031736bea60a709e96bb04e442799970315ae5a5 Mon Sep 17 00:00:00 2001 From: CrispyPin Date: Sun, 30 Mar 2025 17:13:33 +0200 Subject: [PATCH] wrap input bindings in config struct --- src/config.rs | 8 ++++++++ src/editor.rs | 25 ++++++++++++------------- src/input.rs | 5 +++-- src/lib.rs | 27 +++++++++++++++++++++++++-- src/main.rs | 50 +++++++++++++++++++++++++------------------------- src/util.rs | 16 +++++++--------- 6 files changed, 80 insertions(+), 51 deletions(-) create mode 100644 src/config.rs diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..39fee1d --- /dev/null +++ b/src/config.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +use crate::input::Input; + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub input: Input, +} diff --git a/src/editor.rs b/src/editor.rs index c2cf980..ef4af7f 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -453,12 +453,12 @@ impl Editor { pub fn update(&mut self, rl: &RaylibHandle, globals: &mut Globals) { self.tooltip.init_frame(rl); - self.mouse = MouseInput::get(rl); - if self.popup != Popup::None { - self.mouse.clear(); + self.mouse.clear(); + if self.popup == Popup::None { + self.mouse.update(rl); } - if globals.input.is_pressed(ActionId::ToggleMenu) { + if globals.is_pressed(ActionId::ToggleMenu) { self.popup = match self.popup { Popup::Success | Popup::Failure => { self.dismissed_end = true; @@ -496,10 +496,10 @@ impl Editor { self.step_time = avg_step_time; self.max_step_time = avg_step_time.max(self.max_step_time); } - if globals.input.is_pressed(ActionId::StepSim) { + if globals.is_pressed(ActionId::StepSim) { self.step_pressed() } - if globals.input.is_pressed(ActionId::StartSim) { + if globals.is_pressed(ActionId::StartSim) { match self.sim_state { SimState::Editing => { self.init_sim(); @@ -508,7 +508,7 @@ impl Editor { SimState::Stepping => self.sim_state = SimState::Running, SimState::Running => (), } - } else if globals.input.is_pressed(ActionId::StopSim) { + } else if globals.is_pressed(ActionId::StopSim) { match self.sim_state { SimState::Running | SimState::Stepping => { self.sim_state = SimState::Editing; @@ -557,16 +557,16 @@ impl Editor { if self.sim_state == SimState::Editing { if let Some(clipboard) = &mut globals.clipboard { - if globals.input.is_pressed(ActionId::Paste) { + if globals.config.input.is_pressed(ActionId::Paste) { if let Ok(text) = clipboard.get_text() { let b = Board::from_user_str(&text); self.pasting_board = Some(b); } } } - if globals.input.is_pressed(ActionId::Undo) { + if globals.is_pressed(ActionId::Undo) { self.undo(); - } else if globals.input.is_pressed(ActionId::Redo) { + } else if globals.is_pressed(ActionId::Redo) { self.redo(); } } @@ -627,7 +627,7 @@ impl Editor { self.draw_blueprint_sidebar(d, textures); } - self.mouse = MouseInput::get(d); + self.mouse.update(d); if self.popup != Popup::None { self.tooltip.reset(); @@ -1044,8 +1044,7 @@ impl Editor { draw_scaled_texture(d, textures.get("save"), 148, y + 4, 2.); self.tooltip.add(188, y, 40, 40, "Copy"); - if simple_button((d, &self.mouse), 188, y, 40, 40) - || globals.input.is_pressed(ActionId::Copy) + if simple_button((d, &self.mouse), 188, y, 40, 40) || globals.is_pressed(ActionId::Copy) { let board = self.get_selected_as_board(selection); if let Some(clipboard) = &mut globals.clipboard { diff --git a/src/input.rs b/src/input.rs index 823470b..fe4834e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -26,13 +26,14 @@ impl Default for Input { use KeyboardKey::*; let mut bindings = [(); ActionId::SIZE].map(|_| Vec::new()); let mut bind_key = |action, mods, key| { - bindings[action as usize] = vec![Binding { + bindings[action as usize].push(Binding { modifiers: mods, trigger: InputTrigger::Key(key), - }]; + }); }; bind_key(ActionId::Undo, vec![KEY_LEFT_CONTROL], KEY_Z); bind_key(ActionId::Redo, vec![KEY_LEFT_CONTROL], KEY_Y); + bind_key(ActionId::Redo, vec![KEY_LEFT_CONTROL, KEY_LEFT_SHIFT], KEY_Z); bind_key(ActionId::Copy, vec![KEY_LEFT_CONTROL], KEY_C); bind_key(ActionId::Paste, vec![KEY_LEFT_CONTROL], KEY_V); bind_key(ActionId::ToggleMenu, vec![], KEY_ESCAPE); diff --git a/src/lib.rs b/src/lib.rs index c48ee78..3464583 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod blueprint; pub mod board; +pub mod config; pub mod editor; pub mod input; pub mod level; @@ -10,9 +11,31 @@ pub mod ui; pub mod util; use arboard::Clipboard; -use input::Input; +use config::Config; +use input::ActionId; +use raylib::RaylibHandle; +// use util::MouseInput; pub struct Globals { pub clipboard: Option, - pub input: Input, + pub config: Config, + // pub mouse: MouseInput, +} + +impl Globals { + pub fn update(&mut self, rl: &RaylibHandle) { + self.config.input.update(rl); + } + + pub fn is_pressed(&self, action: ActionId) -> bool { + self.config.input.is_pressed(action) + } + + pub fn is_held(&self, action: ActionId) -> bool { + self.config.input.is_held(action) + } + + pub fn is_released(&self, action: ActionId) -> bool { + self.config.input.is_released(action) + } } diff --git a/src/main.rs b/src/main.rs index 13b989e..4ebec62 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ struct Game { level_desc_text: ShapedText, globals: Globals, show_settings: bool, + mouse: MouseInput, } #[derive(Debug)] @@ -62,12 +63,9 @@ impl Game { let levels = get_levels(); let solutions = get_solutions(); let config_path = userdata_dir().join(CONFIG_FILE_NAME); - let input = fs::read_to_string(config_path) + let config = fs::read_to_string(config_path) .ok() - .and_then(|s| { - println!("a"); - serde_json::from_str(&s).unwrap() - }) + .and_then(|s| serde_json::from_str(&s).ok()) .unwrap_or_default(); Self { @@ -85,16 +83,19 @@ impl Game { clipboard: Clipboard::new() .map_err(|e| eprintln!("System clipboard error: {e}")) .ok(), - input, + config, + // mouse: util::MouseInput::default() }, show_settings: false, + mouse: MouseInput::default(), } } fn run(&mut self, rl: &mut RaylibHandle, thread: &RaylibThread) { while !rl.window_should_close() { let mut d = rl.begin_drawing(thread); - self.globals.input.update(&d); + self.globals.update(&d); + self.mouse.update(&d); if let Some(editor) = &mut self.open_editor { editor.update(&d, &mut self.globals); editor.draw(&mut d, &self.textures, &mut self.globals); @@ -141,10 +142,10 @@ impl Game { let level_list_width = (d.get_screen_width() / 3).min(400); let screen_height = d.get_screen_height(); d.draw_rectangle(0, 0, level_list_width, screen_height, BG_MEDIUM); - let mouse = MouseInput::get(d); + if text_button( d, - &mouse, + &self.mouse, d.get_screen_width() - 50, d.get_screen_height() - 40, 40, @@ -156,11 +157,11 @@ impl Game { const ENTRY_SPACING: i32 = 65; let fit_on_screen = (d.get_screen_height() / ENTRY_SPACING) as usize; let max_scroll = self.levels.len().saturating_sub(fit_on_screen); - if mouse.pos().x < level_list_width as f32 { - if mouse.scroll() == Some(Scroll::Down) && self.level_scroll < max_scroll { + if self.mouse.pos().x < level_list_width as f32 { + if self.mouse.scroll() == Some(Scroll::Down) && self.level_scroll < max_scroll { self.level_scroll += 1; } - if mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0 { + if self.mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0 { self.level_scroll -= 1; } } @@ -174,7 +175,7 @@ impl Game { width: level_list_width as f32 - 10., height: ENTRY_SPACING as f32 - 5., }; - let clicked_this = mouse.left_click() && mouse.is_over(bounds); + let clicked_this = self.mouse.left_click() && self.mouse.is_over(bounds); match level { LevelListEntry::Chapter(title, level_count) => { d.draw_rectangle_rec(bounds, BG_DARK); @@ -235,7 +236,7 @@ impl Game { let mut solution_y = y; for (solution_index, solution) in solutions.iter().enumerate() { if simple_option_button( - (d, &mouse), + (d, &self.mouse), rect( level_list_width + 10, solution_y, @@ -267,7 +268,7 @@ impl Game { Color::WHITE, ); if tex32_button( - (d, &mouse), + (d, &self.mouse), (level_list_width + entry_width + 15, solution_y + 4), self.textures.get("cancel"), (&mut tooltip, "delete"), @@ -280,7 +281,7 @@ impl Game { let next_id = get_free_id(solutions, Solution::id); if text_button( d, - &mouse, + &self.mouse, level_list_width + 10, solution_y, entry_width, @@ -295,12 +296,12 @@ impl Game { let y = (solution_y + 40).max(240); let x = level_list_width + 10; d.draw_text(&text, x, y, 20, Color::ORANGE); - if text_button(d, &mouse, x, y + 30, 100, "yes") { + if text_button(d, &self.mouse, x, y + 30, 100, "yes") { solutions[i].remove_file(); solutions.remove(i); self.delete_solution = None; } - if text_button(d, &mouse, x + 110, y + 30, 100, "no") { + if text_button(d, &self.mouse, x + 110, y + 30, 100, "no") { self.delete_solution = None; } } @@ -310,7 +311,7 @@ impl Game { let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.); if text_input( d, - &mouse, + &self.mouse, bounds, &mut solution.name, &mut self.editing_solution_name, @@ -322,14 +323,14 @@ impl Game { let id_text = format!("{}", solution.id()); d.draw_text(&id_text, column_x, y + 35, 10, Color::GRAY); - if text_button(d, &mouse, column_x, y + 50, 220, "clone") { + if text_button(d, &self.mouse, column_x, y + 50, 220, "clone") { let cloned = solution.new_copy(next_id); self.selected_solution = solutions.len(); solutions.push(cloned); return; } - if text_button(d, &mouse, column_x, y + 85, 220, "edit") { + if text_button(d, &self.mouse, column_x, y + 85, 220, "edit") { let mut editor = Editor::new(solution.clone(), level.clone()); editor.center_view(d); self.open_editor = Some(editor); @@ -344,11 +345,10 @@ impl Game { fn draw_settings(&mut self, d: &mut RaylibDrawHandle) { d.clear_background(BG_DARK); - let mouse = MouseInput::get(d); - if text_button(d, &mouse, 5, 5, 50, "return") { + if text_button(d, &self.mouse, 5, 5, 50, "return") { self.show_settings = false; } - if text_button(d, &mouse, 5, 45, 50, "save") { + if text_button(d, &self.mouse, 5, 45, 50, "save") { self.save_config(); } } @@ -356,7 +356,7 @@ impl Game { fn save_config(&self) { let path = userdata_dir().join(CONFIG_FILE_NAME); // todo save more than just input - let json = serde_json::to_string_pretty(&self.globals.input).unwrap(); + let json = serde_json::to_string_pretty(&self.globals.config).unwrap(); let mut f = File::create(path).unwrap(); f.write_all(json.as_bytes()).unwrap(); } diff --git a/src/util.rs b/src/util.rs index b0a00fa..5649306 100644 --- a/src/util.rs +++ b/src/util.rs @@ -84,15 +84,13 @@ pub struct MouseInput { } impl MouseInput { - pub fn get(rl: &RaylibHandle) -> Self { - Self { - pos: rl.get_mouse_position(), - left_click: rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT), - left_hold: rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT), - left_release: rl.is_mouse_button_released(MouseButton::MOUSE_BUTTON_LEFT), - right_hold: rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_RIGHT), - scroll: get_scroll(rl), - } + pub fn update(&mut self, rl: &RaylibHandle) { + self.pos = rl.get_mouse_position(); + self.left_click = rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT); + self.left_hold = rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT); + self.left_release = rl.is_mouse_button_released(MouseButton::MOUSE_BUTTON_LEFT); + self.right_hold = rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_RIGHT); + self.scroll = get_scroll(rl); } pub fn is_over(&self, rect: Rectangle) -> bool {