From 6fc41bdb17a31d16e5ab75b1297564f0cea37db8 Mon Sep 17 00:00:00 2001 From: CrispyPin Date: Mon, 23 Dec 2024 00:44:47 +0100 Subject: [PATCH] add info box and disable some ui while a popup is active --- src/editor.rs | 284 +++++++++++++++++++++++++++++--------------------- src/main.rs | 26 +++-- src/ui.rs | 37 +++---- src/util.rs | 84 +++++++++++++++ 4 files changed, 280 insertions(+), 151 deletions(-) diff --git a/src/editor.rs b/src/editor.rs index 7f116ff..54b5b42 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -21,8 +21,8 @@ use crate::{ const HEADER_HEIGHT: i32 = 40; const FOOTER_HEIGHT: i32 = 95; const SIDEBAR_WIDTH: i32 = 200 + 32 * 2 + 5 * 4; -const POPUP_WIDTH: i32 = 320; -const POPUP_HEIGHT: i32 = 165; +const END_POPUP_WIDTH: i32 = 320; +const END_POPUP_HEIGHT: i32 = 165; const MAX_ZOOM: f32 = 8.; const MIN_ZOOM: f32 = 0.25; @@ -56,9 +56,11 @@ pub struct Editor { exit_state: ExitState, exit_menu: bool, total_steps: usize, - popup: EndPopup, + popup: Popup, score: Option, tooltip: Tooltip, + mouse: MouseInput, + info_text: ShapedText, blueprints: Vec, selected_blueprint: usize, @@ -80,10 +82,12 @@ enum Action { } #[derive(Debug, PartialEq)] -enum EndPopup { +enum Popup { None, Success, Failure, + LevelInfo, + PauseMenu, Dismissed, } @@ -134,6 +138,8 @@ impl Editor { input_as_text = i.input().is_text(); machine.set_input(i.input().as_bytes().to_owned()); } + let mut info_text = ShapedText::new(20); + info_text.set_text(level.description()); Self { source_board: Board::parse(&solution.board), @@ -158,7 +164,8 @@ impl Editor { level, exit_state: ExitState::Dont, exit_menu: false, - popup: EndPopup::None, + popup: Popup::None, + info_text, score: solution.score, total_steps: 0, blueprints: get_blueprints(), @@ -172,6 +179,7 @@ impl Editor { undo_history: Vec::new(), undo_index: 0, tooltip: Tooltip::default(), + mouse: MouseInput::default(), } } @@ -292,18 +300,18 @@ impl Editor { self.machine.step(); if let Some(i) = self.stage { - if self.popup != EndPopup::None { - self.popup = EndPopup::Dismissed; + if self.popup != Popup::None { + self.popup = Popup::Dismissed; } let stage = &self.level.stages()[i]; - if self.popup == EndPopup::None { + if self.popup == Popup::None { if stage.output().as_bytes() == self.machine.output() { if i + 1 < self.level.stages().len() { self.stage = Some(i + 1); self.total_steps += self.machine.step_count(); self.reset_machine(); } else { - self.popup = EndPopup::Success; + self.popup = Popup::Success; println!("completed in {:?}", self.start_time.elapsed()); self.exit_state = ExitState::Save; self.sim_state = SimState::Stepping; @@ -313,7 +321,7 @@ impl Editor { }); } } else if !stage.output().as_bytes().starts_with(self.machine.output()) { - self.popup = EndPopup::Failure; + self.popup = Popup::Failure; self.sim_state = SimState::Stepping; } } @@ -437,7 +445,7 @@ impl Editor { pub fn update(&mut self, rl: &RaylibHandle) { if rl.is_key_pressed(KeyboardKey::KEY_ESCAPE) { self.sim_state = SimState::Editing; - self.popup = EndPopup::None; + self.popup = Popup::None; } if self.sim_state == SimState::Running { self.time_since_step += rl.get_frame_time(); @@ -478,7 +486,7 @@ impl Editor { } SimState::Running => { self.sim_state = SimState::Editing; - self.popup = EndPopup::None; + self.popup = Popup::None; } SimState::Stepping => self.sim_state = SimState::Running, } @@ -563,6 +571,10 @@ impl Editor { } self.tooltip.init_frame(d); + self.mouse = MouseInput::get(d); + if !matches!(self.popup, Popup::None | Popup::Dismissed) { + self.mouse.clear(); + } self.draw_board(d, textures); self.board_overlay(d, textures); @@ -570,97 +582,126 @@ impl Editor { self.draw_top_bar(d, textures); if self.active_tool == Tool::Blueprint { - let sidebar_height = d.get_screen_height() - FOOTER_HEIGHT - HEADER_HEIGHT - 40; - d.draw_rectangle( - 0, - HEADER_HEIGHT + 20, - SIDEBAR_WIDTH, - sidebar_height, - Color::new(32, 32, 32, 255), - ); - d.draw_text("Blueprints", 10, HEADER_HEIGHT + 30, 20, Color::WHITE); - let mut y = HEADER_HEIGHT + 60; - let blueprints_shown = (sidebar_height as usize - 45) / 37; - let end = self - .blueprints - .len() - .min(blueprints_shown + self.blueprint_scroll); - for (i, b) in self.blueprints[self.blueprint_scroll..end] - .iter_mut() - .enumerate() - { - let i = i + self.blueprint_scroll; - self.tooltip.add(5, y, 32, 32, "Delete"); - if simple_button(d, 5, y, 32, 32) { - b.remove_file(); - self.blueprints.remove(i); - break; - } - draw_scaled_texture(d, textures.get("rubbish"), 5, y, 2.); - let is_selected = self.selected_blueprint == i; - let mut text_selected = is_selected && self.blueprint_name_selected; - text_input( - d, - Rectangle::new(42., y as f32, 200., 32.), - &mut b.name, - &mut text_selected, - 32, - is_selected, - ); - if is_selected { - self.blueprint_name_selected = text_selected; - } - self.tooltip.add(42 + 205, y, 32, 32, "Select"); - simple_option_button(d, 42 + 205, y, 32, 32, i, &mut self.selected_blueprint); + self.draw_blueprint_sidebar(d, textures); + } - d.draw_texture_ex( - textures.get("blueprint"), - Vector2::new((42 + 205) as f32, y as f32), - 0., - 2., - Color::new(255, 255, 255, if is_selected { 255 } else { 150 }), - ); - y += 37; + self.mouse = MouseInput::get(d); + + match self.popup { + Popup::Success | Popup::Failure => { + self.tooltip.reset(); + self.draw_end_popup(d, textures); } + Popup::LevelInfo => { + self.tooltip.reset(); + let bounds = screen_centered_rect_dyn(d, 100, 100); + d.draw_rectangle_rec(bounds, BG_MEDIUM); + d.draw_text(self.level.name(), 110, 110, 30, Color::LIGHTBLUE); + self.info_text.update_width(d, bounds.width as i32 - 20); + self.info_text.draw(d, 110, 140); + } + _ => (), } self.tooltip.draw(d); + } - if matches!(self.popup, EndPopup::Success | EndPopup::Failure) { - let x = d.get_screen_width() / 2 - POPUP_WIDTH / 2; - let y = d.get_screen_height() / 2 - POPUP_HEIGHT / 2; - d.draw_rectangle(x, y, POPUP_WIDTH, POPUP_HEIGHT, BG_DARK); - if self.popup == EndPopup::Success { - d.draw_text("Level Complete!", x + 45, y + 10, 30, Color::LIME); - if let Some(score) = &self.score { - d.draw_text("cycles", x + 15, y + 45, 20, Color::WHITE); - draw_usize(d, textures, score.cycles, x + 10, y + 70, 9, 2); - d.draw_text("tiles", x + 215, y + 45, 20, Color::WHITE); - draw_usize(d, textures, score.tiles, x + 210, y + 70, 5, 2); - } - if simple_button(d, x + 10, y + 110, 140, 45) { - self.popup = EndPopup::Dismissed; - } - d.draw_text("continue\nediting", x + 15, y + 115, 20, Color::WHITE); - - if simple_button(d, x + POPUP_WIDTH / 2 + 5, y + 110, 140, 45) { - self.exit_state = ExitState::ExitAndSave; - } - d.draw_text( - "return to\nlevel list", - x + POPUP_WIDTH / 2 + 10, - y + 115, - 20, - Color::WHITE, - ); - } else { - d.draw_text("Level Failed!", x + 45, y + 10, 30, Color::RED); - d.draw_text("incorrect output", x + 45, y + 45, 20, Color::WHITE); - if simple_button(d, x + 10, y + 110, 300, 25) { - self.popup = EndPopup::Dismissed; - } - d.draw_text("ok :(", x + 15, y + 115, 20, Color::WHITE); + fn draw_blueprint_sidebar(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) { + let sidebar_height = d.get_screen_height() - FOOTER_HEIGHT - HEADER_HEIGHT - 40; + d.draw_rectangle( + 0, + HEADER_HEIGHT + 20, + SIDEBAR_WIDTH, + sidebar_height, + Color::new(32, 32, 32, 255), + ); + d.draw_text("Blueprints", 10, HEADER_HEIGHT + 30, 20, Color::WHITE); + let mut y = HEADER_HEIGHT + 60; + let blueprints_shown = (sidebar_height as usize - 45) / 37; + let end = self + .blueprints + .len() + .min(blueprints_shown + self.blueprint_scroll); + for (i, b) in self.blueprints[self.blueprint_scroll..end] + .iter_mut() + .enumerate() + { + let i = i + self.blueprint_scroll; + self.tooltip.add(5, y, 32, 32, "Delete"); + if simple_button(d, &self.mouse, 5, y, 32, 32) { + b.remove_file(); + self.blueprints.remove(i); + break; } + draw_scaled_texture(d, textures.get("rubbish"), 5, y, 2.); + let is_selected = self.selected_blueprint == i; + let mut text_selected = is_selected && self.blueprint_name_selected; + text_input( + d, + Rectangle::new(42., y as f32, 200., 32.), + &mut b.name, + &mut text_selected, + 32, + is_selected, + ); + if is_selected { + self.blueprint_name_selected = text_selected; + } + self.tooltip.add(42 + 205, y, 32, 32, "Select"); + simple_option_button(d, 42 + 205, y, 32, 32, i, &mut self.selected_blueprint); + + d.draw_texture_ex( + textures.get("blueprint"), + Vector2::new((42 + 205) as f32, y as f32), + 0., + 2., + Color::new(255, 255, 255, if is_selected { 255 } else { 150 }), + ); + y += 37; + } + } + + fn draw_end_popup(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) { + let x = d.get_screen_width() / 2 - END_POPUP_WIDTH / 2; + let y = d.get_screen_height() / 2 - END_POPUP_HEIGHT / 2; + d.draw_rectangle(x, y, END_POPUP_WIDTH, END_POPUP_HEIGHT, BG_DARK); + if self.popup == Popup::Success { + d.draw_text("Level Complete!", x + 45, y + 10, 30, Color::LIME); + if let Some(score) = &self.score { + d.draw_text("cycles", x + 15, y + 45, 20, Color::WHITE); + draw_usize(d, textures, score.cycles, x + 10, y + 70, 9, 2); + d.draw_text("tiles", x + 215, y + 45, 20, Color::WHITE); + draw_usize(d, textures, score.tiles, x + 210, y + 70, 5, 2); + } + if simple_button(d, &self.mouse, x + 10, y + 110, 140, 45) { + self.popup = Popup::Dismissed; + } + d.draw_text("continue\nediting", x + 15, y + 115, 20, Color::WHITE); + + if simple_button( + d, + &self.mouse, + x + END_POPUP_WIDTH / 2 + 5, + y + 110, + 140, + 45, + ) { + self.exit_state = ExitState::ExitAndSave; + } + d.draw_text( + "return to\nlevel list", + x + END_POPUP_WIDTH / 2 + 10, + y + 115, + 20, + Color::WHITE, + ); + } else { + d.draw_text("Level Failed!", x + 45, y + 10, 30, Color::RED); + d.draw_text("incorrect output", x + 45, y + 45, 20, Color::WHITE); + if simple_button(d, &self.mouse, x + 10, y + 110, 300, 25) { + self.popup = Popup::Dismissed; + } + d.draw_text("ok :(", x + 15, y + 115, 20, Color::WHITE); } } @@ -675,32 +716,37 @@ impl Editor { ); if self.exit_menu { - if simple_button(d, 4, 4, 32, 32) { + if simple_button(d, &self.mouse, 4, 4, 32, 32) { self.exit_state = ExitState::ExitAndSave; } self.tooltip.add(4, 4, 32, 32, "exit"); draw_scaled_texture(d, textures.get("exit"), 4, 4, 2.); - if simple_button(d, 38, 4, 32, 32) { + if simple_button(d, &self.mouse, 40, 4, 32, 32) { self.exit_menu = false; } - draw_scaled_texture(d, textures.get("cancel"), 38, 4, 2.); - self.tooltip.add(38, 4, 32, 32, "cancel"); + draw_scaled_texture(d, textures.get("cancel"), 40, 4, 2.); + self.tooltip.add(40, 4, 32, 32, "cancel"); } else { - if simple_button(d, 4, 4, 32, 32) { + if simple_button(d, &self.mouse, 4, 4, 32, 32) { self.exit_menu = true; } self.tooltip.add(4, 4, 32, 32, "exit"); draw_scaled_texture(d, textures.get("exit"), 4, 4, 2.); - if simple_button(d, 38, 4, 32, 32) { + if simple_button(d, &self.mouse, 40, 4, 32, 32) { self.exit_state = ExitState::Save; } - draw_scaled_texture(d, textures.get("save"), 38, 4, 2.); - self.tooltip.add(38, 4, 32, 32, "save"); + draw_scaled_texture(d, textures.get("save"), 40, 4, 2.); + self.tooltip.add(40, 4, 32, 32, "save"); } + if simple_button(d, &self.mouse, 76, 5, 60, 30) { + self.popup = Popup::LevelInfo; + } + d.draw_text("info", 80, 10, 20, Color::WHITE); + if self.sim_state == SimState::Editing { self.tooltip.add(150, 4, 32, 32, "Undo"); - if simple_button(d, 150, 4, 32, 32) { + if simple_button(d, &self.mouse, 150, 4, 32, 32) { self.undo() } let undo_icon = if self.undo_index > 0 { @@ -711,7 +757,7 @@ impl Editor { draw_scaled_texture(d, textures.get(undo_icon), 150, 4, 2.); self.tooltip.add(186, 4, 32, 32, "Redo"); - if simple_button(d, 186, 4, 32, 32) { + if simple_button(d, &self.mouse, 186, 4, 32, 32) { self.redo() } let redo_icon = if self.undo_index < self.undo_history.len() { @@ -723,7 +769,7 @@ impl Editor { } self.tooltip.add(223, 4, 32, 32, "Toggle overlay"); - if simple_button(d, 223, 4, 32, 32) { + if simple_button(d, &self.mouse, 223, 4, 32, 32) { self.draw_overlay = !self.draw_overlay; } let overlay_btn_icon = if self.draw_overlay { @@ -735,13 +781,13 @@ impl Editor { if self.sim_state == SimState::Running { self.tooltip.add(260, 4, 32, 32, "Pause"); - if simple_button(d, 260, 4, 32, 32) { + if simple_button(d, &self.mouse, 260, 4, 32, 32) { self.sim_state = SimState::Stepping; } draw_scaled_texture(d, textures.get("pause"), 260, 4, 2.); } else { self.tooltip.add(260, 4, 32, 32, "Start"); - if simple_button(d, 260, 4, 32, 32) { + if simple_button(d, &self.mouse, 260, 4, 32, 32) { if self.sim_state == SimState::Editing { self.init_sim() } @@ -752,15 +798,15 @@ impl Editor { if self.sim_state != SimState::Editing { self.tooltip.add(296, 4, 32, 32, "Stop"); - if simple_button(d, 296, 4, 32, 32) { + if simple_button(d, &self.mouse, 296, 4, 32, 32) { self.sim_state = SimState::Editing; - self.popup = EndPopup::None; + self.popup = Popup::None; } draw_scaled_texture(d, textures.get("stop"), 296, 4, 2.); } self.tooltip.add(332, 4, 32, 32, "Step"); - if simple_button(d, 332, 4, 32, 32) { + if simple_button(d, &self.mouse, 332, 4, 32, 32) { self.step_pressed(); } draw_scaled_texture(d, textures.get("step"), 332, 4, 2.); @@ -781,7 +827,7 @@ impl Editor { draw_usize(d, textures, self.max_step_time as usize, 260, 60, 9, 1); d.draw_text("input:", 603, 8, 10, Color::WHITE); - if simple_button(d, 600, 20, 35, 15) { + if simple_button(d, &self.mouse, 600, 20, 35, 15) { self.input_as_text = !self.input_as_text } let input_mode_text = if self.input_as_text { "text" } else { "bytes" }; @@ -862,19 +908,21 @@ impl Editor { let y = footer_top as i32 + 49; self.tooltip.add(100, y, 40, 40, "Cancel"); - if simple_button(d, 100, y, 40, 40) || d.is_key_pressed(KeyboardKey::KEY_ESCAPE) { + if simple_button(d, &self.mouse, 100, y, 40, 40) + || d.is_key_pressed(KeyboardKey::KEY_ESCAPE) + { self.active_tool = Tool::SelectArea(Selection::default()); } draw_scaled_texture(d, textures.get("cancel"), 104, y + 4, 2.); self.tooltip.add(144, y, 40, 40, "Save blueprint"); - if simple_button(d, 144, y, 40, 40) { + if simple_button(d, &self.mouse, 144, y, 40, 40) { self.save_blueprint(selection); } draw_scaled_texture(d, textures.get("save"), 148, y + 4, 2.); self.tooltip.add(188, y, 40, 40, "Copy"); - if simple_button(d, 188, y, 40, 40) + if simple_button(d, &self.mouse, 188, y, 40, 40) || (d.is_key_pressed(KeyboardKey::KEY_C) && d.is_key_down(KeyboardKey::KEY_LEFT_CONTROL)) { @@ -884,7 +932,7 @@ impl Editor { draw_scaled_texture(d, textures.get("copy"), 192, y + 4, 2.); self.tooltip.add(232, y, 40, 40, "Delete"); - if simple_button(d, 232, y, 40, 40) { + if simple_button(d, &self.mouse, 232, y, 40, 40) { let min = selection.0.min(selection.1); let max = selection.0.max(selection.1); let board = @@ -1042,7 +1090,7 @@ impl Editor { let output_cell_width = 43; let output_cells = (d.get_screen_width() - output_x) as usize / output_cell_width as usize; - if simple_button(d, output_x, y + 70, 65, 15) { + if simple_button(d, &self.mouse, output_x, y + 70, 65, 15) { self.output_as_text = !self.output_as_text } let output_mode_text = if self.output_as_text { diff --git a/src/main.rs b/src/main.rs index 760c56d..e19cb33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -123,19 +123,16 @@ 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 clicked = d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT); - let mouse_pos = d.get_mouse_position(); - let scroll_delta = d.get_mouse_wheel_move(); + let mouse = MouseInput::get(d); 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 scroll_delta < 0. && self.level_scroll < max_scroll { + if mouse.pos().x < level_list_width as f32 { + if mouse.scroll() == Some(Scroll::Down) && self.level_scroll < max_scroll { self.level_scroll += 1; } - if scroll_delta > 0. && self.level_scroll > 0 { + if mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0 { self.level_scroll -= 1; } } @@ -149,7 +146,7 @@ impl Game { width: level_list_width as f32 - 10., height: ENTRY_SPACING as f32 - 5., }; - let clicked_this = clicked && bounds.check_collision_point_rec(mouse_pos); + let clicked_this = mouse.left_click() && mouse.is_over(bounds); match level { LevelListEntry::Chapter(title, level_count) => { d.draw_rectangle_rec(bounds, BG_DARK); @@ -242,7 +239,14 @@ impl Game { } let next_id = get_free_id(solutions, Solution::id); - if simple_button(d, level_list_width + 10, solution_y, entry_width, 30) { + if simple_button( + d, + &mouse, + level_list_width + 10, + solution_y, + entry_width, + 30, + ) { self.selected_solution = solutions.len(); solutions.push(Solution::new(level, next_id)); } @@ -270,7 +274,7 @@ impl Game { let id_text = format!("{}", solution.id()); d.draw_text(&id_text, column_x, y + 35, 10, Color::GRAY); - if simple_button(d, column_x, y + 50, 220, 30) { + if simple_button(d, &mouse, column_x, y + 50, 220, 30) { let cloned = solution.new_copy(next_id); self.selected_solution = solutions.len(); solutions.push(cloned); @@ -278,7 +282,7 @@ impl Game { } d.draw_text("clone", column_x + 5, y + 55, 20, Color::WHITE); - if simple_button(d, column_x, y + 85, 220, 30) { + if simple_button(d, &mouse, column_x, y + 85, 220, 30) { let mut editor = Editor::new(solution.clone(), level.clone()); editor.center_view(d); self.open_editor = Some(editor); diff --git a/src/ui.rs b/src/ui.rs index c4de24b..d3d1f97 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use crate::{draw_scaled_texture, theme::*, Textures}; +use crate::{draw_scaled_texture, theme::*, MouseInput, Textures}; use raylib::prelude::*; #[derive(Debug)] @@ -120,6 +120,10 @@ impl Tooltip { } } + pub fn reset(&mut self){ + self.text = None; + } + pub fn add_rec(&mut self, bounds: Rectangle, text: &'static str) { self.add( bounds.x as i32, @@ -153,8 +157,15 @@ impl Tooltip { } } -pub fn simple_button(d: &mut RaylibDrawHandle, x: i32, y: i32, width: i32, height: i32) -> bool { - let mouse_pos = d.get_mouse_position(); +pub fn simple_button( + d: &mut RaylibDrawHandle, + mouse: &MouseInput, + x: i32, + y: i32, + width: i32, + height: i32, +) -> bool { + let mouse_pos = mouse.pos(); let bounds = Rectangle { x: x as f32, y: y as f32, @@ -162,7 +173,7 @@ pub fn simple_button(d: &mut RaylibDrawHandle, x: i32, y: i32, width: i32, heigh height: height as f32, }; let hover = bounds.check_collision_point_rec(mouse_pos); - let pressed = hover && d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT); + let pressed = hover && mouse.left_click(); d.draw_rectangle(x, y, width, height, widget_bg(hover)); pressed } @@ -379,21 +390,3 @@ pub fn slider( } false } - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Scroll { - Up, - Down, -} - -pub fn get_scroll(rl: &RaylibHandle) -> Option { - const SCROLL_THRESHOLD: f32 = 0.5; - let value = rl.get_mouse_wheel_move(); - if value > SCROLL_THRESHOLD { - Some(Scroll::Up) - } else if value < -SCROLL_THRESHOLD { - Some(Scroll::Down) - } else { - None - } -} diff --git a/src/util.rs b/src/util.rs index a06960f..297bbe2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -50,3 +50,87 @@ pub fn get_free_id(items: &[T], id_fn: fn(&T) -> usize) -> usize { } id } + +pub fn screen_centered_rect_dyn(rl: &RaylibHandle, margin_x: i32, margin_y: i32) -> Rectangle { + let w = rl.get_screen_width(); + let h = rl.get_screen_height(); + Rectangle { + x: margin_x as f32, + y: margin_y as f32, + width: (w - margin_x * 2) as f32, + height: (h - margin_y * 2) as f32, + } +} + +#[derive(Debug, Default)] +pub struct MouseInput { + pos: Vector2, + left_click: bool, + left_hold: bool, + right_click: bool, + right_hold: bool, + scroll: Option, +} + +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), + right_click: rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_RIGHT), + right_hold: rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_RIGHT), + scroll: get_scroll(rl), + } + } + + pub fn is_over(&self, rect: Rectangle) -> bool { + rect.check_collision_point_rec(self.pos) + } + + pub fn clear(&mut self) { + *self = Self::default(); + } + + pub fn pos(&self) -> Vector2 { + self.pos + } + + pub fn left_click(&self) -> bool { + self.left_click + } + + pub fn left_hold(&self) -> bool { + self.left_hold + } + + pub fn right_click(&self) -> bool { + self.right_click + } + + pub fn right_hold(&self) -> bool { + self.right_hold + } + + pub fn scroll(&self) -> Option { + self.scroll + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Scroll { + Up, + Down, +} + +pub fn get_scroll(rl: &RaylibHandle) -> Option { + const SCROLL_THRESHOLD: f32 = 0.5; + let value = rl.get_mouse_wheel_move(); + if value > SCROLL_THRESHOLD { + Some(Scroll::Up) + } else if value < -SCROLL_THRESHOLD { + Some(Scroll::Down) + } else { + None + } +}