Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement bounding box for selected layers #349

Merged
merged 5 commits into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions editor/src/communication/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ impl Dispatcher {
| Message::Frontend(FrontendMessage::UpdateScrollbars { .. })
| Message::Frontend(FrontendMessage::SetCanvasZoom { .. })
| Message::Frontend(FrontendMessage::SetCanvasRotation { .. })
| Message::Documents(DocumentsMessage::Document(DocumentMessage::DispatchOperation { .. }))
) || MessageDiscriminant::from(&message).local_name().ends_with("MouseMove"))
{
log::trace!("Message: {:?}", message);
Expand Down Expand Up @@ -152,7 +151,7 @@ mod test {
let document_before_copy = editor.dispatcher.documents_message_handler.active_document().document.clone();
let shape_id = document_before_copy.root.as_folder().unwrap().layer_ids[1];

editor.handle_message(DocumentMessage::SelectLayers(vec![vec![shape_id]])).unwrap();
editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![shape_id]])).unwrap();
editor.handle_message(DocumentsMessage::CopySelectedLayers).unwrap();
editor.handle_message(DocumentsMessage::PasteLayers { path: vec![], insert_index: -1 }).unwrap();

Expand Down Expand Up @@ -212,7 +211,7 @@ mod test {
})
.unwrap();

editor.handle_message(DocumentMessage::SelectLayers(vec![vec![folder_id]])).unwrap();
editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![folder_id]])).unwrap();

let document_before_copy = editor.dispatcher.documents_message_handler.active_document().document.clone();

Expand Down Expand Up @@ -276,7 +275,7 @@ mod test {
let rect_id = document_before_copy.root.as_folder().unwrap().layer_ids[RECT_INDEX];
let ellipse_id = document_before_copy.root.as_folder().unwrap().layer_ids[ELLIPSE_INDEX];

editor.handle_message(DocumentMessage::SelectLayers(vec![vec![rect_id], vec![ellipse_id]])).unwrap();
editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![rect_id], vec![ellipse_id]])).unwrap();
editor.handle_message(DocumentsMessage::CopySelectedLayers).unwrap();
editor.handle_message(DocumentMessage::DeleteSelectedLayers).unwrap();
editor.draw_rect(0., 800., 12., 200.);
Expand Down Expand Up @@ -310,7 +309,7 @@ mod test {

let verify_order = |handler: &mut DocumentMessageHandler| (handler.all_layers_sorted(), handler.non_selected_layers_sorted(), handler.selected_layers_sorted());

editor.handle_message(DocumentMessage::SelectLayers(vec![vec![0], vec![2]])).unwrap();
editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![0], vec![2]])).unwrap();

editor.handle_message(DocumentMessage::ReorderSelectedLayers(1)).unwrap();
let (all, non_selected, selected) = verify_order(&mut editor.dispatcher.documents_message_handler.active_document_mut());
Expand Down
46 changes: 34 additions & 12 deletions editor/src/document/document_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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(),
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -488,6 +508,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
.into(),
);
}
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
}
AlignSelectedLayers(axis, aggregate) => {
Expand Down Expand Up @@ -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()),
Expand Down
2 changes: 2 additions & 0 deletions editor/src/document/movement_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion editor/src/input/input_mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl Default for Mapping {
entry! {action=MovementMessage::DisableSnapping, key_up=KeyShift},
// Select
entry! {action=SelectMessage::MouseMove, message=InputMapperMessage::PointerMove},
entry! {action=SelectMessage::DragStart, key_down=Lmb},
entry! {action=SelectMessage::DragStart{add_to_selection: KeyShift}, key_down=Lmb},
entry! {action=SelectMessage::DragStop, key_up=Lmb},
entry! {action=SelectMessage::Abort, key_down=Rmb},
entry! {action=SelectMessage::Abort, key_down=KeyEscape},
Expand Down
3 changes: 2 additions & 1 deletion editor/src/input/keyboard.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::message_prelude::*;
use serde::{Deserialize, Serialize};

pub const NUMBER_OF_KEYS: usize = Key::NumKeys as usize;
// Edit this to specify the storage type used
Expand All @@ -12,7 +13,7 @@ const KEY_MASK_STORAGE_LENGTH: usize = (NUMBER_OF_KEYS + STORAGE_SIZE_BITS - 1)
pub type KeyStates = BitVector<KEY_MASK_STORAGE_LENGTH>;

#[impl_message(Message, InputMapperMessage, KeyDown)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Key {
UnknownKey,
// MouseKeys
Expand Down
67 changes: 43 additions & 24 deletions editor/src/tool/tool_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub enum ToolMessage {
SelectSecondaryColor(Color),
SwapColors,
ResetColors,
NoOp,
SetToolOptions(ToolType, ToolOptions),
#[child]
Fill(FillMessage),
Expand Down Expand Up @@ -59,16 +60,27 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessor)>
update_working_colors(&self.tool_state.document_tool_data, responses);
}
SelectTool(tool) => {
let mut reset = |tool| match tool {
ToolType::Ellipse => responses.push_back(EllipseMessage::Abort.into()),
ToolType::Rectangle => responses.push_back(RectangleMessage::Abort.into()),
ToolType::Shape => responses.push_back(ShapeMessage::Abort.into()),
ToolType::Line => responses.push_back(LineMessage::Abort.into()),
ToolType::Pen => responses.push_back(PenMessage::Abort.into()),
_ => (),
let old_tool = self.tool_state.tool_data.active_tool_type;
let reset = |tool| match tool {
ToolType::Ellipse => EllipseMessage::Abort.into(),
ToolType::Rectangle => RectangleMessage::Abort.into(),
ToolType::Shape => ShapeMessage::Abort.into(),
ToolType::Line => LineMessage::Abort.into(),
ToolType::Pen => PenMessage::Abort.into(),
ToolType::Select => SelectMessage::Abort.into(),
_ => ToolMessage::NoOp,
};
reset(tool);
reset(self.tool_state.tool_data.active_tool_type);
let (new, old) = (reset(tool), reset(old_tool));
let mut send_to_tool = |tool_type, message: ToolMessage| {
if let Some(tool) = self.tool_state.tool_data.tools.get_mut(&tool_type) {
tool.process_action(message, (document, &self.tool_state.document_tool_data, input), responses);
}
};
send_to_tool(tool, new);
send_to_tool(old_tool, old);
if tool == ToolType::Select {
responses.push_back(SelectMessage::UpdateSelectionBoundingBox.into());
}
self.tool_state.tool_data.active_tool_type = tool;

responses.push_back(FrontendMessage::SetActiveTool { tool_name: tool.to_string() }.into())
Expand All @@ -88,22 +100,11 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessor)>
self.tool_state.document_tool_data.tool_options.insert(tool_type, tool_options);
}
message => {
let tool_type = match message {
Fill(_) => ToolType::Fill,
Rectangle(_) => ToolType::Rectangle,
Ellipse(_) => ToolType::Ellipse,
Shape(_) => ToolType::Shape,
Line(_) => ToolType::Line,
Pen(_) => ToolType::Pen,
Select(_) => ToolType::Select,
Crop(_) => ToolType::Crop,
Eyedropper(_) => ToolType::Eyedropper,
Navigate(_) => ToolType::Navigate,
Path(_) => ToolType::Path,
_ => unreachable!(),
};
let tool_type = message_to_tool_type(&message);
if let Some(tool) = self.tool_state.tool_data.tools.get_mut(&tool_type) {
tool.process_action(message, (document, &self.tool_state.document_tool_data, input), responses);
if tool_type == self.tool_state.tool_data.active_tool_type {
tool.process_action(message, (document, &self.tool_state.document_tool_data, input), responses);
}
}
}
}
Expand All @@ -115,6 +116,24 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessor)>
}
}

fn message_to_tool_type(message: &ToolMessage) -> ToolType {
use ToolMessage::*;
match message {
Fill(_) => ToolType::Fill,
Rectangle(_) => ToolType::Rectangle,
Ellipse(_) => ToolType::Ellipse,
Shape(_) => ToolType::Shape,
Line(_) => ToolType::Line,
Pen(_) => ToolType::Pen,
Select(_) => ToolType::Select,
Crop(_) => ToolType::Crop,
Eyedropper(_) => ToolType::Eyedropper,
Navigate(_) => ToolType::Navigate,
Path(_) => ToolType::Path,
_ => unreachable!(),
}
}

fn update_working_colors(doc_data: &DocumentToolData, responses: &mut VecDeque<Message>) {
responses.push_back(
FrontendMessage::UpdateWorkingColors {
Expand Down
Loading