diff --git a/README.md b/README.md index 2345688..2f7fa49 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ logic mostly like https://git.crispypin.cc/CrispyPin/marble ## todo +- show level info in editor - comments - accessibility - ui scaling diff --git a/src/editor.rs b/src/editor.rs index 7227ff3..7f116ff 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 END_POPUP_WIDTH: i32 = 320; -const END_POPUP_HEIGHT: i32 = 165; +const POPUP_WIDTH: i32 = 320; +const POPUP_HEIGHT: i32 = 165; const MAX_ZOOM: f32 = 8.; const MIN_ZOOM: f32 = 0.25; @@ -56,11 +56,9 @@ pub struct Editor { exit_state: ExitState, exit_menu: bool, total_steps: usize, - popup: Popup, + popup: EndPopup, score: Option, tooltip: Tooltip, - mouse: MouseInput, - info_text: ShapedText, blueprints: Vec, selected_blueprint: usize, @@ -82,12 +80,10 @@ enum Action { } #[derive(Debug, PartialEq)] -enum Popup { +enum EndPopup { None, Success, Failure, - LevelInfo, - PauseMenu, Dismissed, } @@ -138,8 +134,6 @@ 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), @@ -164,8 +158,7 @@ impl Editor { level, exit_state: ExitState::Dont, exit_menu: false, - popup: Popup::None, - info_text, + popup: EndPopup::None, score: solution.score, total_steps: 0, blueprints: get_blueprints(), @@ -179,7 +172,6 @@ impl Editor { undo_history: Vec::new(), undo_index: 0, tooltip: Tooltip::default(), - mouse: MouseInput::default(), } } @@ -300,18 +292,18 @@ impl Editor { self.machine.step(); if let Some(i) = self.stage { - if self.popup != Popup::None { - self.popup = Popup::Dismissed; + if self.popup != EndPopup::None { + self.popup = EndPopup::Dismissed; } let stage = &self.level.stages()[i]; - if self.popup == Popup::None { + if self.popup == EndPopup::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 = Popup::Success; + self.popup = EndPopup::Success; println!("completed in {:?}", self.start_time.elapsed()); self.exit_state = ExitState::Save; self.sim_state = SimState::Stepping; @@ -321,7 +313,7 @@ impl Editor { }); } } else if !stage.output().as_bytes().starts_with(self.machine.output()) { - self.popup = Popup::Failure; + self.popup = EndPopup::Failure; self.sim_state = SimState::Stepping; } } @@ -443,15 +435,9 @@ impl Editor { } pub fn update(&mut self, rl: &RaylibHandle) { - self.tooltip.init_frame(rl); - self.mouse = MouseInput::get(rl); - if !matches!(self.popup, Popup::None | Popup::Dismissed) { - self.mouse.clear(); - } - if rl.is_key_pressed(KeyboardKey::KEY_ESCAPE) { self.sim_state = SimState::Editing; - self.popup = Popup::None; + self.popup = EndPopup::None; } if self.sim_state == SimState::Running { self.time_since_step += rl.get_frame_time(); @@ -492,26 +478,27 @@ impl Editor { } SimState::Running => { self.sim_state = SimState::Editing; - self.popup = Popup::None; + self.popup = EndPopup::None; } SimState::Stepping => self.sim_state = SimState::Running, } } - let mouse_pos = self.mouse.pos(); + let mouse_pos = rl.get_mouse_position(); if (self.active_tool != Tool::Blueprint || self.sim_state != SimState::Editing || mouse_pos.x > SIDEBAR_WIDTH as f32) && mouse_pos.y > HEADER_HEIGHT as f32 && (mouse_pos.y as i32) < (rl.get_screen_height() - FOOTER_HEIGHT) { - match self.mouse.scroll() { - Some(Scroll::Up) => self.zoom_in(rl), - Some(Scroll::Down) => self.zoom_out(rl), - None => (), + if rl.get_mouse_wheel_move() > 0. { + self.zoom_in(rl); + } + if rl.get_mouse_wheel_move() < 0. { + self.zoom_out(rl); } } - if self.mouse.right_hold() { + if rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_RIGHT) { let speed = if rl.is_key_down(KeyboardKey::KEY_LEFT_SHIFT) { 4. } else { @@ -575,151 +562,105 @@ impl Editor { } } + self.tooltip.init_frame(d); + self.draw_board(d, textures); self.board_overlay(d, textures); self.draw_bottom_bar(d, textures); self.draw_top_bar(d, textures); if self.active_tool == Tool::Blueprint { - self.draw_blueprint_sidebar(d, textures); - } - - self.mouse = MouseInput::get(d); - - if !matches!(self.popup, Popup::None | Popup::Dismissed) { - self.tooltip.reset(); + let sidebar_height = d.get_screen_height() - FOOTER_HEIGHT - HEADER_HEIGHT - 40; d.draw_rectangle( 0, - 0, - d.get_screen_width(), - d.get_screen_height(), - Color::new(100, 100, 100, 120), + 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); - match self.popup { - Popup::Success | Popup::Failure => { - self.draw_end_popup(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; } - Popup::LevelInfo => { - 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); - } - 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, - &self.mouse, - 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, - &self.mouse, - 42 + 205, - y, - 32, - 32, - i, - &mut self.selected_blueprint, - ); + 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); - 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, 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); } - 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); } } @@ -734,37 +675,32 @@ impl Editor { ); if self.exit_menu { - if simple_button(d, &self.mouse, 4, 4, 32, 32) { + if simple_button(d, 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, &self.mouse, 40, 4, 32, 32) { + if simple_button(d, 38, 4, 32, 32) { self.exit_menu = false; } - draw_scaled_texture(d, textures.get("cancel"), 40, 4, 2.); - self.tooltip.add(40, 4, 32, 32, "cancel"); + draw_scaled_texture(d, textures.get("cancel"), 38, 4, 2.); + self.tooltip.add(38, 4, 32, 32, "cancel"); } else { - if simple_button(d, &self.mouse, 4, 4, 32, 32) { + if simple_button(d, 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, &self.mouse, 40, 4, 32, 32) { + if simple_button(d, 38, 4, 32, 32) { self.exit_state = ExitState::Save; } - draw_scaled_texture(d, textures.get("save"), 40, 4, 2.); - self.tooltip.add(40, 4, 32, 32, "save"); + draw_scaled_texture(d, textures.get("save"), 38, 4, 2.); + self.tooltip.add(38, 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, &self.mouse, 150, 4, 32, 32) { + if simple_button(d, 150, 4, 32, 32) { self.undo() } let undo_icon = if self.undo_index > 0 { @@ -775,7 +711,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, &self.mouse, 186, 4, 32, 32) { + if simple_button(d, 186, 4, 32, 32) { self.redo() } let redo_icon = if self.undo_index < self.undo_history.len() { @@ -787,7 +723,7 @@ impl Editor { } self.tooltip.add(223, 4, 32, 32, "Toggle overlay"); - if simple_button(d, &self.mouse, 223, 4, 32, 32) { + if simple_button(d, 223, 4, 32, 32) { self.draw_overlay = !self.draw_overlay; } let overlay_btn_icon = if self.draw_overlay { @@ -799,13 +735,13 @@ impl Editor { if self.sim_state == SimState::Running { self.tooltip.add(260, 4, 32, 32, "Pause"); - if simple_button(d, &self.mouse, 260, 4, 32, 32) { + if simple_button(d, 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, &self.mouse, 260, 4, 32, 32) { + if simple_button(d, 260, 4, 32, 32) { if self.sim_state == SimState::Editing { self.init_sim() } @@ -816,32 +752,22 @@ impl Editor { if self.sim_state != SimState::Editing { self.tooltip.add(296, 4, 32, 32, "Stop"); - if simple_button(d, &self.mouse, 296, 4, 32, 32) { + if simple_button(d, 296, 4, 32, 32) { self.sim_state = SimState::Editing; - self.popup = Popup::None; + self.popup = EndPopup::None; } draw_scaled_texture(d, textures.get("stop"), 296, 4, 2.); } self.tooltip.add(332, 4, 32, 32, "Step"); - if simple_button(d, &self.mouse, 332, 4, 32, 32) { + if simple_button(d, 332, 4, 32, 32) { self.step_pressed(); } draw_scaled_texture(d, textures.get("step"), 332, 4, 2.); self.tooltip.add(368, 4, 48, 32, "Speed"); draw_usize(d, textures, 1 << self.sim_speed, 368, 4, SPEED_DIGITS, 1); - slider( - d, - &self.mouse, - &mut self.sim_speed, - 0, - MAX_SPEED_POWER, - 368, - 24, - 48, - 12, - ); + slider(d, &mut self.sim_speed, 0, MAX_SPEED_POWER, 368, 24, 48, 12); self.tooltip.add(420, 4, 180, 32, "Steps"); draw_usize(d, textures, self.machine.step_count(), 420, 4, 9, 2); @@ -855,7 +781,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, &self.mouse, 600, 20, 35, 15) { + if simple_button(d, 600, 20, 35, 15) { self.input_as_text = !self.input_as_text } let input_mode_text = if self.input_as_text { "text" } else { "bytes" }; @@ -874,7 +800,6 @@ impl Editor { } if text_input( d, - &self.mouse, Rectangle::new(input_x as f32, 5., (width - input_x - 5) as f32, 30.), &mut input_text, &mut self.input_text_selected, @@ -928,7 +853,6 @@ impl Editor { hide_tile_tools = true; text_input( d, - &self.mouse, Rectangle::new(100., footer_top + 10., 240., 30.), &mut self.new_blueprint_name, &mut self.blueprint_name_selected, @@ -938,21 +862,19 @@ impl Editor { let y = footer_top as i32 + 49; self.tooltip.add(100, y, 40, 40, "Cancel"); - if simple_button(d, &self.mouse, 100, y, 40, 40) - || d.is_key_pressed(KeyboardKey::KEY_ESCAPE) - { + if simple_button(d, 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, &self.mouse, 144, y, 40, 40) { + if simple_button(d, 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, &self.mouse, 188, y, 40, 40) + if simple_button(d, 188, y, 40, 40) || (d.is_key_pressed(KeyboardKey::KEY_C) && d.is_key_down(KeyboardKey::KEY_LEFT_CONTROL)) { @@ -962,7 +884,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, &self.mouse, 232, y, 40, 40) { + if simple_button(d, 232, y, 40, 40) { let min = selection.0.min(selection.1); let max = selection.0.max(selection.1); let board = @@ -972,6 +894,7 @@ impl Editor { draw_scaled_texture(d, textures.get("eraser"), 236, y + 4, 2.); } + let mouse_pos = d.get_mouse_position(); let mut tool_button = |(row, col): (i32, i32), texture: &str, tooltip: &'static str, tool_option: Tool| { let border = 4.; @@ -983,20 +906,22 @@ impl Editor { x: 100. + col as f32 * grid_size - if col < 0 { 10. } else { 0. }, y: footer_top + 5. + row as f32 * grid_size, }; - self.tooltip.add_rec( - Rectangle::new(pos.x, pos.y, button_size, button_size), - tooltip, - ); - scrollable_texture_option_button( + texture_option_button( d, - &self.mouse, pos, textures.get(texture), tool_option, &mut self.active_tool, tex_size, border, - ) + ); + let bounds = Rectangle::new(pos.x, pos.y, button_size, button_size); + self.tooltip.add_rec(bounds, tooltip); + if bounds.check_collision_point_rec(mouse_pos) { + get_scroll(d) + } else { + None + } }; tool_button((0, -2), "eraser", "Eraser", Tool::Erase); tool_button( @@ -1117,7 +1042,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, &self.mouse, output_x, y + 70, 65, 15) { + if simple_button(d, output_x, y + 70, 65, 15) { self.output_as_text = !self.output_as_text } let output_mode_text = if self.output_as_text { @@ -1176,7 +1101,8 @@ impl Editor { fn board_overlay(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) { let footer_top = (d.get_screen_height() - FOOTER_HEIGHT) as f32; - + let mouse_pos = d.get_mouse_position(); + let scroll_delta = d.get_mouse_wheel_move(); let tile_size = TILE_TEXTURE_SIZE * self.zoom; if self.sim_state == SimState::Editing { if let Some(board) = &self.pasting_board { @@ -1184,18 +1110,18 @@ impl Editor { self.pasting_board = None; return; } - if self.mouse.pos().y < footer_top && self.mouse.pos().y > HEADER_HEIGHT as f32 { + if mouse_pos.y < footer_top && mouse_pos.y > HEADER_HEIGHT as f32 { let view_offset = Vector2::new( self.view_offset.x.rem(tile_size), self.view_offset.y.rem(tile_size), ); - let mut offset = self.mouse.pos() - view_offset; + let mut offset = mouse_pos - view_offset; offset.x -= offset.x.rem(tile_size); offset.y -= offset.y.rem(tile_size); offset += view_offset; board.draw(d, textures, offset, self.zoom); - if self.mouse.left_click() { - let tile_pos = (self.mouse.pos() - self.view_offset) / tile_size; + if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT) { + let tile_pos = (mouse_pos - self.view_offset) / tile_size; let tile_pos = Vector2::new(tile_pos.x.floor(), tile_pos.y.floor()); let board = self.pasting_board.take().unwrap(); self.set_area(tile_pos.into(), board); @@ -1231,8 +1157,8 @@ impl Editor { } } } - if self.mouse.pos().y < footer_top && self.mouse.pos().y > HEADER_HEIGHT as f32 { - let tile_pos = (self.mouse.pos() - self.view_offset) / tile_size; + if mouse_pos.y < footer_top && mouse_pos.y > HEADER_HEIGHT as f32 { + let tile_pos = (mouse_pos - self.view_offset) / tile_size; let tile_pos = Vector2::new(tile_pos.x.floor(), tile_pos.y.floor()); let tile_screen_pos = self.pos_to_screen(tile_pos); @@ -1266,7 +1192,7 @@ impl Editor { Color::new(255, 255, 255, 100), ); } - if self.mouse.left_click() { + if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT) { let pos = tile_pos.into(); match self.active_tool { Tool::None | Tool::Erase | Tool::SelectArea(_) => (), @@ -1289,7 +1215,7 @@ impl Editor { } } Tool::Blueprint => { - if self.mouse.pos().x > SIDEBAR_WIDTH as f32 { + if mouse_pos.x > SIDEBAR_WIDTH as f32 { if let Some(bp) = self.blueprints.get(self.selected_blueprint) { let board = bp.get_board().unwrap().clone(); self.set_area(pos, board); @@ -1298,11 +1224,13 @@ impl Editor { } } } - if self.mouse.left_hold() && self.active_tool == Tool::Erase { + if d.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT) + && self.active_tool == Tool::Erase + { self.set_tile(tile_pos.into(), Tile::BLANK); } if let Tool::SelectArea(selection) = &mut self.active_tool { - if self.mouse.left_hold() { + if d.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT) { if selection.is_selecting { if let Some((_start, end)) = &mut selection.area { *end = tile_pos.into(); @@ -1313,7 +1241,7 @@ impl Editor { selection.area = Some((tile_pos.into(), tile_pos.into())); selection.is_selecting = true; } - } else if self.mouse.left_release() { + } else if d.is_mouse_button_released(MouseButton::MOUSE_BUTTON_LEFT) { selection.is_selecting = false; } } @@ -1323,20 +1251,18 @@ impl Editor { self.view_offset.x.rem(tile_size), self.view_offset.y.rem(tile_size), ); - let mut offset = self.mouse.pos() - view_offset; + let mut offset = mouse_pos - view_offset; offset.x -= offset.x.rem(tile_size); offset.y -= offset.y.rem(tile_size); offset += view_offset; bp.convert_board().draw(d, textures, offset, self.zoom); } - if self.mouse.pos().x < SIDEBAR_WIDTH as f32 { - if self.mouse.scroll() == Some(Scroll::Down) + if mouse_pos.x < SIDEBAR_WIDTH as f32 { + if scroll_delta < 0. && self.blueprint_scroll < self.blueprints.len().saturating_sub(5) { self.blueprint_scroll += 1; - } else if self.mouse.scroll() == Some(Scroll::Up) - && self.blueprint_scroll > 0 - { + } else if scroll_delta > 0. && self.blueprint_scroll > 0 { self.blueprint_scroll -= 1; } } diff --git a/src/main.rs b/src/main.rs index 0cf3a8a..760c56d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -123,16 +123,19 @@ 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); + + 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(); 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 mouse_pos.x < level_list_width as f32 { + if scroll_delta < 0. && self.level_scroll < max_scroll { self.level_scroll += 1; } - if mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0 { + if scroll_delta > 0. && self.level_scroll > 0 { self.level_scroll -= 1; } } @@ -146,7 +149,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 = clicked && bounds.check_collision_point_rec(mouse_pos); match level { LevelListEntry::Chapter(title, level_count) => { d.draw_rectangle_rec(bounds, BG_DARK); @@ -207,7 +210,6 @@ impl Game { for (solution_index, solution) in solutions.iter().enumerate() { if simple_option_button( d, - &mouse, level_list_width + 10, solution_y, entry_width, @@ -240,14 +242,7 @@ impl Game { } let next_id = get_free_id(solutions, Solution::id); - if simple_button( - d, - &mouse, - level_list_width + 10, - solution_y, - entry_width, - 30, - ) { + if simple_button(d, level_list_width + 10, solution_y, entry_width, 30) { self.selected_solution = solutions.len(); solutions.push(Solution::new(level, next_id)); } @@ -264,7 +259,6 @@ impl Game { let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.); if text_input( d, - &mouse, bounds, &mut solution.name, &mut self.editing_solution_name, @@ -276,7 +270,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, &mouse, column_x, y + 50, 220, 30) { + if simple_button(d, column_x, y + 50, 220, 30) { let cloned = solution.new_copy(next_id); self.selected_solution = solutions.len(); solutions.push(cloned); @@ -284,7 +278,7 @@ impl Game { } d.draw_text("clone", column_x + 5, y + 55, 20, Color::WHITE); - if simple_button(d, &mouse, column_x, y + 85, 220, 30) { + if simple_button(d, 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 7ef9660..c4de24b 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use crate::{draw_scaled_texture, theme::*, MouseInput, Scroll, Textures}; +use crate::{draw_scaled_texture, theme::*, Textures}; use raylib::prelude::*; #[derive(Debug)] @@ -99,7 +99,7 @@ pub struct Tooltip { } impl Tooltip { - pub fn init_frame(&mut self, d: &RaylibHandle) { + pub fn init_frame(&mut self, d: &mut RaylibDrawHandle) { let p = d.get_mouse_position(); *self = Self { text: None, @@ -120,10 +120,6 @@ 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, @@ -157,15 +153,8 @@ impl Tooltip { } } -pub fn simple_button( - d: &mut RaylibDrawHandle, - mouse: &MouseInput, - x: i32, - y: i32, - width: i32, - height: i32, -) -> bool { - let mouse_pos = mouse.pos(); +pub fn simple_button(d: &mut RaylibDrawHandle, x: i32, y: i32, width: i32, height: i32) -> bool { + let mouse_pos = d.get_mouse_position(); let bounds = Rectangle { x: x as f32, y: y as f32, @@ -173,14 +162,13 @@ pub fn simple_button( height: height as f32, }; let hover = bounds.check_collision_point_rec(mouse_pos); - let pressed = hover && mouse.left_click(); + let pressed = hover && d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT); d.draw_rectangle(x, y, width, height, widget_bg(hover)); pressed } pub fn simple_option_button( d: &mut RaylibDrawHandle, - mouse: &MouseInput, x: i32, y: i32, width: i32, @@ -193,8 +181,12 @@ where { let bounds = Rectangle::new(x as f32, y as f32, width as f32, height as f32); d.draw_rectangle_rec(bounds, widget_bg(&option == current)); + let mouse_pos = d.get_mouse_position(); let mut changed = false; - if mouse.left_click() && mouse.is_over(bounds) && current != &option { + if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT) + && bounds.check_collision_point_rec(mouse_pos) + && current != &option + { *current = option; changed = true; } @@ -203,7 +195,6 @@ where pub fn text_input( d: &mut RaylibDrawHandle, - mouse: &MouseInput, bounds: Rectangle, text: &mut String, is_selected: &mut bool, @@ -233,7 +224,11 @@ pub fn text_input( 20, Color::WHITE, ); - if editable && mouse.left_click() && (mouse.is_over(bounds) || *is_selected) { + let mouse_pos = d.get_mouse_position(); + if editable + && d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT) + && (bounds.check_collision_point_rec(mouse_pos) || *is_selected) + { *is_selected = !*is_selected; } @@ -261,17 +256,16 @@ pub fn text_input( changed } -pub fn scrollable_texture_option_button( +pub fn texture_option_button( d: &mut RaylibDrawHandle, - mouse: &MouseInput, pos: Vector2, texture: &Texture2D, option: T, current: &mut T, tex_size: f32, border: f32, -) -> Option -where + // tooltip +) where T: PartialEq, { let bounds = Rectangle { @@ -295,13 +289,13 @@ where tex_size / texture.width as f32, Color::WHITE, ); - if mouse.is_over(bounds) { - if mouse.left_click() { - *current = option; - } - return mouse.scroll(); + + let mouse_pos = d.get_mouse_position(); + if d.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT) + && bounds.check_collision_point_rec(mouse_pos) + { + *current = option; } - None } pub fn draw_usize( @@ -356,7 +350,6 @@ pub fn draw_usize_small( pub fn slider( d: &mut RaylibDrawHandle, - mouse: &MouseInput, value: &mut u8, min: u8, max: u8, @@ -369,19 +362,38 @@ pub fn slider( let percent = (*value - min + 1) as f32 / (max - min + 1) as f32; d.draw_rectangle(x, y, width, height, BG_WIDGET); d.draw_rectangle(x, y, (width as f32 * percent) as i32, height, Color::CYAN); + let mouse_pos = d.get_mouse_position(); let bounds = Rectangle::new(x as f32, y as f32, width as f32, height as f32); - if mouse.is_over(bounds) { - if mouse.left_hold() { - let percent = (mouse.pos().x - bounds.x) / bounds.width; + if bounds.check_collision_point_rec(mouse_pos) { + if d.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT) { + let percent = (mouse_pos.x - bounds.x) / bounds.width; let new_value = min + (percent * (max - min + 1) as f32) as u8; if *value != new_value { *value = new_value; } - } else if mouse.scroll() == Some(Scroll::Up) && *value < max { + } else if d.get_mouse_wheel_move() > 0.5 && *value < max { *value += 1; - } else if mouse.scroll() == Some(Scroll::Down) && *value > min { + } else if d.get_mouse_wheel_move() < -0.5 && *value > min { *value -= 1; } } 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 de8cd9d..a06960f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -50,87 +50,3 @@ 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, - left_release: 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), - 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 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 left_release(&self) -> bool { - self.left_release - } - - 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 - } -}