undo/redo - 50%
This commit is contained in:
parent
0ddb8bdba4
commit
92e3b9f620
7 changed files with 197 additions and 8 deletions
123
src/undo.rs
Normal file
123
src/undo.rs
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue