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:
Oliver Davies
2021-12-22 17:45:14 -08:00
committed by Keavon Chambers
parent 80a3e41654
commit 3fc6e05a12
7 changed files with 122 additions and 75 deletions
+51 -2
View File
@@ -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);
+4
View File
@@ -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