mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 08:08:11 +08:00
Implement backend part of the layer selection (#172)
* Implement backend part of the layer selection
This commit is contained in:
@@ -1,7 +1,69 @@
|
||||
use document_core::document::Document as InteralDocument;
|
||||
use crate::{frontend::layer_panel::*, EditorError};
|
||||
use document_core::{document::Document as InteralDocument, layers::Layer, LayerId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Document {
|
||||
pub document: InteralDocument,
|
||||
pub name: String,
|
||||
pub layer_data: HashMap<Vec<LayerId>, LayerData>,
|
||||
}
|
||||
|
||||
impl Default for Document {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
document: InteralDocument::default(),
|
||||
name: String::from("Unnamed Document"),
|
||||
layer_data: vec![(vec![], LayerData { selected: false, expanded: true })].into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn layer_data<'a>(layer_data: &'a mut HashMap<Vec<LayerId>, LayerData>, path: &[LayerId]) -> &'a mut LayerData {
|
||||
if !layer_data.contains_key(path) {
|
||||
layer_data.insert(path.to_vec(), LayerData::default());
|
||||
}
|
||||
layer_data.get_mut(path).unwrap()
|
||||
}
|
||||
|
||||
pub fn layer_panel_entry(layer_data: &mut LayerData, layer: &Layer, path: Vec<LayerId>) -> LayerPanelEntry {
|
||||
let layer_type: LayerType = (&layer.data).into();
|
||||
let name = layer.name.clone().unwrap_or_else(|| format!("Unnamed {}", layer_type));
|
||||
LayerPanelEntry {
|
||||
name,
|
||||
visible: layer.visible,
|
||||
layer_type,
|
||||
layer_data: *layer_data,
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
||||
impl Document {
|
||||
pub fn layer_data(&mut self, path: &[LayerId]) -> &mut LayerData {
|
||||
layer_data(&mut self.layer_data, path)
|
||||
}
|
||||
|
||||
/// Returns a list of `LayerPanelEntry`s intended for display purposes. These don't contain
|
||||
/// any actual data, but rather metadata such as visibility and names of the layers.
|
||||
pub fn layer_panel(&mut self, path: &[LayerId]) -> Result<Vec<LayerPanelEntry>, EditorError> {
|
||||
let folder = self.document.document_folder(path)?;
|
||||
let self_layer_data = &mut self.layer_data;
|
||||
let entries = folder
|
||||
.layers()
|
||||
.iter()
|
||||
.zip(folder.layer_ids.iter())
|
||||
.map(|(layer, id)| {
|
||||
let path = [path, &[*id]].concat();
|
||||
layer_panel_entry(layer_data(self_layer_data, &path), layer, path)
|
||||
})
|
||||
.collect();
|
||||
Ok(entries)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Copy, Default)]
|
||||
pub struct LayerData {
|
||||
pub selected: bool,
|
||||
pub expanded: bool,
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::collections::VecDeque;
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum DocumentMessage {
|
||||
DispatchOperation(DocumentOperation),
|
||||
SelectLayer(Vec<LayerId>),
|
||||
SelectLayers(Vec<Vec<LayerId>>),
|
||||
DeleteLayer(Vec<LayerId>),
|
||||
AddFolder(Vec<LayerId>),
|
||||
RenameLayer(Vec<LayerId>, String),
|
||||
@@ -49,6 +49,13 @@ impl DocumentMessageHandler {
|
||||
document_responses.retain(|response| !matches!(response, DocumentResponse::DocumentChanged));
|
||||
document_responses.len() != len
|
||||
}
|
||||
fn handle_folder_changed(&mut self, path: Vec<LayerId>) -> Option<Message> {
|
||||
let document = self.active_document_mut();
|
||||
document.layer_data(&path).expanded.then(|| {
|
||||
let children = document.layer_panel(path.as_slice()).expect("The provided Path was not valid");
|
||||
FrontendMessage::ExpandFolder { path, children }.into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DocumentMessageHandler {
|
||||
@@ -84,6 +91,17 @@ impl MessageHandler<DocumentMessage, ()> for DocumentMessageHandler {
|
||||
ToggleLayerVisibility(path) => {
|
||||
responses.push_back(DocumentOperation::ToggleVisibility { path }.into());
|
||||
}
|
||||
ToggleLayerExpansion(path) => {
|
||||
self.active_document_mut().layer_data(&path).expanded ^= true;
|
||||
responses.extend(self.handle_folder_changed(path));
|
||||
}
|
||||
SelectLayers(paths) => {
|
||||
for path in paths {
|
||||
self.active_document_mut().layer_data(&path).selected ^= true;
|
||||
responses.extend(self.handle_folder_changed(path));
|
||||
// TODO: Add deduplication
|
||||
}
|
||||
}
|
||||
Undo => {
|
||||
// this is a temporary fix and will be addressed by #123
|
||||
if let Some(id) = self.active_document().document.root.list_layers().last() {
|
||||
@@ -93,7 +111,15 @@ impl MessageHandler<DocumentMessage, ()> for DocumentMessageHandler {
|
||||
DispatchOperation(op) => {
|
||||
if let Ok(Some(mut document_responses)) = self.active_document_mut().document.handle_operation(op) {
|
||||
let canvas_dirty = self.filter_document_responses(&mut document_responses);
|
||||
responses.extend(document_responses.into_iter().map(Into::into));
|
||||
responses.extend(
|
||||
document_responses
|
||||
.into_iter()
|
||||
.map(|response| match response {
|
||||
DocumentResponse::FolderChanged { path } => self.handle_folder_changed(path),
|
||||
DocumentResponse::DocumentChanged => unreachable!(),
|
||||
})
|
||||
.flatten(),
|
||||
);
|
||||
if canvas_dirty {
|
||||
responses.push_back(RenderDocument.into())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ mod document_file;
|
||||
mod document_message_handler;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use document_file::Document;
|
||||
pub use document_file::{Document, LayerData};
|
||||
|
||||
#[doc(inline)]
|
||||
pub use document_message_handler::{DocumentMessage, DocumentMessageDiscriminant, DocumentMessageHandler};
|
||||
|
||||
Reference in New Issue
Block a user