Implement bounding box for selected layers (#349)

* Implement bounding box for selected layers

* Add shift modifier for multi selection
This commit is contained in:
TrueDoctor
2021-08-20 09:57:00 +02:00
committed by Keavon Chambers
parent 7c64e1a816
commit 68d8ae4804
10 changed files with 159 additions and 72 deletions

View File

@@ -66,8 +66,10 @@ pub enum DocumentMessage {
#[child]
Movement(MovementMessage),
DispatchOperation(Box<DocumentOperation>),
SelectLayers(Vec<Vec<LayerId>>),
SetSelectedLayers(Vec<Vec<LayerId>>),
AddSelectedLayers(Vec<Vec<LayerId>>),
SelectAllLayers,
SelectionChanged,
DeselectAllLayers,
DeleteLayer(Vec<LayerId>),
DeleteSelectedLayers,
@@ -125,9 +127,17 @@ impl DocumentMessageHandler {
self.layer_data.values_mut().for_each(|layer_data| layer_data.selected = false);
}
fn select_layer(&mut self, path: &[LayerId]) -> Option<Message> {
if self.document.layer(path).ok()?.overlay {
return None;
}
self.layer_data(path).selected = true;
let data = self.layer_panel_entry(path.to_vec()).ok()?;
// TODO: Add deduplication
(!path.is_empty()).then(|| self.handle_folder_changed(path[..path.len() - 1].to_vec())).flatten()
(!path.is_empty()).then(|| FrontendMessage::UpdateLayer { path: path.to_vec(), data }.into())
}
pub fn selected_layers_bounding_box(&self) -> Option<[DVec2; 2]> {
let paths = self.selected_layers().map(|vec| &vec[..]);
self.document.combined_viewport_bounding_box(paths)
}
pub fn layerdata(&self, path: &[LayerId]) -> &LayerData {
self.layer_data.get(path).expect("Layerdata does not exist")
@@ -247,6 +257,7 @@ impl DocumentMessageHandler {
.iter()
.zip(paths.iter().zip(data))
.rev()
.filter(|(layer, _)| !layer.overlay)
.map(|(layer, (path, data))| {
layer_panel_entry(
&data,
@@ -332,34 +343,41 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
self.layer_data(&path).expanded ^= true;
responses.extend(self.handle_folder_changed(path));
}
SelectionChanged => responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into()),
DeleteSelectedLayers => {
for path in self.selected_layers().cloned() {
responses.push_back(DocumentOperation::DeleteLayer { path }.into())
}
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
DuplicateSelectedLayers => {
for path in self.selected_layers_sorted() {
responses.push_back(DocumentOperation::DuplicateLayer { path }.into())
}
}
SelectLayers(paths) => {
SetSelectedLayers(paths) => {
self.clear_selection();
responses.push_front(AddSelectedLayers(paths).into());
}
AddSelectedLayers(paths) => {
for path in paths {
responses.extend(self.select_layer(&path));
}
// TODO: Correctly update layer panel in clear_selection instead of here
responses.extend(self.handle_folder_changed(Vec::new()));
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
SelectAllLayers => {
let all_layer_paths = self.layer_data.keys().filter(|path| !path.is_empty()).cloned().collect::<Vec<_>>();
for path in all_layer_paths {
responses.extend(self.select_layer(&path));
}
let all_layer_paths = self
.layer_data
.keys()
.filter(|path| !path.is_empty() && !self.document.layer(path).unwrap().overlay)
.cloned()
.collect::<Vec<_>>();
responses.push_back(SetSelectedLayers(all_layer_paths).into());
}
DeselectAllLayers => {
self.clear_selection();
let children = self.layer_panel(&[]).expect("The provided Path was not valid");
responses.push_back(FrontendMessage::ExpandFolder { path: vec![], children }.into());
responses.push_back(SetSelectedLayers(vec![]).into());
}
Undo => {
// this is a temporary fix and will be addressed by #123
@@ -378,7 +396,8 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
DocumentResponse::FolderChanged { path } => self.handle_folder_changed(path),
DocumentResponse::DeletedLayer { path } => {
self.layer_data.remove(&path);
None
Some(SelectMessage::UpdateSelectionBoundingBox.into())
}
DocumentResponse::LayerChanged { path } => Some(
FrontendMessage::UpdateLayer {
@@ -387,7 +406,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
}
.into(),
),
DocumentResponse::CreatedLayer { path } => self.select_layer(&path),
DocumentResponse::CreatedLayer { path } => (!self.document.layer(&path).unwrap().overlay).then(|| SetSelectedLayers(vec![path]).into()),
DocumentResponse::DocumentChanged => unreachable!(),
})
.flatten(),
@@ -434,6 +453,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
};
responses.push_back(operation.into());
}
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
MoveSelectedLayersTo { path, insert_index } => {
responses.push_back(DocumentsMessage::CopySelectedLayers.into());
@@ -488,6 +508,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
.into(),
);
}
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
}
AlignSelectedLayers(axis, aggregate) => {
@@ -520,6 +541,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
.into(),
);
}
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
}
RenameLayer(path, name) => responses.push_back(DocumentOperation::RenameLayer { path, name }.into()),

View File

@@ -105,6 +105,7 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
layerdata.rotation += rotation;
layerdata.snap_rotate = snapping;
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
responses.push_back(
FrontendMessage::SetCanvasRotation {
new_radians: layerdata.snapped_angle(),
@@ -172,6 +173,7 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
layerdata.rotation = new;
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
responses.push_back(FrontendMessage::SetCanvasRotation { new_radians: new }.into());
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
ZoomCanvasToFitAll => {
if let Some([pos1, pos2]) = document.visible_layers_bounding_box() {