add undo/redo for pasting/area operations
This commit is contained in:
parent
5b6113780a
commit
6970b18e22
2 changed files with 73 additions and 97 deletions
131
src/editor.rs
131
src/editor.rs
|
@ -181,11 +181,16 @@ impl Editor {
|
|||
|
||||
fn do_action(&mut self, action: Action) {
|
||||
match action {
|
||||
Action::SetTile(resize_delta, pos, _old, new) => {
|
||||
self.resize_board(resize_delta);
|
||||
Action::SetTile(deltas, pos, _old, new) => {
|
||||
self.shift_view(deltas.x_neg as f32, deltas.y_neg as f32);
|
||||
self.source_board.grow(&deltas);
|
||||
self.source_board.set(pos, new);
|
||||
}
|
||||
Action::SetArea(_, _, _, _) => todo!(),
|
||||
Action::SetArea(deltas, pos, _old, new) => {
|
||||
self.shift_view(deltas.x_neg as f32, deltas.y_neg as f32);
|
||||
self.source_board.grow(&deltas);
|
||||
self.source_board.paste_board(pos, &new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,26 +201,39 @@ impl Editor {
|
|||
self.undo_index -= 1;
|
||||
let action = self.undo_history[self.undo_index].clone();
|
||||
match action {
|
||||
Action::SetTile(resize_delta, pos, old, _new) => {
|
||||
Action::SetTile(deltas, pos, old, _new) => {
|
||||
self.source_board.set(pos, old);
|
||||
self.undo_resize_board(resize_delta);
|
||||
self.source_board.shrink(&deltas);
|
||||
self.shift_view(-(deltas.x_neg as f32), -(deltas.y_neg as f32));
|
||||
}
|
||||
Action::SetArea(deltas, pos, old, _new) => {
|
||||
self.source_board.paste_board(pos, &old);
|
||||
self.source_board.shrink(&deltas);
|
||||
self.shift_view(-(deltas.x_neg as f32), -(deltas.y_neg as f32));
|
||||
}
|
||||
Action::SetArea(_, _, _, _) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resize_board(&mut self, deltas: ResizeDeltas) {
|
||||
self.source_board.grow(&deltas);
|
||||
fn shift_view(&mut self, x: f32, y: f32) {
|
||||
match &mut self.active_tool {
|
||||
Tool::SelectArea(Selection {
|
||||
area: Some((a, b)),
|
||||
is_selecting: _,
|
||||
}) => {
|
||||
a.x += x as PosInt;
|
||||
a.y += y as PosInt;
|
||||
b.x += x as PosInt;
|
||||
b.y += y as PosInt;
|
||||
}
|
||||
Tool::Digits(Some(pos)) => {
|
||||
pos.x += x as PosInt;
|
||||
pos.y += y as PosInt;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
let tile_size = TILE_TEXTURE_SIZE * self.zoom;
|
||||
self.view_offset.x -= deltas.x_neg as f32 * tile_size;
|
||||
self.view_offset.y -= deltas.y_neg as f32 * tile_size;
|
||||
}
|
||||
|
||||
fn undo_resize_board(&mut self, deltas: ResizeDeltas) {
|
||||
self.source_board.shrink(&deltas);
|
||||
let tile_size = TILE_TEXTURE_SIZE * self.zoom;
|
||||
self.view_offset.x += deltas.x_neg as f32 * tile_size;
|
||||
self.view_offset.y += deltas.y_neg as f32 * tile_size;
|
||||
self.view_offset.x -= x * tile_size;
|
||||
self.view_offset.y -= y * tile_size;
|
||||
}
|
||||
|
||||
pub fn get_exit_state(&self) -> ExitState {
|
||||
|
@ -356,31 +374,39 @@ impl Editor {
|
|||
self.active_tool = Tool::Blueprint;
|
||||
}
|
||||
|
||||
fn grow_board_and_update_view(&mut self, pos: &mut Pos) {
|
||||
let tile_size = TILE_TEXTURE_SIZE * self.zoom;
|
||||
let (x, y) = self.source_board.grow_to_include(*pos);
|
||||
if x != 0 || y != 0 {
|
||||
self.view_offset.x -= x as f32 * tile_size;
|
||||
self.view_offset.y -= y as f32 * tile_size;
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
match &mut self.active_tool {
|
||||
Tool::Digits(Some(pos)) => {
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
}
|
||||
Tool::SelectArea(Selection {
|
||||
area: Some((start, end)),
|
||||
is_selecting: _,
|
||||
}) => {
|
||||
start.x += x;
|
||||
start.y += y;
|
||||
end.x += x;
|
||||
end.y += y;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
fn set_area(&mut self, pos: Pos, area: Board) {
|
||||
let old_area = self.source_board.get_rect(pos, area.width(), area.height());
|
||||
if area == old_area {
|
||||
return;
|
||||
}
|
||||
let width = self.source_board.width() as PosInt;
|
||||
let height = self.source_board.height() as PosInt;
|
||||
let resize = ResizeDeltas {
|
||||
x_pos: if (pos.x + BOARD_MARGIN + area.width() as PosInt) > width {
|
||||
pos.x + BOARD_MARGIN + area.width() as PosInt - width
|
||||
} else {
|
||||
0
|
||||
} as usize,
|
||||
x_neg: if pos.x < BOARD_MARGIN {
|
||||
BOARD_MARGIN - pos.x
|
||||
} else {
|
||||
0
|
||||
} as usize,
|
||||
y_pos: if (pos.y + BOARD_MARGIN + area.height() as PosInt) > height {
|
||||
pos.y + BOARD_MARGIN + area.height() as PosInt - height
|
||||
} else {
|
||||
0
|
||||
} as usize,
|
||||
y_neg: if pos.y < BOARD_MARGIN {
|
||||
BOARD_MARGIN - pos.y
|
||||
} else {
|
||||
0
|
||||
} as usize,
|
||||
};
|
||||
let mut pos = pos;
|
||||
pos.x += resize.x_neg as PosInt;
|
||||
pos.y += resize.y_neg as PosInt;
|
||||
self.push_action(Action::SetArea(resize, pos, old_area, area));
|
||||
}
|
||||
|
||||
fn set_tile(&mut self, pos: Pos, tile: Tile) {
|
||||
|
@ -825,11 +851,9 @@ impl Editor {
|
|||
if simple_button(d, 232, y, 40, 40) {
|
||||
let min = selection.0.min(selection.1);
|
||||
let max = selection.0.max(selection.1);
|
||||
for x in min.x..=max.x {
|
||||
for y in min.y..=max.y {
|
||||
self.source_board.set(Pos { x, y }, Tile::BLANK);
|
||||
}
|
||||
}
|
||||
let board =
|
||||
Board::new_empty((max.x - min.x) as usize + 1, (max.y - min.y) as usize + 1);
|
||||
self.set_area(min, board);
|
||||
}
|
||||
draw_scaled_texture(d, textures.get("eraser"), 236, y + 4, 2.);
|
||||
}
|
||||
|
@ -1003,14 +1027,8 @@ impl Editor {
|
|||
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 mut pos = tile_pos.into();
|
||||
|
||||
let board = self.pasting_board.take().unwrap();
|
||||
self.grow_board_and_update_view(&mut pos);
|
||||
self.grow_board_and_update_view(
|
||||
&mut (pos + (board.width() - 1, board.height() - 1).into()),
|
||||
);
|
||||
self.source_board.paste_board(pos, &board);
|
||||
self.set_area(tile_pos.into(), board);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -1106,12 +1124,7 @@ impl Editor {
|
|||
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();
|
||||
let mut pos = pos;
|
||||
self.grow_board_and_update_view(&mut pos);
|
||||
self.grow_board_and_update_view(
|
||||
&mut (pos + (board.width() - 1, board.height() - 1).into()),
|
||||
);
|
||||
self.source_board.paste_board(pos, &board);
|
||||
self.set_area(pos, board);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use super::Pos;
|
|||
use super::PosInt;
|
||||
use raylib::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Board {
|
||||
rows: Vec<Vec<Tile>>,
|
||||
width: usize,
|
||||
|
@ -140,41 +140,6 @@ impl Board {
|
|||
out
|
||||
}
|
||||
|
||||
pub fn grow_to_include(&mut self, p: Pos) -> (PosInt, PosInt) {
|
||||
let mut offset_x = 0;
|
||||
let mut offset_y = 0;
|
||||
if p.x < 0 {
|
||||
let len = p.x.unsigned_abs() as usize;
|
||||
for row in &mut self.rows {
|
||||
let mut new_row = vec![Tile::BLANK; len];
|
||||
new_row.append(row);
|
||||
*row = new_row;
|
||||
}
|
||||
offset_x = len;
|
||||
self.width += len;
|
||||
} else if p.x as usize >= self.width {
|
||||
let new_width = p.x as usize + 1;
|
||||
for row in &mut self.rows {
|
||||
row.resize(new_width, Tile::BLANK);
|
||||
}
|
||||
self.width = new_width;
|
||||
}
|
||||
|
||||
if p.y < 0 {
|
||||
let len = p.y.unsigned_abs() as usize;
|
||||
let mut new_rows = vec![vec![Tile::BLANK; self.width]; len];
|
||||
new_rows.append(&mut self.rows);
|
||||
self.rows = new_rows;
|
||||
offset_y = len;
|
||||
self.height += len;
|
||||
} else if p.y as usize >= self.height {
|
||||
let new_height = p.y as usize + 1;
|
||||
self.rows.resize(new_height, vec![Tile::BLANK; self.width]);
|
||||
self.height = new_height;
|
||||
}
|
||||
(offset_x as PosInt, offset_y as PosInt)
|
||||
}
|
||||
|
||||
pub fn trim_size(&mut self, margin: usize) -> (usize, usize) {
|
||||
let (offset_x, offset_y);
|
||||
// top
|
||||
|
@ -235,7 +200,6 @@ impl Board {
|
|||
}
|
||||
|
||||
pub fn grow(&mut self, deltas: &ResizeDeltas) {
|
||||
// dbg!(&deltas);
|
||||
let new_width = self.width + deltas.x_neg + deltas.x_pos;
|
||||
let new_height = self.height + deltas.y_neg + deltas.y_pos;
|
||||
let mut new_board = Board::new_empty(new_width, new_height);
|
||||
|
@ -249,7 +213,6 @@ impl Board {
|
|||
}
|
||||
|
||||
pub fn shrink(&mut self, deltas: &ResizeDeltas) {
|
||||
// dbg!(&deltas);
|
||||
let new_width = self.width - deltas.x_neg - deltas.x_pos;
|
||||
let new_height = self.height - deltas.y_neg - deltas.y_pos;
|
||||
let mut new_board = Board::new_empty(new_width, new_height);
|
||||
|
|
Loading…
Reference in a new issue