undo/redo - 50%

This commit is contained in:
RustyStriker 2022-09-05 19:42:40 +03:00
parent 0ddb8bdba4
commit 92e3b9f620
7 changed files with 197 additions and 8 deletions

123
src/undo.rs Normal file
View file

@ -0,0 +1,123 @@
use bevy::prelude::*;
use crate::{CreateShape, ShapeData};
#[derive(Debug, Clone)]
pub enum UndoItem {
Base,
CreateShape { entity: Entity },
MoveDot { shape_data: Entity, dot: Entity, from: Vec2, to: Vec2 },
MoveShape { shape: Entity, from: Vec2, to: Vec2 },
Rotate { entity: Entity, from: f32, to: f32 },
NameChange { entity: Entity, from: String },
DeleteShape { name: String, shape: CreateShape, edges: Vec<Vec2>, transform: Transform, color: Color, note: String },
}
pub struct UndoStack {
items: Vec<UndoItem>,
current_action: usize,
last_valid: usize,
}
impl Default for UndoStack {
fn default() -> Self {
Self { items: [UndoItem::Base].to_vec(), current_action: 0, last_valid: 0 }
}
}
impl UndoStack {
pub fn push(&mut self, item: UndoItem) {
bevy::log::info!("PUSHING: {:?}", item);
if self.current_action < self.items.len() - 1 {
// We need to do a "semi push"
self.current_action += 1;
self.items[self.current_action] = item;
}
else {
// We push a completly new item and might need more space!
self.items.push(item);
self.current_action = self.items.len() - 1;
}
self.last_valid = self.current_action;
}
/// Pop the last item in the stack
pub fn pop(&mut self) -> Option<&mut UndoItem> {
// If this happens we are clearly into invalid territory
assert!(self.current_action < self.items.len());
if self.current_action > 0 {
let item = &mut self.items[self.current_action];
self.current_action -= 1;
Some(item)
}
else {
None
}
}
// If exists, "unpops" the last popped item
pub fn unpop(&mut self) -> Option<&mut UndoItem> {
if self.current_action < self.last_valid {
self.current_action += 1;
let item = &mut self.items[self.current_action];
Some(item)
}
else {
None
}
}
}
pub fn undo_redo_sys(
mut coms: Commands,
mut stack: ResMut<UndoStack>,
keyboard: Res<Input<KeyCode>>,
mut shapes: Query<&mut ShapeData>,
mut transforms: Query<&mut Transform>,
) {
if keyboard.just_pressed(KeyCode::Z) && keyboard.pressed(KeyCode::LControl) {
let item = if keyboard.pressed(KeyCode::LShift) { stack.unpop() } else { stack.pop() };
if let Some(item) = item {
match item {
UndoItem::Base => bevy::log::error!("POP/UNPOP: Got UndoItem::Base as a result!"),
UndoItem::CreateShape { entity } => {
bevy::log::error!("NOT IMPLEMENTED : CreateShape");
},
UndoItem::MoveDot { shape_data, dot, from, to } => {
bevy::log::error!("NOT IMPLEMENTED : MoveDot");
},
UndoItem::MoveShape { shape, from, to } => {
if let Ok(mut t) = transforms.get_mut(*shape) {
t.translation = from.extend(t.translation.z);
}
let t = *from;
*from = *to;
*to = t;
},
UndoItem::Rotate { entity, from, to } => {
if let Ok(mut t) = transforms.get_mut(*entity) {
t.rotation = Quat::from_rotation_z(from.to_radians());
}
let t = *from;
*from = *to;
*to = t;
},
UndoItem::NameChange { entity, from } => {
if let Ok(mut sd) = shapes.get_mut(*entity) {
std::mem::swap(&mut sd.name, from);
}
// No need to update the item, so no need to replace
},
UndoItem::DeleteShape {
name,
shape,
edges,
transform,
color,
note
} => {
bevy::log::error!("NOT IMPLEMENTED : DeleteShape");
},
}
}
else {
bevy::log::info!("Nothing to pop/unpop!");
}
}
}