Artboard history (#976)

* Convert DocumentSave to struct

* Comit the artboard history save in some cases

* Cause index out of bounds error

* Use box to avoid weird wasm error

* Implement the artboard history

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube 2023-01-22 19:51:08 +00:00 committed by Keavon Chambers
parent d2219cec36
commit 5cbe3f7573
5 changed files with 41 additions and 24 deletions

View File

@ -12,7 +12,7 @@ use document_legacy::Operation as DocumentOperation;
use glam::DAffine2;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct ArtboardMessageHandler {
pub artboards_document: DocumentLegacy,
pub artboard_ids: Vec<LayerId>,

View File

@ -49,6 +49,7 @@ pub enum DocumentMessage {
},
BackupDocument {
document: DocumentLegacy,
artboard: Box<ArtboardMessageHandler>,
layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
},
BooleanOperation(BooleanOperationType),

View File

@ -247,7 +247,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
responses.push_back(BroadcastEvent::DocumentIsDirty.into());
}
}
BackupDocument { document, layer_metadata } => self.backup_with_document(document, layer_metadata, responses),
BackupDocument { document, artboard, layer_metadata } => self.backup_with_document(document, *artboard, layer_metadata, responses),
BooleanOperation(op) => {
// Convert Vec<&[LayerId]> to Vec<Vec<&LayerId>> because Vec<&[LayerId]> does not implement several traits (Debug, Serialize, Deserialize, ...) required by DocumentOperation enum
responses.push_back(StartTransaction.into());
@ -1288,9 +1288,9 @@ impl DocumentMessageHandler {
}
/// Places a document into the history system
fn backup_with_document(&mut self, document: DocumentLegacy, layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>, responses: &mut VecDeque<Message>) {
fn backup_with_document(&mut self, document: DocumentLegacy, artboard: ArtboardMessageHandler, layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>, responses: &mut VecDeque<Message>) {
self.document_redo_history.clear();
self.document_undo_history.push_back((document, layer_metadata));
self.document_undo_history.push_back(DocumentSave { document, artboard, layer_metadata });
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
@ -1301,7 +1301,7 @@ impl DocumentMessageHandler {
/// Copies the entire document into the history system
pub fn backup(&mut self, responses: &mut VecDeque<Message>) {
self.backup_with_document(self.document_legacy.clone(), self.layer_metadata.clone(), responses);
self.backup_with_document(self.document_legacy.clone(), self.artboard_message_handler.clone(), self.layer_metadata.clone(), responses);
}
/// Push a message backing up the document in its current state
@ -1309,6 +1309,7 @@ impl DocumentMessageHandler {
responses.push_back(
DocumentMessage::BackupDocument {
document: self.document_legacy.clone(),
artboard: Box::new(self.artboard_message_handler.clone()),
layer_metadata: self.layer_metadata.clone(),
}
.into(),
@ -1321,6 +1322,23 @@ impl DocumentMessageHandler {
// TODO: Consider if we should check if the document is saved
}
/// Replace the document with a new document save, returning the document save.
pub fn replace_document(&mut self, DocumentSave { document, artboard, layer_metadata }: DocumentSave) -> DocumentSave {
// Keeping the root is required if the bounds of the viewport have changed during the operation
let old_root = self.document_legacy.root.transform;
let old_artboard_root = self.artboard_message_handler.artboards_document.root.transform;
let document = std::mem::replace(&mut self.document_legacy, document);
let artboard = std::mem::replace(&mut self.artboard_message_handler, artboard);
self.document_legacy.root.transform = old_root;
self.artboard_message_handler.artboards_document.root.transform = old_artboard_root;
self.document_legacy.root.cache_dirty = true;
self.artboard_message_handler.artboards_document.root.cache_dirty = true;
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
DocumentSave { document, artboard, layer_metadata }
}
pub fn undo(&mut self, responses: &mut VecDeque<Message>) -> Result<(), EditorError> {
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
responses.push_back(PortfolioMessage::UpdateOpenDocumentsList.into());
@ -1328,7 +1346,7 @@ impl DocumentMessageHandler {
let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();
match self.document_undo_history.pop_back() {
Some((document, layer_metadata)) => {
Some(DocumentSave { document, artboard, layer_metadata }) => {
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
// Also appropriately update the Properties panel if an undo action results in a layer being deleted
let prev_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();
@ -1337,14 +1355,9 @@ impl DocumentMessageHandler {
responses.push_back(BroadcastEvent::SelectionChanged.into());
}
// Keeping the root is required if the bounds of the viewport have changed during the operation
let old_root = self.document_legacy.root.transform;
let document = std::mem::replace(&mut self.document_legacy, document);
self.document_legacy.root.transform = old_root;
self.document_legacy.root.cache_dirty = true;
let document_save = self.replace_document(DocumentSave { document, artboard, layer_metadata });
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
self.document_redo_history.push_back((document, layer_metadata));
self.document_redo_history.push_back(document_save);
if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_redo_history.pop_front();
}
@ -1368,7 +1381,7 @@ impl DocumentMessageHandler {
let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();
match self.document_redo_history.pop_back() {
Some((document, layer_metadata)) => {
Some(DocumentSave { document, artboard, layer_metadata }) => {
// Update currently displayed layer on property panel if selection changes after redo action
// Also appropriately update property panel if redo action results in a layer being added
let next_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();
@ -1377,14 +1390,8 @@ impl DocumentMessageHandler {
responses.push_back(BroadcastEvent::SelectionChanged.into());
}
// Keeping the root is required if the bounds of the viewport have changed during the operation
let old_root = self.document_legacy.root.transform;
let document = std::mem::replace(&mut self.document_legacy, document);
self.document_legacy.root.transform = old_root;
self.document_legacy.root.cache_dirty = true;
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
self.document_undo_history.push_back((document, layer_metadata));
let document_save = self.replace_document(DocumentSave { document, artboard, layer_metadata });
self.document_undo_history.push_back(document_save);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
@ -1407,7 +1414,7 @@ impl DocumentMessageHandler {
self.document_undo_history
.iter()
.last()
.map(|(document_legacy, _)| document_legacy.current_state_identifier())
.map(|DocumentSave { document, .. }| document.current_state_identifier())
.unwrap_or(0)
}

View File

@ -1,4 +1,5 @@
pub use super::layer_panel::{LayerMetadata, LayerPanelEntry};
use crate::messages::prelude::ArtboardMessageHandler;
use document_legacy::color::Color;
use document_legacy::document::Document as DocumentLegacy;
@ -8,7 +9,12 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
pub type DocumentSave = (DocumentLegacy, HashMap<Vec<LayerId>, LayerMetadata>);
#[derive(Debug, Clone)]
pub struct DocumentSave {
pub document: DocumentLegacy,
pub artboard: ArtboardMessageHandler,
pub layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
}
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, Hash)]
pub enum FlipAxis {

View File

@ -190,6 +190,8 @@ impl Fsm for ArtboardToolFsmState {
};
if let Some(selected_edges) = dragging_bounds {
responses.push_back(DocumentMessage::StartTransaction.into());
let snap_x = selected_edges.2 || selected_edges.3;
let snap_y = selected_edges.0 || selected_edges.1;
@ -206,6 +208,7 @@ impl Fsm for ArtboardToolFsmState {
ArtboardToolFsmState::ResizingBounds
} else {
responses.push_back(DocumentMessage::StartTransaction.into());
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
let intersection = document.artboard_message_handler.artboards_document.intersects_quad_root(quad, font_cache);