id-based-docs (#376)
* Added some notes on what ds to use for the documents. * Added a separate list of ids to associate ID to doc. Looks up all documents by id to retrieve an index via linear search. * Fixed function name. * Removed id recycling, replaced document vector with hashmap. * Uses the same logic for PrevDocument in closing
This commit is contained in:
parent
52f597234c
commit
5641f5d822
|
|
@ -3,9 +3,8 @@ use crate::message_prelude::*;
|
||||||
use graphene::layers::Layer;
|
use graphene::layers::Layer;
|
||||||
use graphene::{LayerId, Operation as DocumentOperation};
|
use graphene::{LayerId, Operation as DocumentOperation};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::VecDeque;
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
use super::DocumentMessageHandler;
|
use super::DocumentMessageHandler;
|
||||||
use crate::consts::DEFAULT_DOCUMENT_NAME;
|
use crate::consts::DEFAULT_DOCUMENT_NAME;
|
||||||
|
|
@ -36,28 +35,37 @@ pub enum DocumentsMessage {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DocumentsMessageHandler {
|
pub struct DocumentsMessageHandler {
|
||||||
documents: Vec<DocumentMessageHandler>,
|
documents: HashMap<u64, DocumentMessageHandler>,
|
||||||
|
document_ids: Vec<u64>,
|
||||||
|
document_id_counter: u64,
|
||||||
active_document_index: usize,
|
active_document_index: usize,
|
||||||
copy_buffer: Vec<Layer>,
|
copy_buffer: Vec<Layer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentsMessageHandler {
|
impl DocumentsMessageHandler {
|
||||||
pub fn active_document(&self) -> &DocumentMessageHandler {
|
pub fn active_document(&self) -> &DocumentMessageHandler {
|
||||||
&self.documents[self.active_document_index]
|
let id = self.document_ids[self.active_document_index];
|
||||||
|
self.documents.get(&id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_document_mut(&mut self) -> &mut DocumentMessageHandler {
|
pub fn active_document_mut(&mut self) -> &mut DocumentMessageHandler {
|
||||||
&mut self.documents[self.active_document_index]
|
let id = self.document_ids[self.active_document_index];
|
||||||
|
self.documents.get_mut(&id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_new_document_name(&self) -> String {
|
fn generate_new_document_name(&self) -> String {
|
||||||
let mut doc_title_numbers = self
|
let mut doc_title_numbers = self
|
||||||
.documents
|
.document_ids
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|d| {
|
.filter_map(|id| self.documents.get(&id))
|
||||||
d.name
|
.map(|doc| {
|
||||||
|
doc.name
|
||||||
.rsplit_once(DEFAULT_DOCUMENT_NAME)
|
.rsplit_once(DEFAULT_DOCUMENT_NAME)
|
||||||
.map(|(prefix, number)| (prefix.is_empty()).then(|| number.trim().parse::<isize>().ok()).flatten().unwrap_or(1))
|
.map(|(prefix, number)| (prefix.is_empty()).then(|| number.trim().parse::<isize>().ok()).flatten().unwrap_or(1))
|
||||||
|
.unwrap()
|
||||||
})
|
})
|
||||||
.collect::<Vec<isize>>();
|
.collect::<Vec<isize>>();
|
||||||
|
|
||||||
doc_title_numbers.sort_unstable();
|
doc_title_numbers.sort_unstable();
|
||||||
doc_title_numbers.iter_mut().enumerate().for_each(|(i, number)| *number = *number - i as isize - 2);
|
doc_title_numbers.iter_mut().enumerate().for_each(|(i, number)| *number = *number - i as isize - 2);
|
||||||
// Uses binary search to find the index of the element where number is bigger than i
|
// Uses binary search to find the index of the element where number is bigger than i
|
||||||
|
|
@ -71,11 +79,14 @@ impl DocumentsMessageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_document(&mut self, new_document: DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
fn load_document(&mut self, new_document: DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||||
self.active_document_index = self.documents.len();
|
self.document_id_counter += 1;
|
||||||
self.documents.push(new_document);
|
self.active_document_index = self.document_ids.len();
|
||||||
|
self.document_ids.push(self.document_id_counter);
|
||||||
|
self.documents.insert(self.document_id_counter, new_document);
|
||||||
|
|
||||||
// Send the new list of document tab names
|
// Send the new list of document tab names
|
||||||
let open_documents = self.documents.iter().map(|doc| doc.name.clone()).collect();
|
let open_documents = self.document_ids.iter().filter_map(|id| self.documents.get(&id).map(|doc| doc.name.clone())).collect::<Vec<String>>();
|
||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
||||||
|
|
||||||
responses.push_back(DocumentsMessage::SelectDocument(self.active_document_index).into());
|
responses.push_back(DocumentsMessage::SelectDocument(self.active_document_index).into());
|
||||||
|
|
@ -89,10 +100,14 @@ impl DocumentsMessageHandler {
|
||||||
|
|
||||||
impl Default for DocumentsMessageHandler {
|
impl Default for DocumentsMessageHandler {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut documents_map: HashMap<u64, DocumentMessageHandler> = HashMap::with_capacity(1);
|
||||||
|
documents_map.insert(0, DocumentMessageHandler::default());
|
||||||
Self {
|
Self {
|
||||||
documents: vec![DocumentMessageHandler::default()],
|
documents: documents_map,
|
||||||
active_document_index: 0,
|
document_ids: vec![0],
|
||||||
copy_buffer: vec![],
|
copy_buffer: vec![],
|
||||||
|
active_document_index: 0,
|
||||||
|
document_id_counter: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -103,15 +118,11 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
|
||||||
use DocumentsMessage::*;
|
use DocumentsMessage::*;
|
||||||
match message {
|
match message {
|
||||||
Document(message) => self.active_document_mut().process_action(message, ipp, responses),
|
Document(message) => self.active_document_mut().process_action(message, ipp, responses),
|
||||||
SelectDocument(id) => {
|
SelectDocument(index) => {
|
||||||
assert!(id < self.documents.len(), "Tried to select a document that was not initialized");
|
// NOTE: Potentially this will break if we ever exceed 56 bit values due to how the message parsing system works.
|
||||||
self.active_document_index = id;
|
assert!(index < self.documents.len(), "Tried to select a document that was not initialized");
|
||||||
responses.push_back(
|
self.active_document_index = index;
|
||||||
FrontendMessage::SetActiveDocument {
|
responses.push_back(FrontendMessage::SetActiveDocument { document_index: index }.into());
|
||||||
document_index: self.active_document_index,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
responses.push_back(RenderDocument.into());
|
responses.push_back(RenderDocument.into());
|
||||||
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
||||||
for layer in self.active_document().layer_data.keys() {
|
for layer in self.active_document().layer_data.keys() {
|
||||||
|
|
@ -132,54 +143,47 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
|
||||||
CloseAllDocuments => {
|
CloseAllDocuments => {
|
||||||
// Empty the list of internal document data
|
// Empty the list of internal document data
|
||||||
self.documents.clear();
|
self.documents.clear();
|
||||||
|
self.document_ids.clear();
|
||||||
|
|
||||||
// Create a new blank document
|
// Create a new blank document
|
||||||
responses.push_back(NewDocument.into());
|
responses.push_back(NewDocument.into());
|
||||||
}
|
}
|
||||||
CloseDocument(id) => {
|
CloseDocument(index) => {
|
||||||
assert!(id < self.documents.len(), "Tried to select a document that was not initialized");
|
assert!(index < self.documents.len(), "Tried to close a document that was not initialized");
|
||||||
// Remove doc from the backend store; use `id` as client tabs and backend documents will be in sync
|
// Get the ID based on the current collection of the documents.
|
||||||
self.documents.remove(id);
|
let id = self.document_ids[index];
|
||||||
|
// Map the ID to an index and remove the document
|
||||||
// Send the new list of document tab names
|
self.documents.remove(&id);
|
||||||
let open_documents = self.documents.iter().map(|doc| doc.name.clone()).collect();
|
self.document_ids.remove(index);
|
||||||
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
|
||||||
|
|
||||||
// Last tab was closed, so create a new blank tab
|
// Last tab was closed, so create a new blank tab
|
||||||
if self.documents.is_empty() {
|
if self.document_ids.is_empty() {
|
||||||
self.active_document_index = 0;
|
self.document_id_counter += 1;
|
||||||
responses.push_back(NewDocument.into());
|
self.document_ids.push(self.document_id_counter);
|
||||||
|
self.documents.insert(self.document_id_counter, DocumentMessageHandler::default());
|
||||||
}
|
}
|
||||||
// The currently selected doc is being closed
|
|
||||||
else if id == self.active_document_index {
|
|
||||||
// The currently selected tab was the rightmost tab
|
|
||||||
if id == self.documents.len() {
|
|
||||||
self.active_document_index -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
self.active_document_index = if self.active_document_index >= self.document_ids.len() {
|
||||||
responses.push_back(
|
self.document_ids.len() - 1
|
||||||
FrontendMessage::SetActiveDocument {
|
} else {
|
||||||
document_index: self.active_document_index,
|
index
|
||||||
}
|
};
|
||||||
.into(),
|
|
||||||
);
|
// Send the new list of document tab names
|
||||||
responses.push_back(
|
let open_documents = self.document_ids.iter().filter_map(|id| self.documents.get(&id).map(|doc| doc.name.clone())).collect();
|
||||||
FrontendMessage::UpdateCanvas {
|
|
||||||
document: self.active_document_mut().graphene_document.render_root(),
|
// Update the list of new documents on the front end, active tab, and ensure that document renders
|
||||||
}
|
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
||||||
.into(),
|
responses.push_back(
|
||||||
);
|
FrontendMessage::SetActiveDocument {
|
||||||
}
|
document_index: self.active_document_index,
|
||||||
// Active doc will move one space to the left
|
}
|
||||||
else if id < self.active_document_index {
|
.into(),
|
||||||
self.active_document_index -= 1;
|
);
|
||||||
responses.push_back(
|
responses.push_back(RenderDocument.into());
|
||||||
FrontendMessage::SetActiveDocument {
|
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
||||||
document_index: self.active_document_index,
|
for layer in self.active_document().layer_data.keys() {
|
||||||
}
|
responses.push_back(DocumentMessage::LayerChanged(layer.clone()).into());
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NewDocument => {
|
NewDocument => {
|
||||||
|
|
@ -207,16 +211,17 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
|
||||||
}
|
}
|
||||||
GetOpenDocumentsList => {
|
GetOpenDocumentsList => {
|
||||||
// Send the list of document tab names
|
// Send the list of document tab names
|
||||||
let open_documents = self.documents.iter().map(|doc| doc.name.clone()).collect();
|
let open_documents = self.documents.values().map(|doc| doc.name.clone()).collect();
|
||||||
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
||||||
}
|
}
|
||||||
NextDocument => {
|
NextDocument => {
|
||||||
let id = (self.active_document_index + 1) % self.documents.len();
|
let next = (self.active_document_index + 1) % self.document_ids.len();
|
||||||
responses.push_back(SelectDocument(id).into());
|
responses.push_back(SelectDocument(next).into());
|
||||||
}
|
}
|
||||||
PrevDocument => {
|
PrevDocument => {
|
||||||
let id = (self.active_document_index + self.documents.len() - 1) % self.documents.len();
|
let len = self.document_ids.len();
|
||||||
responses.push_back(SelectDocument(id).into());
|
let prev = (self.active_document_index + len - 1) % len;
|
||||||
|
responses.push_back(SelectDocument(prev).into());
|
||||||
}
|
}
|
||||||
Copy => {
|
Copy => {
|
||||||
let paths = self.active_document().selected_layers_sorted();
|
let paths = self.active_document().selected_layers_sorted();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue