stiletto/src/versioned_canvas.rs

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());
}
}