mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 04:38:13 +08:00
Known cases of crash / incorrect behavior resolved
This commit is contained in:
@@ -277,15 +277,31 @@ impl DocumentMessageHandler {
|
|||||||
self.layer_data.iter().filter_map(|(path, data)| data.selected.then(|| path.as_slice()))
|
self.layer_data.iter().filter_map(|(path, data)| data.selected.then(|| path.as_slice()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selected_layers_without_children(&self) -> impl Iterator<Item = &[LayerId]> {
|
pub fn selected_layers_without_children(&self) -> Vec<Vec<LayerId>> {
|
||||||
let selected_folders: Vec<&Folder> = self
|
let mut without_children: Vec<Vec<LayerId>> = vec![];
|
||||||
.layer_data
|
recurse_layer_tree(self, vec![], &mut without_children, false);
|
||||||
.iter()
|
|
||||||
.filter_map(|(path, data)| (data.selected && self.graphene_document.is_folder(path)).then(|| self.graphene_document.folder(path).unwrap()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
self.selected_layers()
|
// Traversing the layer tree was chosen for both readability and instead of an n^2 comparison approach.
|
||||||
.filter(move |path| selected_folders.is_empty() || !selected_folders.iter().any(|folder| (*folder).folder_contains(path[path.len() - 1])))
|
// A future optmiziation would be not needing to start at the root []
|
||||||
|
fn recurse_layer_tree(ctx: &DocumentMessageHandler, mut path: Vec<u64>, without_children: &mut Vec<Vec<LayerId>>, selected: bool) {
|
||||||
|
if let Ok(folder) = ctx.graphene_document.folder(&path) {
|
||||||
|
for child in folder.list_layers() {
|
||||||
|
path.push(*child);
|
||||||
|
let selected_or_parent_selected = selected || ctx.selected_layers_contains(&path);
|
||||||
|
let selected_without_any_parent_selected = !selected && ctx.selected_layers_contains(&path);
|
||||||
|
if ctx.graphene_document.is_folder(&path) {
|
||||||
|
if selected_without_any_parent_selected {
|
||||||
|
without_children.push(path.clone());
|
||||||
|
}
|
||||||
|
recurse_layer_tree(ctx, path.clone(), without_children, selected_or_parent_selected);
|
||||||
|
} else if selected_without_any_parent_selected {
|
||||||
|
without_children.push(path.clone());
|
||||||
|
}
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
without_children
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selected_layers_contains(&self, path: &[LayerId]) -> bool {
|
pub fn selected_layers_contains(&self, path: &[LayerId]) -> bool {
|
||||||
@@ -579,10 +595,10 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
|||||||
responses.push_back(DocumentMessage::SetLayerExpansion(path, true).into());
|
responses.push_back(DocumentMessage::SetLayerExpansion(path, true).into());
|
||||||
}
|
}
|
||||||
GroupSelectedLayers => {
|
GroupSelectedLayers => {
|
||||||
let selected_layers = self.selected_layers();
|
|
||||||
// TODO simplify and protect unwrap
|
// TODO simplify and protect unwrap
|
||||||
let mut new_folder_path: Vec<u64> = self.graphene_document.deepest_common_folder(selected_layers).unwrap().to_vec();
|
let mut new_folder_path: Vec<u64> = self.graphene_document.shallowest_common_folder(self.selected_layers()).unwrap_or(&[]).to_vec();
|
||||||
|
|
||||||
|
// Required for grouping parent folders with their own children
|
||||||
if !new_folder_path.is_empty() && self.selected_layers_contains(&new_folder_path) {
|
if !new_folder_path.is_empty() && self.selected_layers_contains(&new_folder_path) {
|
||||||
new_folder_path.remove(new_folder_path.len() - 1);
|
new_folder_path.remove(new_folder_path.len() - 1);
|
||||||
}
|
}
|
||||||
@@ -638,7 +654,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
|
|||||||
DeleteSelectedLayers => {
|
DeleteSelectedLayers => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
|
|
||||||
for path in self.selected_layers_without_children().map(|path| path.to_vec()) {
|
for path in self.selected_layers_without_children() {
|
||||||
responses.push_front(DocumentOperation::DeleteLayer { path }.into());
|
responses.push_front(DocumentOperation::DeleteLayer { path }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
|
|||||||
copy_buffer[clipboard as usize].clear();
|
copy_buffer[clipboard as usize].clear();
|
||||||
|
|
||||||
for layer_path in active_document.selected_layers_without_children() {
|
for layer_path in active_document.selected_layers_without_children() {
|
||||||
match (active_document.graphene_document.layer(layer_path).map(|t| t.clone()), *active_document.layer_data(layer_path)) {
|
match (active_document.graphene_document.layer(&layer_path).map(|t| t.clone()), *active_document.layer_data(&layer_path)) {
|
||||||
(Ok(layer), layer_data) => {
|
(Ok(layer), layer_data) => {
|
||||||
copy_buffer[clipboard as usize].push(CopyBufferEntry { layer, layer_data });
|
copy_buffer[clipboard as usize].push(CopyBufferEntry { layer, layer_data });
|
||||||
}
|
}
|
||||||
@@ -373,11 +373,16 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
|
|||||||
}
|
}
|
||||||
Paste(clipboard) => {
|
Paste(clipboard) => {
|
||||||
let document = self.active_document();
|
let document = self.active_document();
|
||||||
let shallowest_common_folder = document
|
let mut shallowest_common_folder = document
|
||||||
.graphene_document
|
.graphene_document
|
||||||
.deepest_common_folder(document.selected_layers())
|
.shallowest_common_folder(document.selected_layers())
|
||||||
.expect("While pasting, the selected layers did not exist while attempting to find the appropriate folder path for insertion");
|
.expect("While pasting, the selected layers did not exist while attempting to find the appropriate folder path for insertion");
|
||||||
|
|
||||||
|
// We want to paste folders at the same depth as their copy source
|
||||||
|
if !shallowest_common_folder.is_empty() && document.selected_layers_contains(shallowest_common_folder) {
|
||||||
|
shallowest_common_folder = &shallowest_common_folder[..shallowest_common_folder.len() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
PasteIntoFolder {
|
PasteIntoFolder {
|
||||||
clipboard,
|
clipboard,
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ impl Document {
|
|||||||
self.folder_mut(path)?.layer_mut(id).ok_or_else(|| DocumentError::LayerNotFound(path.into()))
|
self.folder_mut(path)?.layer_mut(id).ok_or_else(|| DocumentError::LayerNotFound(path.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deepest_common_folder<'a>(&self, layers: impl Iterator<Item = &'a [LayerId]>) -> Result<&'a [LayerId], DocumentError> {
|
pub fn shallowest_common_folder<'a>(&self, layers: impl Iterator<Item = &'a [LayerId]>) -> Result<&'a [LayerId], DocumentError> {
|
||||||
let common_prefix_of_path = self.common_layer_path_prefix(layers);
|
let common_prefix_of_path = self.common_layer_path_prefix(layers);
|
||||||
|
|
||||||
Ok(match self.layer(common_prefix_of_path)?.data {
|
Ok(match self.layer(common_prefix_of_path)?.data {
|
||||||
@@ -546,7 +546,6 @@ impl Document {
|
|||||||
Some(vec![LayerChanged { path: path.clone() }])
|
Some(vec![LayerChanged { path: path.clone() }])
|
||||||
}
|
}
|
||||||
Operation::CreateFolder { path } => {
|
Operation::CreateFolder { path } => {
|
||||||
log::debug!("Creating a folder with path {:?}", path);
|
|
||||||
self.set_layer(path, Layer::new(LayerDataType::Folder(Folder::default()), DAffine2::IDENTITY.to_cols_array()), -1)?;
|
self.set_layer(path, Layer::new(LayerDataType::Folder(Folder::default()), DAffine2::IDENTITY.to_cols_array()), -1)?;
|
||||||
self.mark_as_dirty(path)?;
|
self.mark_as_dirty(path)?;
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ impl Folder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn folder_contains(&self, id: LayerId) -> bool {
|
pub fn folder_contains(&self, id: LayerId) -> bool {
|
||||||
log::debug!("For {:?} Folder does contain {:?}", id, self.layer_ids.contains(&id));
|
|
||||||
self.layer_ids.contains(&id)
|
self.layer_ids.contains(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user