84 lines
2.6 KiB
Rust
84 lines
2.6 KiB
Rust
use crate::canvas::Canvas;
|
|
|
|
#[derive(Clone, druid::Data)]
|
|
pub struct VersionedCanvas {
|
|
// We internally guarantee that this vector
|
|
// is never empty
|
|
versions: im::Vector<Canvas>,
|
|
curr_version: usize,
|
|
}
|
|
|
|
impl VersionedCanvas {
|
|
pub fn new(canvas: Canvas) -> VersionedCanvas {
|
|
VersionedCanvas {
|
|
versions: im::vector![canvas],
|
|
curr_version: 0,
|
|
}
|
|
}
|
|
|
|
// Get current canvas version
|
|
pub fn get(&self) -> &Canvas {
|
|
self.versions.get(self.curr_version).unwrap()
|
|
}
|
|
|
|
fn has_newer_versions(&self) -> bool {
|
|
self.curr_version + 1 < self.versions.len()
|
|
}
|
|
|
|
fn has_older_versions(&self) -> bool {
|
|
self.curr_version > 0
|
|
}
|
|
|
|
pub fn version(&self) -> usize {
|
|
self.curr_version
|
|
}
|
|
|
|
pub fn undo(&mut self) {
|
|
if self.has_older_versions() {
|
|
self.curr_version = self.curr_version - 1;
|
|
}
|
|
}
|
|
|
|
pub fn redo(&mut self) {
|
|
if self.has_newer_versions() {
|
|
self.curr_version = self.curr_version + 1;
|
|
}
|
|
}
|
|
|
|
// TODO: Right now the update function internally checks
|
|
// whether the canvas has been changed by leveraging the
|
|
// Copy on Write semantics of im::Vector.
|
|
// Is this a good solution? Does this work correctly? THINK ABOUT THIS
|
|
pub fn update(&mut self, update_fn: impl FnOnce(&mut Canvas)) {
|
|
// This is a linear history,
|
|
// so we first check if there are newer versions, if so
|
|
// this means we are in the past, so a change in the past destroys the future
|
|
// and creates a new future.
|
|
if self.has_newer_versions() {
|
|
self.versions = self.versions.take(self.curr_version + 1);
|
|
}
|
|
|
|
let mut new_version = self.get().clone();
|
|
update_fn(&mut new_version);
|
|
|
|
// Only push new version if there has been an actual change in the vector
|
|
if !new_version.elements.ptr_eq(&self.get().elements) {
|
|
self.versions.push_back(new_version);
|
|
self.curr_version = self.curr_version + 1;
|
|
}
|
|
}
|
|
|
|
// Do inplace update, which will be irreversible
|
|
pub fn irreversible_update(&mut self, update_fn: impl FnOnce(&mut Canvas)) {
|
|
// This is a linear history,
|
|
// so we first check if there are newer versions, if so
|
|
// this means we are in the past, so a change in the past destroys the future
|
|
// and creates a new future.
|
|
if self.has_newer_versions() {
|
|
self.versions = self.versions.take(self.curr_version + 1);
|
|
}
|
|
|
|
update_fn(self.versions.back_mut().unwrap());
|
|
}
|
|
}
|