enter and exit solution editor
This commit is contained in:
parent
44b7d63cde
commit
c4381ac1a1
8 changed files with 195 additions and 41 deletions
|
@ -4,9 +4,8 @@
|
||||||
logic mostly like https://git.crispypin.cc/CrispyPin/marble
|
logic mostly like https://git.crispypin.cc/CrispyPin/marble
|
||||||
|
|
||||||
## todo
|
## todo
|
||||||
level selection
|
|
||||||
|
|
||||||
solution saving & loading
|
solution saving & loading
|
||||||
|
cleanup: unpowered texture names x_off -> x
|
||||||
input/output display
|
input/output display
|
||||||
grow grid automatically while editing
|
grow grid automatically while editing
|
||||||
sim/speed control gui
|
sim/speed control gui
|
||||||
|
|
121
src/editor.rs
121
src/editor.rs
|
@ -9,9 +9,14 @@ use crate::{
|
||||||
tile::{Direction, GateType, MathOp, MirrorType, PTile, Tile, WireType},
|
tile::{Direction, GateType, MathOp, MirrorType, PTile, Tile, WireType},
|
||||||
Machine,
|
Machine,
|
||||||
},
|
},
|
||||||
|
simple_button,
|
||||||
|
solution::Solution,
|
||||||
text_input, texture_option_button, Textures,
|
text_input, texture_option_button, Textures,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const HEADER_HEIGHT: i32 = 40;
|
||||||
|
const FOOTER_HEIGHT: i32 = 95;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
source_board: Board,
|
source_board: Board,
|
||||||
|
@ -31,6 +36,8 @@ pub struct Editor {
|
||||||
input_text_selected: bool,
|
input_text_selected: bool,
|
||||||
sim_speed: f32,
|
sim_speed: f32,
|
||||||
time_since_step: f32,
|
time_since_step: f32,
|
||||||
|
exit_state: ExitState,
|
||||||
|
exit_menu: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -53,10 +60,17 @@ enum SimState {
|
||||||
Stepping,
|
Stepping,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum ExitState {
|
||||||
|
Dont,
|
||||||
|
ExitAndSave,
|
||||||
|
ExitNoSave,
|
||||||
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn new_sandbox() -> Self {
|
pub fn new(solution: Solution, level: Level) -> Self {
|
||||||
Self {
|
Self {
|
||||||
source_board: Board::new_empty(16, 16),
|
source_board: Board::parse(&solution.board),
|
||||||
machine: Machine::new_empty(1),
|
machine: Machine::new_empty(1),
|
||||||
sim_state: SimState::Editing,
|
sim_state: SimState::Editing,
|
||||||
view_offset: Vector2::zero(),
|
view_offset: Vector2::zero(),
|
||||||
|
@ -72,10 +86,28 @@ impl Editor {
|
||||||
tool_menu_arrow: Direction::Right,
|
tool_menu_arrow: Direction::Right,
|
||||||
tool_menu_mirror: MirrorType::Forward,
|
tool_menu_mirror: MirrorType::Forward,
|
||||||
tool_menu_wire: WireType::Vertical,
|
tool_menu_wire: WireType::Vertical,
|
||||||
level: Level::new_sandbox(),
|
level,
|
||||||
|
exit_state: ExitState::Dont,
|
||||||
|
exit_menu: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_exit_state(&self) -> ExitState {
|
||||||
|
self.exit_state
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn level_id(&self) -> &str {
|
||||||
|
&self.level.id()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_board(&self) -> &Board {
|
||||||
|
&self.source_board
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_board(&mut self, board: Board) {
|
pub fn load_board(&mut self, board: Board) {
|
||||||
self.source_board = board;
|
self.source_board = board;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +163,9 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&mut self, rl: &RaylibHandle) {
|
pub fn input(&mut self, rl: &RaylibHandle) {
|
||||||
|
if rl.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
|
||||||
|
self.sim_state = SimState::Editing
|
||||||
|
}
|
||||||
if self.sim_state == SimState::Running {
|
if self.sim_state == SimState::Running {
|
||||||
self.time_since_step += rl.get_frame_time();
|
self.time_since_step += rl.get_frame_time();
|
||||||
if self.time_since_step > 1. / self.sim_speed {
|
if self.time_since_step > 1. / self.sim_speed {
|
||||||
|
@ -149,9 +184,6 @@ impl Editor {
|
||||||
}
|
}
|
||||||
self.sim_state = SimState::Stepping;
|
self.sim_state = SimState::Stepping;
|
||||||
}
|
}
|
||||||
if rl.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
|
|
||||||
self.sim_state = SimState::Editing;
|
|
||||||
}
|
|
||||||
if rl.is_key_pressed(KeyboardKey::KEY_ENTER) {
|
if rl.is_key_pressed(KeyboardKey::KEY_ENTER) {
|
||||||
match self.sim_state {
|
match self.sim_state {
|
||||||
SimState::Editing => {
|
SimState::Editing => {
|
||||||
|
@ -175,6 +207,10 @@ impl Editor {
|
||||||
if rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_RIGHT) {
|
if rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_RIGHT) {
|
||||||
self.view_offset = Vector2::zero();
|
self.view_offset = Vector2::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rl.is_key_pressed(KeyboardKey::KEY_R) {
|
||||||
|
self.rotate_tool(rl.is_key_down(KeyboardKey::KEY_LEFT_SHIFT));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_board(&self, d: &mut RaylibDrawHandle, textures: &Textures) {
|
fn draw_board(&self, d: &mut RaylibDrawHandle, textures: &Textures) {
|
||||||
|
@ -192,18 +228,6 @@ impl Editor {
|
||||||
|
|
||||||
pub fn draw(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) {
|
pub fn draw(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) {
|
||||||
d.clear_background(Color::new(64, 64, 64, 255));
|
d.clear_background(Color::new(64, 64, 64, 255));
|
||||||
self.draw_board(d, textures);
|
|
||||||
|
|
||||||
let height = d.get_screen_height();
|
|
||||||
let footer_height = 95;
|
|
||||||
let footer_top = (height - footer_height) as f32;
|
|
||||||
d.draw_rectangle(
|
|
||||||
0,
|
|
||||||
height - footer_height,
|
|
||||||
d.get_screen_width(),
|
|
||||||
footer_height,
|
|
||||||
Color::new(32, 32, 32, 255),
|
|
||||||
);
|
|
||||||
|
|
||||||
let tile_size = (16 << self.zoom) as f32;
|
let tile_size = (16 << self.zoom) as f32;
|
||||||
let grid_spill_x = (self.view_offset.x).rem(tile_size) - tile_size;
|
let grid_spill_x = (self.view_offset.x).rem(tile_size) - tile_size;
|
||||||
|
@ -213,13 +237,62 @@ impl Editor {
|
||||||
grid_spill_x,
|
grid_spill_x,
|
||||||
grid_spill_y,
|
grid_spill_y,
|
||||||
d.get_screen_width() as f32 * 2.,
|
d.get_screen_width() as f32 * 2.,
|
||||||
height as f32 - grid_spill_y - footer_height as f32,
|
d.get_screen_height() as f32 * 2.,
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
tile_size,
|
tile_size,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.draw_board(d, textures);
|
||||||
|
self.board_overlay(d, textures);
|
||||||
|
self.draw_bottom_bar(d, textures);
|
||||||
|
self.draw_top_bar(d, textures);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_top_bar(&mut self, d: &mut RaylibDrawHandle, _textures: &Textures) {
|
||||||
|
// background
|
||||||
|
d.draw_rectangle(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
d.get_screen_width(),
|
||||||
|
HEADER_HEIGHT,
|
||||||
|
Color::new(32, 32, 32, 255),
|
||||||
|
);
|
||||||
|
|
||||||
|
if self.exit_menu {
|
||||||
|
if simple_button(d, 5, 5, 80, 30) {
|
||||||
|
self.exit_menu = false;
|
||||||
|
}
|
||||||
|
d.draw_text("cancel", 10, 10, 20, Color::WHITE);
|
||||||
|
if simple_button(d, 90, 5, 80, 30) {
|
||||||
|
self.exit_state = ExitState::ExitAndSave;
|
||||||
|
}
|
||||||
|
d.draw_text("save", 95, 10, 20, Color::WHITE);
|
||||||
|
if simple_button(d, 175, 5, 80, 30) {
|
||||||
|
self.exit_state = ExitState::ExitNoSave;
|
||||||
|
}
|
||||||
|
d.draw_text("revert", 180, 10, 20, Color::WHITE);
|
||||||
|
} else {
|
||||||
|
if simple_button(d, 5, 5, 80, 30) {
|
||||||
|
self.exit_menu = true;
|
||||||
|
}
|
||||||
|
d.draw_text("exit", 10, 10, 20, Color::WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_bottom_bar(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) {
|
||||||
|
let height = d.get_screen_height();
|
||||||
|
let footer_top = (height - FOOTER_HEIGHT) as f32;
|
||||||
|
// background
|
||||||
|
d.draw_rectangle(
|
||||||
|
0,
|
||||||
|
height - FOOTER_HEIGHT,
|
||||||
|
d.get_screen_width(),
|
||||||
|
FOOTER_HEIGHT,
|
||||||
|
Color::new(32, 32, 32, 255),
|
||||||
|
);
|
||||||
|
|
||||||
d.gui_check_box(
|
d.gui_check_box(
|
||||||
Rectangle::new(5., footer_top + 5., 25., 25.),
|
Rectangle::new(5., footer_top + 5., 25., 25.),
|
||||||
Some(rstr!("output as text")),
|
Some(rstr!("output as text")),
|
||||||
|
@ -297,12 +370,10 @@ impl Editor {
|
||||||
&Tile::Powerable(PTile::Gate(self.tool_menu_gate), false).texture(),
|
&Tile::Powerable(PTile::Gate(self.tool_menu_gate), false).texture(),
|
||||||
Tool::Gate,
|
Tool::Gate,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let is_shift = d.is_key_down(KeyboardKey::KEY_LEFT_SHIFT);
|
fn board_overlay(&mut self, d: &mut RaylibDrawHandle, textures: &Textures) {
|
||||||
if d.is_key_pressed(KeyboardKey::KEY_R) {
|
let footer_top = (d.get_screen_height() - FOOTER_HEIGHT) as f32;
|
||||||
self.rotate_tool(is_shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouse_pos = d.get_mouse_position();
|
let mouse_pos = d.get_mouse_position();
|
||||||
if self.sim_state == SimState::Editing {
|
if self.sim_state == SimState::Editing {
|
||||||
if let Tool::Digits(Some(pos)) = &mut self.active_tool {
|
if let Tool::Digits(Some(pos)) = &mut self.active_tool {
|
||||||
|
@ -334,7 +405,7 @@ impl Editor {
|
||||||
pos.y += 1;
|
pos.y += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mouse_pos.y < footer_top {
|
if mouse_pos.y < footer_top && mouse_pos.y > HEADER_HEIGHT as f32 {
|
||||||
let tile_pos = (mouse_pos - self.view_offset) / (16 << self.zoom) as f32;
|
let tile_pos = (mouse_pos - self.view_offset) / (16 << self.zoom) as f32;
|
||||||
let tile_pos = Vector2::new(tile_pos.x.floor(), tile_pos.y.floor());
|
let tile_pos = Vector2::new(tile_pos.x.floor(), tile_pos.y.floor());
|
||||||
|
|
||||||
|
|
10
src/level.rs
10
src/level.rs
|
@ -2,7 +2,7 @@ use serde::Deserialize;
|
||||||
|
|
||||||
use crate::marble_engine::board::Board;
|
use crate::marble_engine::board::Board;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct Level {
|
pub struct Level {
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -36,8 +36,12 @@ impl Level {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_board(&self) -> Option<Board> {
|
// pub fn init_board(&self) -> Option<Board> {
|
||||||
self.init_board.as_deref().map(Board::parse)
|
// self.init_board.as_deref().map(Board::parse)
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn init_board(&self)->Option<String>{
|
||||||
|
self.init_board.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inputs(&self) -> &[u8] {
|
pub fn inputs(&self) -> &[u8] {
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -11,7 +11,7 @@ mod marble_engine;
|
||||||
mod solution;
|
mod solution;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
use editor::Editor;
|
use editor::{Editor, ExitState};
|
||||||
use level::Level;
|
use level::Level;
|
||||||
use marble_engine::board::Board;
|
use marble_engine::board::Board;
|
||||||
use solution::Solution;
|
use solution::Solution;
|
||||||
|
@ -67,6 +67,16 @@ impl Game {
|
||||||
if let Some(editor) = &mut self.open_editor {
|
if let Some(editor) = &mut self.open_editor {
|
||||||
editor.input(&d);
|
editor.input(&d);
|
||||||
editor.draw(&mut d, &self.textures);
|
editor.draw(&mut d, &self.textures);
|
||||||
|
match editor.get_exit_state() {
|
||||||
|
ExitState::Dont => (),
|
||||||
|
ExitState::ExitNoSave => self.open_editor = None,
|
||||||
|
ExitState::ExitAndSave => {
|
||||||
|
self.solutions.get_mut(editor.level_id()).unwrap()
|
||||||
|
[self.selected_solution]
|
||||||
|
.board = editor.source_board().to_string();
|
||||||
|
self.open_editor = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.draw(&mut d);
|
self.draw(&mut d);
|
||||||
}
|
}
|
||||||
|
@ -165,7 +175,7 @@ impl Game {
|
||||||
|
|
||||||
if simple_button(d, level_list_width + 10, y, solution_entry_width, 30) {
|
if simple_button(d, level_list_width + 10, y, solution_entry_width, 30) {
|
||||||
let n = solutions.len();
|
let n = solutions.len();
|
||||||
solutions.push(Solution::new(level.id().to_owned(), n));
|
solutions.push(Solution::new(&level, n));
|
||||||
}
|
}
|
||||||
d.draw_text(
|
d.draw_text(
|
||||||
"new solution",
|
"new solution",
|
||||||
|
@ -179,7 +189,7 @@ impl Game {
|
||||||
let bounds = Rectangle {
|
let bounds = Rectangle {
|
||||||
x: (level_list_width + 10 + solution_entry_width + 10) as f32,
|
x: (level_list_width + 10 + solution_entry_width + 10) as f32,
|
||||||
y: 60.,
|
y: 60.,
|
||||||
width: 240.,
|
width: 220.,
|
||||||
height: 30.,
|
height: 30.,
|
||||||
};
|
};
|
||||||
text_input(
|
text_input(
|
||||||
|
@ -188,6 +198,12 @@ impl Game {
|
||||||
&mut solution.name,
|
&mut solution.name,
|
||||||
&mut self.editing_solution_name,
|
&mut self.editing_solution_name,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let button_x = level_list_width + solution_entry_width + 20;
|
||||||
|
if simple_button(d, button_x, 100, 220, 30) {
|
||||||
|
self.open_editor = Some(Editor::new(solution.clone(), level.clone()));
|
||||||
|
}
|
||||||
|
d.draw_text("edit", button_x + 5, 105, 20, Color::WHITE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.solutions.insert(level.id().to_owned(), Vec::new());
|
self.solutions.insert(level.id().to_owned(), Vec::new());
|
||||||
|
|
|
@ -63,6 +63,17 @@ impl Board {
|
||||||
Board::new(rows)
|
Board::new(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self)->String{
|
||||||
|
let mut out = String::new();
|
||||||
|
for row in &self.rows{
|
||||||
|
for tile in row{
|
||||||
|
out.push(tile.to_char())
|
||||||
|
}
|
||||||
|
out.push('\n');
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_empty(width: usize, height: usize) -> Self {
|
pub fn new_empty(width: usize, height: usize) -> Self {
|
||||||
let rows = vec![vec![Tile::Blank; width]; height];
|
let rows = vec![vec![Tile::Blank; width]; height];
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -104,6 +104,50 @@ impl Tile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_char(self) -> char {
|
||||||
|
match self {
|
||||||
|
Tile::Blank => ' ',
|
||||||
|
Tile::Block => '#',
|
||||||
|
Tile::Marble { value: _, dir: _ } => 'o',
|
||||||
|
Tile::Digit(n) => (b'0' + n) as char,
|
||||||
|
Tile::Mirror(dir) => match dir {
|
||||||
|
MirrorType::Forward => '/',
|
||||||
|
MirrorType::Back => '\\',
|
||||||
|
},
|
||||||
|
Tile::Arrow(dir) => match dir {
|
||||||
|
Direction::Up => '^',
|
||||||
|
Direction::Down => 'v',
|
||||||
|
Direction::Left => '<',
|
||||||
|
Direction::Right => '>',
|
||||||
|
},
|
||||||
|
Tile::Powerable(tile, _) => match tile {
|
||||||
|
PTile::Trigger => '*',
|
||||||
|
PTile::Wire(wire) => match wire {
|
||||||
|
WireType::Vertical => '|',
|
||||||
|
WireType::Horizontal => '-',
|
||||||
|
WireType::Cross => '+',
|
||||||
|
},
|
||||||
|
PTile::Gate(gate) => match gate {
|
||||||
|
GateType::LessThan => 'L',
|
||||||
|
GateType::GreaterThan => 'G',
|
||||||
|
GateType::Equal => '=',
|
||||||
|
GateType::NotEqual => '!',
|
||||||
|
},
|
||||||
|
PTile::Math(math) => match math {
|
||||||
|
MathOp::Add => 'A',
|
||||||
|
MathOp::Sub => 'S',
|
||||||
|
MathOp::Mul => 'M',
|
||||||
|
MathOp::Div => 'D',
|
||||||
|
MathOp::Rem => 'R',
|
||||||
|
},
|
||||||
|
PTile::Bag => 'B',
|
||||||
|
PTile::Flipper => 'F',
|
||||||
|
PTile::Input => 'I',
|
||||||
|
PTile::Output => 'P',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_blank(&self) -> bool {
|
pub fn is_blank(&self) -> bool {
|
||||||
matches!(self, Tile::Blank)
|
matches!(self, Tile::Blank)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
use crate::level::Level;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Solution {
|
pub struct Solution {
|
||||||
solution_id: String,
|
// solution_id: String,
|
||||||
level_id: String, // redundant?
|
level_id: String, // redundant?
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub board: String,
|
pub board: String,
|
||||||
pub score: Option<Score>,
|
pub score: Option<Score>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Score {
|
pub struct Score {
|
||||||
pub cycles: u32,
|
pub cycles: u32,
|
||||||
pub tiles: u32,
|
pub tiles: u32,
|
||||||
|
@ -17,16 +19,23 @@ pub struct Score {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Solution {
|
impl Solution {
|
||||||
pub fn new(level_id: String, number: usize) -> Self {
|
pub fn new(level: &Level, number: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
solution_id: format!("solution_{number}"),
|
// solution_id: format!("solution_{number}"),
|
||||||
level_id,
|
level_id: level.id().to_owned(),
|
||||||
name: format!("Unnamed {number}"),
|
name: format!("Unnamed {number}"),
|
||||||
board: " \n".repeat(20), // todo remove when auto resizing is implemented
|
board: level
|
||||||
|
.init_board()
|
||||||
|
.unwrap_or_else(|| " \n".repeat(20)), // todo remove when auto resizing is implemented
|
||||||
// score: Some(Score { cycles: 5, tiles: 88, area: 987 }),
|
// score: Some(Score { cycles: 5, tiles: 88, area: 987 }),
|
||||||
score: None,
|
score: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn level_id(&self) -> &str {
|
||||||
|
&self.level_id
|
||||||
|
}
|
||||||
|
|
||||||
pub fn score_text(&self) -> String {
|
pub fn score_text(&self) -> String {
|
||||||
if let Some(score) = &self.score {
|
if let Some(score) = &self.score {
|
||||||
format!(
|
format!(
|
||||||
|
|
|
@ -122,7 +122,7 @@ pub fn text_input(
|
||||||
if d.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
|
if d.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
|
||||||
*is_selected = false;
|
*is_selected = false;
|
||||||
}
|
}
|
||||||
if d.is_key_pressed(KeyboardKey::KEY_BACKSPACE) {
|
if d.is_key_pressed(KeyboardKey::KEY_BACKSPACE) && !text.is_empty() {
|
||||||
changed = true;
|
changed = true;
|
||||||
text.pop();
|
text.pop();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue