diff --git a/src/config.rs b/src/config.rs index 39fee1d..87c3351 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,8 +1,36 @@ +use raylib::prelude::*; use serde::{Deserialize, Serialize}; -use crate::input::Input; +use crate::{input::Input, theme::FG_CHAPTER_TITLE, ui::text_button, Globals}; #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct Config { pub input: Input, } + +pub enum MenuReturn { + Stay, + StaySave, + ReturnSave, + ReturnCancel, +} + +impl Config { + #[must_use] + pub fn draw_edit(&mut self, d: &mut RaylibDrawHandle, globals: &Globals) -> MenuReturn { + d.draw_text("Settings", 16, 16, 30, FG_CHAPTER_TITLE); + + if text_button(d, &globals.mouse, 10, 60, 80, "apply") { + return MenuReturn::StaySave; + } + if text_button(d, &globals.mouse, 100, 60, 80, "done") { + return MenuReturn::ReturnSave; + } + if text_button(d, &globals.mouse, 190, 60, 80, "cancel") { + return MenuReturn::ReturnCancel; + } + + self.input.draw_edit(d, globals); + MenuReturn::Stay + } +} diff --git a/src/editor.rs b/src/editor.rs index c8506b0..8e5fc32 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -893,16 +893,15 @@ impl Editor { self.sim_state = SimState::Running; } - if self.sim_state != SimState::Editing { - if tex32_button( + if self.sim_state != SimState::Editing + && tex32_button( (d, &self.mouse), (296, 4), textures.get("stop"), (&mut self.tooltip, "Stop"), ) { - self.sim_state = SimState::Editing; - self.popup = Popup::None; - } + self.sim_state = SimState::Editing; + self.popup = Popup::None; } if tex32_button( diff --git a/src/input.rs b/src/input.rs index fe4834e..90dede5 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,11 +1,15 @@ use std::{collections::BTreeMap, mem::transmute}; use raylib::{ + color::Color, + drawing::{RaylibDraw, RaylibDrawHandle}, ffi::{KeyboardKey, MouseButton}, RaylibHandle, }; use serde::{Deserialize, Serialize}; +use crate::{ui::text_button, Globals}; + #[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] pub enum ActionId { @@ -33,7 +37,11 @@ impl Default for Input { }; 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::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); @@ -67,6 +75,30 @@ pub struct Input { } impl Input { + pub fn draw_edit(&mut self, d: &mut RaylibDrawHandle, globals: &Globals) { + let mut y = 96; + for action_index in 0..ActionId::SIZE { + let action = ActionId::from_usize(action_index).unwrap(); + + d.draw_text(&format!("{action:?}"), 16, y, 20, Color::ORANGE); + if self.bindings[action_index].is_empty() { + y += 32; + } + for (binding_index, binding) in self.bindings[action_index].iter().enumerate() { + if text_button(d, &globals.mouse, 160, y, 80, "remove") { + self.bindings[action_index].remove(binding_index); + return; + } + let trigger = format!("{:?}", binding.trigger); + d.draw_text(&trigger, 256, y, 20, Color::LIMEGREEN); + let x = 264 + d.measure_text(&trigger, 20); + let modifiers = format!("{:?}", binding.modifiers); + d.draw_text(&modifiers, x, y, 20, Color::LIGHTBLUE); + y += 32; + } + } + } + pub fn update(&mut self, rl: &RaylibHandle) { for i in 0..ActionId::SIZE { let bindings = &self.bindings[i]; diff --git a/src/lib.rs b/src/lib.rs index 2de043b..c2f29c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ use arboard::Clipboard; use config::Config; use input::ActionId; use raylib::{texture::Texture2D, RaylibHandle}; -use util::{userdata_dir, Textures}; +use util::{userdata_dir, MouseInput, Textures}; // use util::MouseInput; pub const CONFIG_FILE_NAME: &str = "config.json"; @@ -25,7 +25,7 @@ pub struct Globals { pub clipboard: Option, pub config: Config, textures: Textures, - // pub mouse: MouseInput, + pub mouse: MouseInput, } impl Globals { @@ -47,12 +47,13 @@ impl Globals { .ok(), config, textures, - // mouse: util::MouseInput::default() + mouse: MouseInput::default(), } } pub fn update(&mut self, rl: &RaylibHandle) { self.config.input.update(rl); + self.mouse.update(rl); } pub fn is_pressed(&self, action: ActionId) -> bool { diff --git a/src/main.rs b/src/main.rs index 9659834..68e824b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use raylib::prelude::*; use marble_machinations::*; +use config::Config; use editor::{Editor, ExitState}; use level::{Chapter, Level}; use solution::Solution; @@ -28,8 +29,7 @@ struct Game { editing_solution_name: bool, level_desc_text: ShapedText, globals: Globals, - show_settings: bool, - mouse: MouseInput, + edit_settings: Option, } #[derive(Debug)] @@ -66,8 +66,7 @@ impl Game { editing_solution_name: false, level_desc_text: ShapedText::new(20), globals: Globals::new(rl, thread), - show_settings: false, - mouse: MouseInput::default(), + edit_settings: None, } } @@ -75,7 +74,6 @@ impl Game { while !rl.window_should_close() { let mut d = rl.begin_drawing(thread); 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, &mut self.globals); @@ -97,8 +95,21 @@ impl Game { solution.save(); } } - } else if self.show_settings { - self.draw_settings(&mut d); + } else if let Some(config) = &mut self.edit_settings { + d.clear_background(BG_DARK); + match config.draw_edit(&mut d, &self.globals) { + config::MenuReturn::Stay => (), + config::MenuReturn::StaySave => { + self.globals.config = config.clone(); + self.save_config(); + } + config::MenuReturn::ReturnSave => { + self.globals.config = config.clone(); + self.save_config(); + self.edit_settings = None; + } + config::MenuReturn::ReturnCancel => self.edit_settings = None, + } } else { self.draw(&mut d); } @@ -125,23 +136,23 @@ impl Game { if text_button( d, - &self.mouse, - d.get_screen_width() - 50, - d.get_screen_height() - 40, - 40, + &self.globals.mouse, + d.get_screen_width() - 100, + d.get_screen_height() - 70, + 90, "settings", ) { - self.show_settings = true; + self.edit_settings = Some(self.globals.config.clone()); } 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 self.mouse.pos().x < level_list_width as f32 { - if self.mouse.scroll() == Some(Scroll::Down) && self.level_scroll < max_scroll { + if self.globals.mouse.pos().x < level_list_width as f32 { + if self.globals.mouse.scroll() == Some(Scroll::Down) && self.level_scroll < max_scroll { self.level_scroll += 1; } - if self.mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0 { + if self.globals.mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0 { self.level_scroll -= 1; } } @@ -155,7 +166,8 @@ impl Game { width: level_list_width as f32 - 10., height: ENTRY_SPACING as f32 - 5., }; - let clicked_this = self.mouse.left_click() && self.mouse.is_over(bounds); + let clicked_this = + self.globals.mouse.left_click() && self.globals.mouse.is_over(bounds); match level { LevelListEntry::Chapter(title, level_count) => { d.draw_rectangle_rec(bounds, BG_DARK); @@ -216,7 +228,7 @@ impl Game { let mut solution_y = y; for (solution_index, solution) in solutions.iter().enumerate() { if simple_option_button( - (d, &self.mouse), + (d, &self.globals.mouse), rect( level_list_width + 10, solution_y, @@ -248,7 +260,7 @@ impl Game { Color::WHITE, ); if tex32_button( - (d, &self.mouse), + (d, &self.globals.mouse), (level_list_width + entry_width + 15, solution_y + 4), self.globals.get_tex("cancel"), (&mut tooltip, "delete"), @@ -261,7 +273,7 @@ impl Game { let next_id = get_free_id(solutions, Solution::id); if text_button( d, - &self.mouse, + &self.globals.mouse, level_list_width + 10, solution_y, entry_width, @@ -276,12 +288,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, &self.mouse, x, y + 30, 100, "yes") { + if text_button(d, &self.globals.mouse, x, y + 30, 100, "yes") { solutions[i].remove_file(); solutions.remove(i); self.delete_solution = None; } - if text_button(d, &self.mouse, x + 110, y + 30, 100, "no") { + if text_button(d, &self.globals.mouse, x + 110, y + 30, 100, "no") { self.delete_solution = None; } } @@ -291,7 +303,7 @@ impl Game { let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.); if text_input( d, - &self.mouse, + &self.globals.mouse, bounds, &mut solution.name, &mut self.editing_solution_name, @@ -303,14 +315,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, &self.mouse, column_x, y + 50, 220, "clone") { + if text_button(d, &self.globals.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, &self.mouse, column_x, y + 85, 220, "edit") { + if text_button(d, &self.globals.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); @@ -323,16 +335,6 @@ impl Game { tooltip.draw(d); } - fn draw_settings(&mut self, d: &mut RaylibDrawHandle) { - d.clear_background(BG_DARK); - if text_button(d, &self.mouse, 5, 5, 50, "return") { - self.show_settings = false; - } - if text_button(d, &self.mouse, 5, 45, 50, "save") { - self.save_config(); - } - } - fn save_config(&self) { let path = userdata_dir().join(CONFIG_FILE_NAME); let json = serde_json::to_string_pretty(&self.globals.config).unwrap();