disable all input bindings while in a text edit box

This commit is contained in:
Crispy 2025-04-16 22:30:22 +02:00
parent 62fcb538a6
commit 509b577aaa
6 changed files with 104 additions and 51 deletions

View file

@ -3,6 +3,7 @@ Game store page: https://crispypin.itch.io/marble-machinations
## [unreleased] ## [unreleased]
### fixed ### fixed
- keybindings activated even when typing in a text field, making especially renaming blueprints difficult
- after removing a binding that was a superset of another, the remaining one did not stop being blocked by the removed ones additional modifiers until another binding was added or edited - after removing a binding that was a superset of another, the remaining one did not stop being blocked by the removed ones additional modifiers until another binding was added or edited
## v0.3.2 - 2025-04-14 ## v0.3.2 - 2025-04-14

View file

@ -7,9 +7,9 @@ logic mostly like https://git.crispypin.cc/CrispyPin/marble
## todo ## todo
### meta ### meta
- engine tests - engine tests
- blag post about marble movement logic - blag post about marble movement logic?
### bugs ### bugs
- modifier-less bindings trigger when typing in a text box, makes renaming existing blueprints basically impossible
### features ### features
#### 0.3.x #### 0.3.x
- more levels - more levels

View file

@ -574,27 +574,35 @@ impl Editor {
} }
} }
fn draw_board(&self, d: &mut RaylibDrawHandle, textures: &Textures) { fn draw_board(&self, d: &mut RaylibDrawHandle, globals: &Globals) {
if self.sim_state == SimState::Editing { if self.sim_state == SimState::Editing {
self.source_board self.source_board
.grid .grid
.draw(d, textures, self.view_offset, self.zoom); .draw(d, &globals.textures, self.view_offset, self.zoom);
} else { } else {
if self.machine.debug_subticks.is_empty() { if self.machine.debug_subticks.is_empty() {
self.machine self.machine
.grid() .grid()
.draw(d, textures, self.view_offset, self.zoom); .draw(d, &globals.textures, self.view_offset, self.zoom);
} else { } else {
let subframe = &self.machine.debug_subticks[self.machine.subtick_index]; let subframe = &self.machine.debug_subticks[self.machine.subtick_index];
subframe.grid.draw(d, textures, self.view_offset, self.zoom); subframe
.grid
.draw(d, &globals.textures, self.view_offset, self.zoom);
if let Some(pos) = subframe.pos { if let Some(pos) = subframe.pos {
let p = self.pos_to_screen(pos.to_vec()); let p = self.pos_to_screen(pos.to_vec());
d.draw_texture_ex(textures.get("selection"), p, 0., self.zoom, Color::ORANGE); d.draw_texture_ex(
globals.get_tex("selection"),
p,
0.,
self.zoom,
Color::ORANGE,
);
} }
} }
if self.draw_overlay { if self.draw_overlay {
self.machine self.machine
.draw_marble_values(d, textures, self.view_offset, self.zoom); .draw_marble_values(d, &globals.textures, self.view_offset, self.zoom);
} }
} }
if self.draw_overlay { if self.draw_overlay {
@ -620,13 +628,13 @@ impl Editor {
} }
} }
self.draw_board(d, &globals.textures); self.draw_board(d, globals);
self.board_overlay(d, &globals.textures); self.board_overlay(d, globals);
self.draw_bottom_bar(d, globals); self.draw_bottom_bar(d, globals);
self.draw_top_bar(d, globals); self.draw_top_bar(d, globals);
if self.active_tool == Tool::Blueprint { if self.active_tool == Tool::Blueprint {
self.draw_blueprint_sidebar(d, &globals.textures); self.draw_blueprint_sidebar(d, globals);
} }
self.mouse.update(d); self.mouse.update(d);
@ -676,7 +684,7 @@ impl Editor {
self.tooltip.draw(d); self.tooltip.draw(d);
} }
fn draw_blueprint_sidebar(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) { fn draw_blueprint_sidebar(&mut self, d: &mut RaylibDrawHandle, globals: &mut Globals) {
let sidebar_height = d.get_screen_height() - FOOTER_HEIGHT - HEADER_HEIGHT - 40; let sidebar_height = d.get_screen_height() - FOOTER_HEIGHT - HEADER_HEIGHT - 40;
d.draw_rectangle( d.draw_rectangle(
0, 0,
@ -700,7 +708,7 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(5, y), (5, y),
textures.get("rubbish"), globals.get_tex("rubbish"),
(&mut self.tooltip, "Delete"), (&mut self.tooltip, "Delete"),
) { ) {
b.remove_file(); b.remove_file();
@ -711,7 +719,7 @@ impl Editor {
let mut text_selected = is_selected && self.blueprint_name_selected; let mut text_selected = is_selected && self.blueprint_name_selected;
text_input( text_input(
d, d,
&self.mouse, globals,
Rectangle::new(42., y as f32, 200., 32.), Rectangle::new(42., y as f32, 200., 32.),
&mut b.name, &mut b.name,
&mut text_selected, &mut text_selected,
@ -730,7 +738,7 @@ impl Editor {
); );
d.draw_texture_ex( d.draw_texture_ex(
textures.get("blueprint"), globals.get_tex("blueprint"),
Vector2::new((42 + 205) as f32, y as f32), Vector2::new((42 + 205) as f32, y as f32),
0., 0.,
2., 2.,
@ -789,8 +797,7 @@ impl Editor {
} }
} }
fn draw_top_bar(&mut self, d: &mut RaylibDrawHandle, globals: &Globals) { fn draw_top_bar(&mut self, d: &mut RaylibDrawHandle, globals: &mut Globals) {
let textures = &globals.textures;
// background // background
d.draw_rectangle( d.draw_rectangle(
0, 0,
@ -803,7 +810,7 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(4, 4), (4, 4),
textures.get("exit"), globals.get_tex("exit"),
(&mut self.tooltip, "exit"), (&mut self.tooltip, "exit"),
) { ) {
if self.exit_menu { if self.exit_menu {
@ -816,7 +823,7 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(40, 4), (40, 4),
textures.get("cancel"), globals.get_tex("cancel"),
(&mut self.tooltip, "cancel"), (&mut self.tooltip, "cancel"),
) { ) {
self.exit_menu = false; self.exit_menu = false;
@ -824,7 +831,7 @@ impl Editor {
} else if tex32_button( } else if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(40, 4), (40, 4),
textures.get("save"), globals.get_tex("save"),
(&mut self.tooltip, "save"), (&mut self.tooltip, "save"),
) || globals.is_pressed(ActionId::Save) ) || globals.is_pressed(ActionId::Save)
{ {
@ -844,7 +851,7 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(150, 4), (150, 4),
textures.get(undo_icon), globals.get_tex(undo_icon),
(&mut self.tooltip, "Undo"), (&mut self.tooltip, "Undo"),
) { ) {
self.undo() self.undo()
@ -858,7 +865,7 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(186, 4), (186, 4),
textures.get(redo_icon), globals.get_tex(redo_icon),
(&mut self.tooltip, "Redo"), (&mut self.tooltip, "Redo"),
) { ) {
self.redo() self.redo()
@ -873,7 +880,7 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(223, 4), (223, 4),
textures.get(overlay_btn_icon), globals.get_tex(overlay_btn_icon),
(&mut self.tooltip, "Toggle overlay"), (&mut self.tooltip, "Toggle overlay"),
) { ) {
self.draw_overlay = !self.draw_overlay; self.draw_overlay = !self.draw_overlay;
@ -883,7 +890,7 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(260, 4), (260, 4),
textures.get("pause"), globals.get_tex("pause"),
(&mut self.tooltip, "Pause"), (&mut self.tooltip, "Pause"),
) { ) {
self.sim_state = SimState::Stepping; self.sim_state = SimState::Stepping;
@ -891,7 +898,7 @@ impl Editor {
} else if tex32_button( } else if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(260, 4), (260, 4),
textures.get("play"), globals.get_tex("play"),
(&mut self.tooltip, "Start"), (&mut self.tooltip, "Start"),
) { ) {
if self.sim_state == SimState::Editing { if self.sim_state == SimState::Editing {
@ -904,7 +911,7 @@ impl Editor {
&& tex32_button( && tex32_button(
(d, &self.mouse), (d, &self.mouse),
(296, 4), (296, 4),
textures.get("stop"), globals.get_tex("stop"),
(&mut self.tooltip, "Stop"), (&mut self.tooltip, "Stop"),
) { ) {
self.sim_state = SimState::Editing; self.sim_state = SimState::Editing;
@ -914,14 +921,21 @@ impl Editor {
if tex32_button( if tex32_button(
(d, &self.mouse), (d, &self.mouse),
(332, 4), (332, 4),
textures.get("step"), globals.get_tex("step"),
(&mut self.tooltip, "Step"), (&mut self.tooltip, "Step"),
) { ) {
self.step_pressed(); self.step_pressed();
} }
self.tooltip.add(368, 4, 48, 32, "Speed"); self.tooltip.add(368, 4, 48, 32, "Speed");
draw_usize(d, textures, 1 << self.sim_speed, (368, 4), SPEED_DIGITS, 1); draw_usize(
d,
&globals.textures,
1 << self.sim_speed,
(368, 4),
SPEED_DIGITS,
1,
);
slider( slider(
(d, &self.mouse), (d, &self.mouse),
rect(368, 24, 48, 12), rect(368, 24, 48, 12),
@ -931,20 +945,48 @@ impl Editor {
); );
self.tooltip.add(420, 4, 180, 32, "Steps"); self.tooltip.add(420, 4, 180, 32, "Steps");
draw_usize(d, textures, self.machine.step_count(), (420, 4), 9, 2); draw_usize(
d,
&globals.textures,
self.machine.step_count(),
(420, 4),
9,
2,
);
if self.stage > Some(0) { if self.stage > Some(0) {
self.tooltip.add(420, 44, 180, 32, "Total steps"); self.tooltip.add(420, 44, 180, 32, "Total steps");
let total_steps = self.total_steps + self.machine.step_count(); let total_steps = self.total_steps + self.machine.step_count();
draw_usize(d, textures, total_steps, (420, 44), 9, 2); draw_usize(d, &globals.textures, total_steps, (420, 44), 9, 2);
} }
draw_usize(d, textures, self.step_time as usize, (260, 42), 9, 1); draw_usize(
draw_usize(d, textures, self.max_step_time as usize, (260, 60), 9, 1); d,
&globals.textures,
self.step_time as usize,
(260, 42),
9,
1,
);
draw_usize(
d,
&globals.textures,
self.max_step_time as usize,
(260, 60),
9,
1,
);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
draw_usize(d, textures, self.machine.subtick_index, (260, 80), 9, 1); draw_usize(
d,
&globals.textures,
self.machine.subtick_index,
(260, 80),
9,
1,
);
let subtick_count = self.machine.debug_subticks.len(); let subtick_count = self.machine.debug_subticks.len();
draw_usize(d, textures, subtick_count, (260, 100), 9, 1); draw_usize(d, &globals.textures, subtick_count, (260, 100), 9, 1);
} }
d.draw_text("input:", 603, 8, 10, Color::WHITE); d.draw_text("input:", 603, 8, 10, Color::WHITE);
@ -967,7 +1009,7 @@ impl Editor {
} }
if text_input( if text_input(
d, d,
&self.mouse, globals,
Rectangle::new(input_x as f32, 5., (width - input_x - 5) as f32, 30.), Rectangle::new(input_x as f32, 5., (width - input_x - 5) as f32, 30.),
&mut input_text, &mut input_text,
&mut self.input_text_selected, &mut self.input_text_selected,
@ -1021,7 +1063,7 @@ impl Editor {
hide_tile_tools = true; hide_tile_tools = true;
text_input( text_input(
d, d,
&self.mouse, globals,
Rectangle::new(100., footer_top + 10., 240., 30.), Rectangle::new(100., footer_top + 10., 240., 30.),
&mut self.new_blueprint_name, &mut self.new_blueprint_name,
&mut self.blueprint_name_selected, &mut self.blueprint_name_selected,
@ -1317,7 +1359,7 @@ impl Editor {
} }
} }
fn board_overlay(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) { fn board_overlay(&mut self, d: &mut RaylibDrawHandle, globals: &Globals) {
let footer_top = (d.get_screen_height() - FOOTER_HEIGHT) as f32; let footer_top = (d.get_screen_height() - FOOTER_HEIGHT) as f32;
let tile_size = TILE_TEXTURE_SIZE * self.zoom; let tile_size = TILE_TEXTURE_SIZE * self.zoom;
@ -1336,7 +1378,7 @@ impl Editor {
offset.x -= offset.x.rem(tile_size); offset.x -= offset.x.rem(tile_size);
offset.y -= offset.y.rem(tile_size); offset.y -= offset.y.rem(tile_size);
offset += view_offset; offset += view_offset;
board.grid.draw(d, textures, offset, self.zoom); board.grid.draw(d, &globals.textures, offset, self.zoom);
board.draw_comments(d, offset, self.zoom); board.draw_comments(d, offset, self.zoom);
if self.mouse.left_click() { if self.mouse.left_click() {
let tile_pos = (self.mouse.pos() - self.view_offset) / tile_size; let tile_pos = (self.mouse.pos() - self.view_offset) / tile_size;
@ -1350,7 +1392,7 @@ impl Editor {
if let Tool::Digits(Some(pos)) = &mut self.active_tool { if let Tool::Digits(Some(pos)) = &mut self.active_tool {
let tile_screen_pos = pos.to_vec() * tile_size + self.view_offset; let tile_screen_pos = pos.to_vec() * tile_size + self.view_offset;
d.draw_texture_ex( d.draw_texture_ex(
textures.get("selection"), globals.get_tex("selection"),
tile_screen_pos, tile_screen_pos,
0., 0.,
self.zoom, self.zoom,
@ -1403,7 +1445,7 @@ impl Editor {
}; };
d.draw_texture_ex( d.draw_texture_ex(
textures.get(tex), globals.get_tex(tex),
tile_screen_pos, tile_screen_pos,
0., 0.,
self.zoom, self.zoom,
@ -1473,7 +1515,7 @@ impl Editor {
offset.x -= offset.x.rem(tile_size); offset.x -= offset.x.rem(tile_size);
offset.y -= offset.y.rem(tile_size); offset.y -= offset.y.rem(tile_size);
offset += view_offset; offset += view_offset;
bp.board.grid.draw(d, textures, offset, self.zoom); bp.board.grid.draw(d, &globals.textures, offset, self.zoom);
bp.board.draw_comments(d, offset, self.zoom); bp.board.draw_comments(d, offset, self.zoom);
} }
if self.mouse.pos().x < SIDEBAR_WIDTH as f32 { if self.mouse.pos().x < SIDEBAR_WIDTH as f32 {

View file

@ -97,6 +97,7 @@ impl Default for Input {
bindings, bindings,
states: Default::default(), states: Default::default(),
editing_binding: None, editing_binding: None,
in_text_edit: false,
} }
} }
} }
@ -118,6 +119,7 @@ pub struct Input {
bindings: [Vec<Binding>; ActionId::SIZE], bindings: [Vec<Binding>; ActionId::SIZE],
states: [BindingState; ActionId::SIZE], states: [BindingState; ActionId::SIZE],
editing_binding: Option<(ActionId, usize, BindingEdit)>, editing_binding: Option<(ActionId, usize, BindingEdit)>,
pub in_text_edit: bool,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -284,11 +286,13 @@ impl Input {
for i in 0..ActionId::SIZE { for i in 0..ActionId::SIZE {
let bindings = &self.bindings[i]; let bindings = &self.bindings[i];
let mut is_active = false; let mut is_active = false;
for binding in bindings { if !self.in_text_edit {
if binding.modifiers.iter().all(|&m| m.is_down(rl)) for binding in bindings {
&& !binding.blocking_modifiers.iter().any(|&m| m.is_down(rl)) if binding.modifiers.iter().all(|&m| m.is_down(rl))
{ && !binding.blocking_modifiers.iter().any(|&m| m.is_down(rl))
is_active |= binding.trigger.is_down(rl); {
is_active |= binding.trigger.is_down(rl);
}
} }
} }
let state = &mut self.states[i]; let state = &mut self.states[i];
@ -304,6 +308,7 @@ impl Input {
} }
} }
} }
self.in_text_edit = false;
} }
pub fn is_pressed(&self, action: ActionId) -> bool { pub fn is_pressed(&self, action: ActionId) -> bool {

View file

@ -315,7 +315,7 @@ impl Game {
let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.); let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.);
if text_input( if text_input(
d, d,
&self.globals.mouse, &mut self.globals,
bounds, bounds,
&mut solution.name, &mut solution.name,
&mut self.editing_solution_name, &mut self.editing_solution_name,

View file

@ -1,6 +1,10 @@
use std::ops::Range; use std::ops::Range;
use crate::{theme::*, util::draw_scaled_texture, util::MouseInput, util::Scroll, util::Textures}; use crate::{
theme::*,
util::{draw_scaled_texture, MouseInput, Scroll, Textures},
Globals,
};
use raylib::prelude::*; use raylib::prelude::*;
#[derive(Debug)] #[derive(Debug)]
@ -225,7 +229,7 @@ where
pub fn text_input( pub fn text_input(
d: &mut RaylibDrawHandle, d: &mut RaylibDrawHandle,
mouse: &MouseInput, globals: &mut Globals,
bounds: Rectangle, bounds: Rectangle,
text: &mut String, text: &mut String,
is_selected: &mut bool, is_selected: &mut bool,
@ -262,12 +266,13 @@ pub fn text_input(
Color::WHITE, Color::WHITE,
); );
}; };
if editable && mouse.left_click() && (mouse.is_over(bounds) || *is_selected) { if editable && globals.mouse.left_click() && (globals.mouse.is_over(bounds) || *is_selected) {
*is_selected = !*is_selected; *is_selected = !*is_selected;
} }
if *is_selected { if *is_selected {
if d.is_key_pressed(KeyboardKey::KEY_ESCAPE) { globals.config.input.in_text_edit = true;
if d.is_key_pressed(KeyboardKey::KEY_ESCAPE) || d.is_key_pressed(KeyboardKey::KEY_ENTER) {
*is_selected = false; *is_selected = false;
} }
if d.is_key_pressed(KeyboardKey::KEY_BACKSPACE) && !text.is_empty() { if d.is_key_pressed(KeyboardKey::KEY_BACKSPACE) && !text.is_empty() {