mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-24 01:08:11 +08:00
Move layer selection logic from vue to editor (#410)
* Add vue selectLayer(layer, ctrl, shift) * Individual selection working, range fill next * Frontend package-lock.json seems apparently needs to be pushed. Weird. * Selection working with ctrl, shift from editor. Still some bugs to sqaush with folder nesting. * WIP resolving nesting folders issues * Changed comparison approach, handling corner cases now * Fully working selection. * Reverted changes to package-lock.json * Removed unused code * Resolved ctrl click not behaving similar to windows * Slight comment clarification * Double checked a windows behavior and corrected. Changed last_selected name. * Simplified if statement slightly. * Made the naming clearer regarding UUIDs versus indices * Clarified comments further * Minor comment fixup * Implemented suggestions, clarified comments * Resolved todo regarding clearing selection when ctrl not pressed * Ensure we only push responses when needed Co-authored-by: Keavon Chambers <keavon@keavon.com> Reviewed by: @TrueDoctor <3
This commit is contained in:
committed by
Keavon Chambers
parent
80a3e41654
commit
3fc6e05a12
@@ -1,4 +1,5 @@
|
||||
use std::{
|
||||
cmp::max,
|
||||
collections::hash_map::DefaultHasher,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
@@ -102,7 +103,7 @@ impl Document {
|
||||
}
|
||||
|
||||
pub fn deepest_common_folder<'a>(&self, layers: impl Iterator<Item = &'a [LayerId]>) -> Result<&'a [LayerId], DocumentError> {
|
||||
let common_prefix_of_path = self.common_prefix(layers);
|
||||
let common_prefix_of_path = self.common_layer_path_prefix(layers);
|
||||
|
||||
Ok(match self.layer(common_prefix_of_path)?.data {
|
||||
LayerDataType::Folder(_) => common_prefix_of_path,
|
||||
@@ -110,7 +111,7 @@ impl Document {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn common_prefix<'a>(&self, layers: impl Iterator<Item = &'a [LayerId]>) -> &'a [LayerId] {
|
||||
pub fn common_layer_path_prefix<'a>(&self, layers: impl Iterator<Item = &'a [LayerId]>) -> &'a [LayerId] {
|
||||
layers
|
||||
.reduce(|a, b| {
|
||||
let number_of_uncommon_ids_in_a = (0..a.len()).position(|i| b.starts_with(&a[..a.len() - i])).unwrap_or_default();
|
||||
@@ -119,6 +120,53 @@ impl Document {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
// Determines which layer is closer to the root, if path_a return true, if path_b return false
|
||||
// Answers the question: Is A closer to the root than B?
|
||||
pub fn layer_closer_to_root(&self, path_a: &Vec<u64>, path_b: &Vec<u64>) -> bool {
|
||||
// Convert UUIDs to indices
|
||||
let indices_for_path_a = self.indices_for_path(path_a).unwrap();
|
||||
let indices_for_path_b = self.indices_for_path(path_b).unwrap();
|
||||
|
||||
let longest = max(indices_for_path_a.len(), indices_for_path_b.len());
|
||||
for i in 0..longest {
|
||||
// usize::MAX becomes negative one here, sneaky. So folders are compared as [X, -1]. This is intentional.
|
||||
let index_a = *indices_for_path_a.get(i).unwrap_or(&usize::MAX) as i32;
|
||||
let index_b = *indices_for_path_b.get(i).unwrap_or(&usize::MAX) as i32;
|
||||
|
||||
// index_a == index_b -> true, this means the "2" indices being compared are within the same folder
|
||||
// eg -> [2, X] == [2, X] since we are only comparing the "2" in this iteration
|
||||
// Continue onto comparing the X indices.
|
||||
if index_a == index_b {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If index_a is smaller, index_a is closer to the root
|
||||
return index_a < index_b;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the target layer between a <-> b layers, inclusive
|
||||
pub fn layer_is_between(&self, target: &Vec<u64>, path_a: &Vec<u64>, path_b: &Vec<u64>) -> bool {
|
||||
// If the target is a nonsense path, it isn't between
|
||||
if target.len() < 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is inclusive, so we consider path_a, path_b to be between themselves
|
||||
if target == path_a || target == path_b {
|
||||
return true;
|
||||
};
|
||||
|
||||
// These can't both be true and be between two values
|
||||
let layer_vs_a = self.layer_closer_to_root(target, path_a);
|
||||
let layer_vs_b = self.layer_closer_to_root(target, path_b);
|
||||
|
||||
// To be inbetween you need to be above A and below B or vice versa
|
||||
return layer_vs_a != layer_vs_b;
|
||||
}
|
||||
|
||||
/// Given a path to a layer, returns a vector of the indices in the layer tree
|
||||
/// These indices can be used to order a list of layers
|
||||
pub fn indices_for_path(&self, path: &[LayerId]) -> Result<Vec<usize>, DocumentError> {
|
||||
@@ -126,6 +174,7 @@ impl Document {
|
||||
let mut indices = vec![];
|
||||
let (path, layer_id) = split_path(path)?;
|
||||
|
||||
// TODO: appears to be n^2? should we maintain a lookup table?
|
||||
for id in path {
|
||||
let pos = root.layer_ids.iter().position(|x| *x == *id).ok_or(DocumentError::LayerNotFound)?;
|
||||
indices.push(pos);
|
||||
|
||||
@@ -41,6 +41,7 @@ impl Folder {
|
||||
/// When a insertion id is provided, try to insert the layer with the given id.
|
||||
/// If that id is already used, return None.
|
||||
/// When no insertion id is provided, search for the next free id and insert it with that.
|
||||
/// Negative values for insert_index represent distance from the end
|
||||
pub fn add_layer(&mut self, layer: Layer, id: Option<LayerId>, insert_index: isize) -> Option<LayerId> {
|
||||
let mut insert_index = insert_index as i128;
|
||||
if insert_index < 0 {
|
||||
@@ -54,13 +55,16 @@ impl Folder {
|
||||
if self.layer_ids.contains(&self.next_assignment_id) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let id = self.next_assignment_id;
|
||||
self.layers.insert(insert_index as usize, layer);
|
||||
self.layer_ids.insert(insert_index as usize, id);
|
||||
|
||||
// Linear probing for collision avoidance
|
||||
while self.layer_ids.contains(&self.next_assignment_id) {
|
||||
self.next_assignment_id += 1;
|
||||
}
|
||||
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user