mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 00:58:11 +08:00
Modify all message enum data to use named struct values, not tuples (#479)
* Massively reorganize and clean up the whole Rust codebase * Modify all message enum data to use named struct values, not tuples
This commit is contained in:
@@ -161,10 +161,10 @@ mod test {
|
|||||||
let mut editor = create_editor_with_three_layers();
|
let mut editor = create_editor_with_three_layers();
|
||||||
|
|
||||||
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
||||||
editor.handle_message(PortfolioMessage::Copy(Clipboard::User));
|
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::User });
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::User,
|
clipboard: Clipboard::User,
|
||||||
path: vec![],
|
folder_path: vec![],
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
});
|
});
|
||||||
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
||||||
@@ -197,11 +197,13 @@ mod test {
|
|||||||
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
||||||
let shape_id = document_before_copy.root.as_folder().unwrap().layer_ids[1];
|
let shape_id = document_before_copy.root.as_folder().unwrap().layer_ids[1];
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![shape_id]]));
|
editor.handle_message(DocumentMessage::SetSelectedLayers {
|
||||||
editor.handle_message(PortfolioMessage::Copy(Clipboard::User));
|
replacement_selected_layers: vec![vec![shape_id]],
|
||||||
|
});
|
||||||
|
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::User });
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::User,
|
clipboard: Clipboard::User,
|
||||||
path: vec![],
|
folder_path: vec![],
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -235,7 +237,7 @@ mod test {
|
|||||||
const LINE_INDEX: usize = 0;
|
const LINE_INDEX: usize = 0;
|
||||||
const PEN_INDEX: usize = 1;
|
const PEN_INDEX: usize = 1;
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::CreateEmptyFolder(vec![]));
|
editor.handle_message(DocumentMessage::CreateEmptyFolder { container_path: vec![] });
|
||||||
|
|
||||||
let document_before_added_shapes = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
let document_before_added_shapes = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
||||||
let folder_id = document_before_added_shapes.root.as_folder().unwrap().layer_ids[FOLDER_INDEX];
|
let folder_id = document_before_added_shapes.root.as_folder().unwrap().layer_ids[FOLDER_INDEX];
|
||||||
@@ -257,20 +259,22 @@ mod test {
|
|||||||
points: vec![(10.0, 20.0), (30.0, 40.0)],
|
points: vec![(10.0, 20.0), (30.0, 40.0)],
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![folder_id]]));
|
editor.handle_message(DocumentMessage::SetSelectedLayers {
|
||||||
|
replacement_selected_layers: vec![vec![folder_id]],
|
||||||
|
});
|
||||||
|
|
||||||
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().graphene_document.clone();
|
||||||
|
|
||||||
editor.handle_message(PortfolioMessage::Copy(Clipboard::User));
|
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::User });
|
||||||
editor.handle_message(DocumentMessage::DeleteSelectedLayers);
|
editor.handle_message(DocumentMessage::DeleteSelectedLayers);
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::User,
|
clipboard: Clipboard::User,
|
||||||
path: vec![],
|
folder_path: vec![],
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
});
|
});
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::User,
|
clipboard: Clipboard::User,
|
||||||
path: vec![],
|
folder_path: vec![],
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -329,18 +333,20 @@ mod test {
|
|||||||
let rect_id = document_before_copy.root.as_folder().unwrap().layer_ids[RECT_INDEX];
|
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];
|
let ellipse_id = document_before_copy.root.as_folder().unwrap().layer_ids[ELLIPSE_INDEX];
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::SetSelectedLayers(vec![vec![rect_id], vec![ellipse_id]]));
|
editor.handle_message(DocumentMessage::SetSelectedLayers {
|
||||||
editor.handle_message(PortfolioMessage::Copy(Clipboard::User));
|
replacement_selected_layers: vec![vec![rect_id], vec![ellipse_id]],
|
||||||
|
});
|
||||||
|
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::User });
|
||||||
editor.handle_message(DocumentMessage::DeleteSelectedLayers);
|
editor.handle_message(DocumentMessage::DeleteSelectedLayers);
|
||||||
editor.draw_rect(0., 800., 12., 200.);
|
editor.draw_rect(0., 800., 12., 200.);
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::User,
|
clipboard: Clipboard::User,
|
||||||
path: vec![],
|
folder_path: vec![],
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
});
|
});
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::User,
|
clipboard: Clipboard::User,
|
||||||
path: vec![],
|
folder_path: vec![],
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -385,17 +391,19 @@ mod test {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::SetSelectedLayers(sorted_layers[..2].to_vec()));
|
editor.handle_message(DocumentMessage::SetSelectedLayers {
|
||||||
|
replacement_selected_layers: sorted_layers[..2].to_vec(),
|
||||||
|
});
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::ReorderSelectedLayers(1));
|
editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: 1 });
|
||||||
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
|
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
|
||||||
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());
|
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::ReorderSelectedLayers(-1));
|
editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: -1 });
|
||||||
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
|
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
|
||||||
assert_eq!(all, selected.into_iter().chain(non_selected.into_iter()).collect::<Vec<_>>());
|
assert_eq!(all, selected.into_iter().chain(non_selected.into_iter()).collect::<Vec<_>>());
|
||||||
|
|
||||||
editor.handle_message(DocumentMessage::ReorderSelectedLayers(i32::MAX));
|
editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: isize::MAX });
|
||||||
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
|
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut());
|
||||||
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());
|
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,23 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum DocumentMessage {
|
pub enum DocumentMessage {
|
||||||
AbortTransaction,
|
AbortTransaction,
|
||||||
AddSelectedLayers(Vec<Vec<LayerId>>),
|
AddSelectedLayers {
|
||||||
AlignSelectedLayers(AlignAxis, AlignAggregate),
|
additional_layers: Vec<Vec<LayerId>>,
|
||||||
|
},
|
||||||
|
AlignSelectedLayers {
|
||||||
|
axis: AlignAxis,
|
||||||
|
aggregate: AlignAggregate,
|
||||||
|
},
|
||||||
#[child]
|
#[child]
|
||||||
Artboard(ArtboardMessage),
|
Artboard(ArtboardMessage),
|
||||||
CommitTransaction,
|
CommitTransaction,
|
||||||
CreateEmptyFolder(Vec<LayerId>),
|
CreateEmptyFolder {
|
||||||
|
container_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
DebugPrintDocument,
|
DebugPrintDocument,
|
||||||
DeleteLayer(Vec<LayerId>),
|
DeleteLayer {
|
||||||
|
layer_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
DeleteSelectedLayers,
|
DeleteSelectedLayers,
|
||||||
DeselectAllLayers,
|
DeselectAllLayers,
|
||||||
DirtyRenderDocument,
|
DirtyRenderDocument,
|
||||||
@@ -32,41 +41,78 @@ pub enum DocumentMessage {
|
|||||||
DocumentStructureChanged,
|
DocumentStructureChanged,
|
||||||
DuplicateSelectedLayers,
|
DuplicateSelectedLayers,
|
||||||
ExportDocument,
|
ExportDocument,
|
||||||
FlipSelectedLayers(FlipAxis),
|
FlipSelectedLayers {
|
||||||
FolderChanged(Vec<LayerId>),
|
flip_axis: FlipAxis,
|
||||||
|
},
|
||||||
|
FolderChanged {
|
||||||
|
affected_folder_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
GroupSelectedLayers,
|
GroupSelectedLayers,
|
||||||
LayerChanged(Vec<LayerId>),
|
LayerChanged {
|
||||||
|
affected_layer_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
#[child]
|
#[child]
|
||||||
Movement(MovementMessage),
|
Movement(MovementMessage),
|
||||||
MoveSelectedLayersTo {
|
MoveSelectedLayersTo {
|
||||||
path: Vec<LayerId>,
|
folder_path: Vec<LayerId>,
|
||||||
insert_index: isize,
|
insert_index: isize,
|
||||||
},
|
},
|
||||||
NudgeSelectedLayers(f64, f64),
|
NudgeSelectedLayers {
|
||||||
|
delta_x: f64,
|
||||||
|
delta_y: f64,
|
||||||
|
},
|
||||||
#[child]
|
#[child]
|
||||||
Overlays(OverlaysMessage),
|
Overlays(OverlaysMessage),
|
||||||
Redo,
|
Redo,
|
||||||
RenameLayer(Vec<LayerId>, String),
|
RenameLayer {
|
||||||
|
layer_path: Vec<LayerId>,
|
||||||
|
new_name: String,
|
||||||
|
},
|
||||||
RenderDocument,
|
RenderDocument,
|
||||||
ReorderSelectedLayers(i32), // relative_position,
|
ReorderSelectedLayers {
|
||||||
|
relative_index_offset: isize,
|
||||||
|
},
|
||||||
RollbackTransaction,
|
RollbackTransaction,
|
||||||
SaveDocument,
|
SaveDocument,
|
||||||
SelectAllLayers,
|
SelectAllLayers,
|
||||||
SelectionChanged,
|
SelectionChanged,
|
||||||
SelectLayer(Vec<LayerId>, bool, bool),
|
SelectLayer {
|
||||||
SetBlendModeForSelectedLayers(BlendMode),
|
layer_path: Vec<LayerId>,
|
||||||
SetLayerExpansion(Vec<LayerId>, bool),
|
ctrl: bool,
|
||||||
SetOpacityForSelectedLayers(f64),
|
shift: bool,
|
||||||
SetSelectedLayers(Vec<Vec<LayerId>>),
|
},
|
||||||
SetSnapping(bool),
|
SetBlendModeForSelectedLayers {
|
||||||
SetViewMode(ViewMode),
|
blend_mode: BlendMode,
|
||||||
|
},
|
||||||
|
SetLayerExpansion {
|
||||||
|
layer_path: Vec<LayerId>,
|
||||||
|
set_expanded: bool,
|
||||||
|
},
|
||||||
|
SetOpacityForSelectedLayers {
|
||||||
|
opacity: f64,
|
||||||
|
},
|
||||||
|
SetSelectedLayers {
|
||||||
|
replacement_selected_layers: Vec<Vec<LayerId>>,
|
||||||
|
},
|
||||||
|
SetSnapping {
|
||||||
|
snap: bool,
|
||||||
|
},
|
||||||
|
SetViewMode {
|
||||||
|
view_mode: ViewMode,
|
||||||
|
},
|
||||||
StartTransaction,
|
StartTransaction,
|
||||||
ToggleLayerExpansion(Vec<LayerId>),
|
ToggleLayerExpansion {
|
||||||
ToggleLayerVisibility(Vec<LayerId>),
|
layer_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
|
ToggleLayerVisibility {
|
||||||
|
layer_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
#[child]
|
#[child]
|
||||||
TransformLayers(TransformLayerMessage),
|
TransformLayers(TransformLayerMessage),
|
||||||
Undo,
|
Undo,
|
||||||
UngroupLayers(Vec<LayerId>),
|
UngroupLayers {
|
||||||
|
folder_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
UngroupSelectedLayers,
|
UngroupSelectedLayers,
|
||||||
UpdateLayerMetadata {
|
UpdateLayerMetadata {
|
||||||
layer_path: Vec<LayerId>,
|
layer_path: Vec<LayerId>,
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ impl DocumentMessageHandler {
|
|||||||
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
||||||
self.document_redo_history.push((document, layer_metadata));
|
self.document_redo_history.push((document, layer_metadata));
|
||||||
for layer in self.layer_metadata.keys() {
|
for layer in self.layer_metadata.keys() {
|
||||||
responses.push_back(DocumentMessage::LayerChanged(layer.clone()).into())
|
responses.push_back(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }.into())
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -358,7 +358,7 @@ impl DocumentMessageHandler {
|
|||||||
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
||||||
self.document_undo_history.push((document, layer_metadata));
|
self.document_undo_history.push((document, layer_metadata));
|
||||||
for layer in self.layer_metadata.keys() {
|
for layer in self.layer_metadata.keys() {
|
||||||
responses.push_back(DocumentMessage::LayerChanged(layer.clone()).into())
|
responses.push_back(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }.into())
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -446,15 +446,15 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
self.undo(responses).unwrap_or_else(|e| log::warn!("{}", e));
|
self.undo(responses).unwrap_or_else(|e| log::warn!("{}", e));
|
||||||
responses.extend([RenderDocument.into(), DocumentStructureChanged.into()]);
|
responses.extend([RenderDocument.into(), DocumentStructureChanged.into()]);
|
||||||
}
|
}
|
||||||
AddSelectedLayers(paths) => {
|
AddSelectedLayers { additional_layers } => {
|
||||||
for path in paths {
|
for layer_path in additional_layers {
|
||||||
responses.extend(self.select_layer(&path));
|
responses.extend(self.select_layer(&layer_path));
|
||||||
}
|
}
|
||||||
// TODO: Correctly update layer panel in clear_selection instead of here
|
// TODO: Correctly update layer panel in clear_selection instead of here
|
||||||
responses.push_back(FolderChanged(Vec::new()).into());
|
responses.push_back(FolderChanged { affected_folder_path: vec![] }.into());
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
}
|
}
|
||||||
AlignSelectedLayers(axis, aggregate) => {
|
AlignSelectedLayers { axis, aggregate } => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
let (paths, boxes): (Vec<_>, Vec<_>) = self
|
let (paths, boxes): (Vec<_>, Vec<_>) = self
|
||||||
.selected_layers()
|
.selected_layers()
|
||||||
@@ -499,16 +499,22 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
CommitTransaction => (),
|
CommitTransaction => (),
|
||||||
CreateEmptyFolder(mut path) => {
|
CreateEmptyFolder { mut container_path } => {
|
||||||
let id = generate_uuid();
|
let id = generate_uuid();
|
||||||
path.push(id);
|
container_path.push(id);
|
||||||
responses.push_back(DocumentOperation::CreateFolder { path: path.clone() }.into());
|
responses.push_back(DocumentOperation::CreateFolder { path: container_path.clone() }.into());
|
||||||
responses.push_back(DocumentMessage::SetLayerExpansion(path, true).into());
|
responses.push_back(
|
||||||
|
DocumentMessage::SetLayerExpansion {
|
||||||
|
layer_path: container_path,
|
||||||
|
set_expanded: true,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
DebugPrintDocument => {
|
DebugPrintDocument => {
|
||||||
log::debug!("{:#?}\n{:#?}", self.graphene_document, self.layer_metadata);
|
log::debug!("{:#?}\n{:#?}", self.graphene_document, self.layer_metadata);
|
||||||
}
|
}
|
||||||
DeleteLayer(path) => responses.push_front(DocumentOperation::DeleteLayer { path }.into()),
|
DeleteLayer { layer_path } => responses.push_front(DocumentOperation::DeleteLayer { path: layer_path }.into()),
|
||||||
DeleteSelectedLayers => {
|
DeleteSelectedLayers => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
|
|
||||||
@@ -519,7 +525,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
responses.push_front(ToolMessage::DocumentIsDirty.into());
|
responses.push_front(ToolMessage::DocumentIsDirty.into());
|
||||||
}
|
}
|
||||||
DeselectAllLayers => {
|
DeselectAllLayers => {
|
||||||
responses.push_front(SetSelectedLayers(vec![]).into());
|
responses.push_front(SetSelectedLayers { replacement_selected_layers: vec![] }.into());
|
||||||
self.layer_range_selection_reference.clear();
|
self.layer_range_selection_reference.clear();
|
||||||
}
|
}
|
||||||
DirtyRenderDocument => {
|
DirtyRenderDocument => {
|
||||||
@@ -537,20 +543,25 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
Ok(Some(document_responses)) => {
|
Ok(Some(document_responses)) => {
|
||||||
for response in document_responses {
|
for response in document_responses {
|
||||||
match &response {
|
match &response {
|
||||||
DocumentResponse::FolderChanged { path } => responses.push_back(FolderChanged(path.clone()).into()),
|
DocumentResponse::FolderChanged { path } => responses.push_back(FolderChanged { affected_folder_path: path.clone() }.into()),
|
||||||
DocumentResponse::DeletedLayer { path } => {
|
DocumentResponse::DeletedLayer { path } => {
|
||||||
self.layer_metadata.remove(path);
|
self.layer_metadata.remove(path);
|
||||||
}
|
}
|
||||||
DocumentResponse::LayerChanged { path } => responses.push_back(LayerChanged(path.clone()).into()),
|
DocumentResponse::LayerChanged { path } => responses.push_back(LayerChanged { affected_layer_path: path.clone() }.into()),
|
||||||
DocumentResponse::CreatedLayer { path } => {
|
DocumentResponse::CreatedLayer { path } => {
|
||||||
if self.layer_metadata.contains_key(path) {
|
if self.layer_metadata.contains_key(path) {
|
||||||
log::warn!("CreatedLayer overrides existing layer metadata.");
|
log::warn!("CreatedLayer overrides existing layer metadata.");
|
||||||
}
|
}
|
||||||
self.layer_metadata.insert(path.clone(), LayerMetadata::new(false));
|
self.layer_metadata.insert(path.clone(), LayerMetadata::new(false));
|
||||||
|
|
||||||
responses.push_back(LayerChanged(path.clone()).into());
|
responses.push_back(LayerChanged { affected_layer_path: path.clone() }.into());
|
||||||
self.layer_range_selection_reference = path.clone();
|
self.layer_range_selection_reference = path.clone();
|
||||||
responses.push_back(AddSelectedLayers(vec![path.clone()]).into());
|
responses.push_back(
|
||||||
|
AddSelectedLayers {
|
||||||
|
additional_layers: vec![path.clone()],
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
DocumentResponse::DocumentChanged => responses.push_back(RenderDocument.into()),
|
DocumentResponse::DocumentChanged => responses.push_back(RenderDocument.into()),
|
||||||
};
|
};
|
||||||
@@ -596,9 +607,9 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
FlipSelectedLayers(axis) => {
|
FlipSelectedLayers { flip_axis } => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
let scale = match axis {
|
let scale = match flip_axis {
|
||||||
FlipAxis::X => DVec2::new(-1., 1.),
|
FlipAxis::X => DVec2::new(-1., 1.),
|
||||||
FlipAxis::Y => DVec2::new(1., -1.),
|
FlipAxis::Y => DVec2::new(1., -1.),
|
||||||
};
|
};
|
||||||
@@ -618,9 +629,10 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FolderChanged(path) => {
|
FolderChanged { affected_folder_path } => {
|
||||||
let _ = self.graphene_document.render_root(self.view_mode);
|
let _ = self.graphene_document.render_root(self.view_mode);
|
||||||
responses.extend([LayerChanged(path).into(), DocumentStructureChanged.into()]);
|
let affected_layer_path = affected_folder_path;
|
||||||
|
responses.extend([LayerChanged { affected_layer_path }.into(), DocumentStructureChanged.into()]);
|
||||||
}
|
}
|
||||||
GroupSelectedLayers => {
|
GroupSelectedLayers => {
|
||||||
let mut new_folder_path: Vec<u64> = self.graphene_document.shallowest_common_folder(self.selected_layers()).unwrap_or(&[]).to_vec();
|
let mut new_folder_path: Vec<u64> = self.graphene_document.shallowest_common_folder(self.selected_layers()).unwrap_or(&[]).to_vec();
|
||||||
@@ -632,51 +644,58 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
|
|
||||||
new_folder_path.push(generate_uuid());
|
new_folder_path.push(generate_uuid());
|
||||||
|
|
||||||
responses.push_back(PortfolioMessage::Copy(Clipboard::System).into());
|
responses.push_back(PortfolioMessage::Copy { clipboard: Clipboard::System }.into());
|
||||||
responses.push_back(DocumentMessage::DeleteSelectedLayers.into());
|
responses.push_back(DocumentMessage::DeleteSelectedLayers.into());
|
||||||
responses.push_back(DocumentOperation::CreateFolder { path: new_folder_path.clone() }.into());
|
responses.push_back(DocumentOperation::CreateFolder { path: new_folder_path.clone() }.into());
|
||||||
responses.push_back(DocumentMessage::ToggleLayerExpansion(new_folder_path.clone()).into());
|
responses.push_back(DocumentMessage::ToggleLayerExpansion { layer_path: new_folder_path.clone() }.into());
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
PortfolioMessage::PasteIntoFolder {
|
PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::System,
|
clipboard: Clipboard::System,
|
||||||
path: new_folder_path.clone(),
|
folder_path: new_folder_path.clone(),
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
responses.push_back(DocumentMessage::SetSelectedLayers(vec![new_folder_path]).into());
|
responses.push_back(
|
||||||
|
DocumentMessage::SetSelectedLayers {
|
||||||
|
replacement_selected_layers: vec![new_folder_path],
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
LayerChanged(path) => {
|
LayerChanged { affected_layer_path } => {
|
||||||
if let Ok(layer_entry) = self.layer_panel_entry(path) {
|
if let Ok(layer_entry) = self.layer_panel_entry(affected_layer_path) {
|
||||||
responses.push_back(FrontendMessage::UpdateDocumentLayer { data: layer_entry }.into());
|
responses.push_back(FrontendMessage::UpdateDocumentLayer { data: layer_entry }.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Movement(message) => self.movement_handler.process_action(message, (&self.graphene_document, ipp), responses),
|
Movement(message) => self.movement_handler.process_action(message, (&self.graphene_document, ipp), responses),
|
||||||
MoveSelectedLayersTo { path, insert_index } => {
|
MoveSelectedLayersTo { folder_path, insert_index } => {
|
||||||
let layers = self.selected_layers().collect::<Vec<_>>();
|
let selected_layers = self.selected_layers().collect::<Vec<_>>();
|
||||||
|
|
||||||
// Trying to insert into self.
|
// Prevent trying to insert into self
|
||||||
if layers.iter().any(|layer| path.starts_with(layer)) {
|
if selected_layers.iter().any(|layer| folder_path.starts_with(layer)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let insert_index = self.update_insert_index(&layers, &path, insert_index).unwrap();
|
|
||||||
responses.push_back(PortfolioMessage::Copy(Clipboard::System).into());
|
let insert_index = self.update_insert_index(&selected_layers, &folder_path, insert_index).unwrap();
|
||||||
|
|
||||||
|
responses.push_back(PortfolioMessage::Copy { clipboard: Clipboard::System }.into());
|
||||||
responses.push_back(DocumentMessage::DeleteSelectedLayers.into());
|
responses.push_back(DocumentMessage::DeleteSelectedLayers.into());
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
PortfolioMessage::PasteIntoFolder {
|
PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::System,
|
clipboard: Clipboard::System,
|
||||||
path,
|
folder_path,
|
||||||
insert_index,
|
insert_index,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
NudgeSelectedLayers(x, y) => {
|
NudgeSelectedLayers { delta_x, delta_y } => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
for path in self.selected_layers().map(|path| path.to_vec()) {
|
for path in self.selected_layers().map(|path| path.to_vec()) {
|
||||||
let operation = DocumentOperation::TransformLayerInViewport {
|
let operation = DocumentOperation::TransformLayerInViewport {
|
||||||
path,
|
path,
|
||||||
transform: DAffine2::from_translation((x, y).into()).to_cols_array(),
|
transform: DAffine2::from_translation((delta_x, delta_y).into()).to_cols_array(),
|
||||||
};
|
};
|
||||||
responses.push_back(operation.into());
|
responses.push_back(operation.into());
|
||||||
}
|
}
|
||||||
@@ -695,9 +714,9 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
responses.push_back(DocumentHistoryForward.into());
|
responses.push_back(DocumentHistoryForward.into());
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
responses.push_back(RenderDocument.into());
|
responses.push_back(RenderDocument.into());
|
||||||
responses.push_back(FolderChanged(vec![]).into());
|
responses.push_back(FolderChanged { affected_folder_path: vec![] }.into());
|
||||||
}
|
}
|
||||||
RenameLayer(path, name) => responses.push_back(DocumentOperation::RenameLayer { path, name }.into()),
|
RenameLayer { layer_path, new_name } => responses.push_back(DocumentOperation::RenameLayer { layer_path, new_name }.into()),
|
||||||
RenderDocument => {
|
RenderDocument => {
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
FrontendMessage::UpdateDocumentArtwork {
|
FrontendMessage::UpdateDocumentArtwork {
|
||||||
@@ -743,32 +762,55 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ReorderSelectedLayers(relative_position) => {
|
ReorderSelectedLayers { relative_index_offset } => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
|
|
||||||
let all_layer_paths = self.all_layers_sorted();
|
let all_layer_paths = self.all_layers_sorted();
|
||||||
let selected_layers = self.selected_layers_sorted();
|
let selected_layers = self.selected_layers_sorted();
|
||||||
if let Some(pivot) = match relative_position.signum() {
|
|
||||||
|
let first_or_last_selected_layer = match relative_index_offset.signum() {
|
||||||
-1 => selected_layers.first(),
|
-1 => selected_layers.first(),
|
||||||
1 => selected_layers.last(),
|
1 => selected_layers.last(),
|
||||||
_ => unreachable!(),
|
_ => panic!("ReorderSelectedLayers must be given a non-zero value"),
|
||||||
} {
|
};
|
||||||
let all_layer_paths: Vec<_> = all_layer_paths
|
|
||||||
|
if let Some(pivot_layer) = first_or_last_selected_layer {
|
||||||
|
let sibling_layer_paths: Vec<_> = all_layer_paths
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|layer| layer.starts_with(&pivot[0..pivot.len() - 1]) && pivot.len() == layer.len())
|
.filter(|layer| {
|
||||||
|
// Check if this is a sibling of the pivot layer
|
||||||
|
// TODO: Break this out into a reusable function `fn are_layers_siblings(layer_a, layer_b) -> bool`
|
||||||
|
let containing_folder_path = &pivot_layer[0..pivot_layer.len() - 1];
|
||||||
|
layer.starts_with(containing_folder_path) && pivot_layer.len() == layer.len()
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if let Some(pos) = all_layer_paths.iter().position(|path| *path == pivot) {
|
|
||||||
let max = all_layer_paths.len() as i64 - 1;
|
|
||||||
let insert_pos = (pos as i64 + relative_position as i64).clamp(0, max) as usize;
|
|
||||||
let insert = all_layer_paths.get(insert_pos);
|
|
||||||
if let Some(insert_path) = insert {
|
|
||||||
let (id, path) = insert_path.split_last().expect("Can't move the root folder");
|
|
||||||
if let Some(folder) = self.graphene_document.layer(path).ok().and_then(|layer| layer.as_folder().ok()) {
|
|
||||||
let layer_index = folder.layer_ids.iter().position(|comparison_id| comparison_id == id).unwrap() as isize;
|
|
||||||
|
|
||||||
// If moving down, insert below this layer, if moving up, insert above this layer
|
// TODO: Break this out into a reusable function: `fn layer_index_in_containing_folder(layer_path) -> usize`
|
||||||
let insert_index = if relative_position < 0 { layer_index } else { layer_index + 1 };
|
let pivot_index_among_siblings = sibling_layer_paths.iter().position(|path| *path == pivot_layer);
|
||||||
|
|
||||||
responses.push_back(DocumentMessage::MoveSelectedLayersTo { path: path.to_vec(), insert_index }.into());
|
if let Some(pivot_index) = pivot_index_among_siblings {
|
||||||
|
let max = sibling_layer_paths.len() as i64 - 1;
|
||||||
|
let insert_index = (pivot_index as i64 + relative_index_offset as i64).clamp(0, max) as usize;
|
||||||
|
|
||||||
|
let existing_layer_to_insert_beside = sibling_layer_paths.get(insert_index);
|
||||||
|
|
||||||
|
// TODO: Break this block out into a call to a message called `MoveSelectedLayersNextToLayer { neighbor_path, above_or_below }`
|
||||||
|
if let Some(neighbor_path) = existing_layer_to_insert_beside {
|
||||||
|
let (neighbor_id, folder_path) = neighbor_path.split_last().expect("Can't move the root folder");
|
||||||
|
|
||||||
|
if let Some(folder) = self.graphene_document.layer(folder_path).ok().and_then(|layer| layer.as_folder().ok()) {
|
||||||
|
let neighbor_layer_index = folder.layer_ids.iter().position(|id| id == neighbor_id).unwrap() as isize;
|
||||||
|
|
||||||
|
// If moving down, insert below this layer. If moving up, insert above this layer.
|
||||||
|
let insert_index = if relative_index_offset < 0 { neighbor_layer_index } else { neighbor_layer_index + 1 };
|
||||||
|
|
||||||
|
responses.push_back(
|
||||||
|
DocumentMessage::MoveSelectedLayersTo {
|
||||||
|
folder_path: folder_path.to_vec(),
|
||||||
|
insert_index,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -797,14 +839,14 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
SelectAllLayers => {
|
SelectAllLayers => {
|
||||||
let all_layer_paths = self.all_layers();
|
let all = self.all_layers().map(|path| path.to_vec()).collect();
|
||||||
responses.push_front(SetSelectedLayers(all_layer_paths.map(|path| path.to_vec()).collect()).into());
|
responses.push_front(SetSelectedLayers { replacement_selected_layers: all }.into());
|
||||||
}
|
}
|
||||||
SelectionChanged => {
|
SelectionChanged => {
|
||||||
// TODO: Hoist this duplicated code into wider system
|
// TODO: Hoist this duplicated code into wider system
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
}
|
}
|
||||||
SelectLayer(selected, ctrl, shift) => {
|
SelectLayer { layer_path, ctrl, shift } => {
|
||||||
let mut paths = vec![];
|
let mut paths = vec![];
|
||||||
let last_selection_exists = !self.layer_range_selection_reference.is_empty();
|
let last_selection_exists = !self.layer_range_selection_reference.is_empty();
|
||||||
|
|
||||||
@@ -813,47 +855,52 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
// Fill the selection range
|
// Fill the selection range
|
||||||
self.layer_metadata
|
self.layer_metadata
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(target, _)| self.graphene_document.layer_is_between(target, &selected, &self.layer_range_selection_reference))
|
.filter(|(target, _)| self.graphene_document.layer_is_between(target, &layer_path, &self.layer_range_selection_reference))
|
||||||
.for_each(|(layer_path, _)| {
|
.for_each(|(layer_path, _)| {
|
||||||
paths.push(layer_path.clone());
|
paths.push(layer_path.clone());
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if ctrl {
|
if ctrl {
|
||||||
// Toggle selection when holding ctrl
|
// Toggle selection when holding ctrl
|
||||||
let layer = self.layer_metadata_mut(&selected);
|
let layer = self.layer_metadata_mut(&layer_path);
|
||||||
layer.selected = !layer.selected;
|
layer.selected = !layer.selected;
|
||||||
responses.push_back(LayerChanged(selected.clone()).into());
|
responses.push_back(
|
||||||
|
LayerChanged {
|
||||||
|
affected_layer_path: layer_path.clone(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
} else {
|
} else {
|
||||||
paths.push(selected.clone());
|
paths.push(layer_path.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set our last selection reference
|
// Set our last selection reference
|
||||||
self.layer_range_selection_reference = selected;
|
self.layer_range_selection_reference = layer_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't create messages for empty operations
|
// Don't create messages for empty operations
|
||||||
if !paths.is_empty() {
|
if !paths.is_empty() {
|
||||||
// Add or set our selected layers
|
// Add or set our selected layers
|
||||||
if ctrl {
|
if ctrl {
|
||||||
responses.push_front(AddSelectedLayers(paths).into());
|
responses.push_front(AddSelectedLayers { additional_layers: paths }.into());
|
||||||
} else {
|
} else {
|
||||||
responses.push_front(SetSelectedLayers(paths).into());
|
responses.push_front(SetSelectedLayers { replacement_selected_layers: paths }.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetBlendModeForSelectedLayers(blend_mode) => {
|
SetBlendModeForSelectedLayers { blend_mode } => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
for path in self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then(|| path.clone())) {
|
for path in self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then(|| path.clone())) {
|
||||||
responses.push_back(DocumentOperation::SetLayerBlendMode { path, blend_mode }.into());
|
responses.push_back(DocumentOperation::SetLayerBlendMode { path, blend_mode }.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetLayerExpansion(path, is_expanded) => {
|
SetLayerExpansion { layer_path, set_expanded } => {
|
||||||
self.layer_metadata_mut(&path).expanded = is_expanded;
|
self.layer_metadata_mut(&layer_path).expanded = set_expanded;
|
||||||
responses.push_back(DocumentStructureChanged.into());
|
responses.push_back(DocumentStructureChanged.into());
|
||||||
responses.push_back(LayerChanged(path).into())
|
responses.push_back(LayerChanged { affected_layer_path: layer_path }.into())
|
||||||
}
|
}
|
||||||
SetOpacityForSelectedLayers(opacity) => {
|
SetOpacityForSelectedLayers { opacity } => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
let opacity = opacity.clamp(0., 1.);
|
let opacity = opacity.clamp(0., 1.);
|
||||||
|
|
||||||
@@ -861,30 +908,31 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
responses.push_back(DocumentOperation::SetLayerOpacity { path, opacity }.into());
|
responses.push_back(DocumentOperation::SetLayerOpacity { path, opacity }.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetSelectedLayers(paths) => {
|
SetSelectedLayers { replacement_selected_layers } => {
|
||||||
let selected = self.layer_metadata.iter_mut().filter(|(_, layer_metadata)| layer_metadata.selected);
|
let selected = self.layer_metadata.iter_mut().filter(|(_, layer_metadata)| layer_metadata.selected);
|
||||||
selected.for_each(|(path, layer_metadata)| {
|
selected.for_each(|(path, layer_metadata)| {
|
||||||
layer_metadata.selected = false;
|
layer_metadata.selected = false;
|
||||||
responses.push_back(LayerChanged(path.clone()).into())
|
responses.push_back(LayerChanged { affected_layer_path: path.clone() }.into())
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.push_front(AddSelectedLayers(paths).into());
|
let additional_layers = replacement_selected_layers;
|
||||||
|
responses.push_front(AddSelectedLayers { additional_layers }.into());
|
||||||
}
|
}
|
||||||
SetSnapping(new_status) => {
|
SetSnapping { snap } => {
|
||||||
self.snapping_enabled = new_status;
|
self.snapping_enabled = snap;
|
||||||
}
|
}
|
||||||
SetViewMode(mode) => {
|
SetViewMode { view_mode } => {
|
||||||
self.view_mode = mode;
|
self.view_mode = view_mode;
|
||||||
responses.push_front(DocumentMessage::DirtyRenderDocument.into());
|
responses.push_front(DocumentMessage::DirtyRenderDocument.into());
|
||||||
}
|
}
|
||||||
StartTransaction => self.backup(responses),
|
StartTransaction => self.backup(responses),
|
||||||
ToggleLayerExpansion(path) => {
|
ToggleLayerExpansion { layer_path } => {
|
||||||
self.layer_metadata_mut(&path).expanded ^= true;
|
self.layer_metadata_mut(&layer_path).expanded ^= true;
|
||||||
responses.push_back(DocumentStructureChanged.into());
|
responses.push_back(DocumentStructureChanged.into());
|
||||||
responses.push_back(LayerChanged(path).into())
|
responses.push_back(LayerChanged { affected_layer_path: layer_path }.into())
|
||||||
}
|
}
|
||||||
ToggleLayerVisibility(path) => {
|
ToggleLayerVisibility { layer_path } => {
|
||||||
responses.push_back(DocumentOperation::ToggleLayerVisibility { path }.into());
|
responses.push_back(DocumentOperation::ToggleLayerVisibility { path: layer_path }.into());
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
}
|
}
|
||||||
TransformLayers(message) => self
|
TransformLayers(message) => self
|
||||||
@@ -895,24 +943,26 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
responses.push_back(DocumentHistoryBackward.into());
|
responses.push_back(DocumentHistoryBackward.into());
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
responses.push_back(RenderDocument.into());
|
responses.push_back(RenderDocument.into());
|
||||||
responses.push_back(FolderChanged(vec![]).into());
|
responses.push_back(FolderChanged { affected_folder_path: vec![] }.into());
|
||||||
}
|
}
|
||||||
UngroupLayers(folder_path) => {
|
UngroupLayers { folder_path } => {
|
||||||
// Select all the children of the folder
|
// Select all the children of the folder
|
||||||
let to_select = self.graphene_document.folder_children_paths(&folder_path);
|
let select = self.graphene_document.folder_children_paths(&folder_path);
|
||||||
|
|
||||||
let message_buffer = [
|
let message_buffer = [
|
||||||
|
// Select them
|
||||||
|
DocumentMessage::SetSelectedLayers { replacement_selected_layers: select }.into(),
|
||||||
// Copy them
|
// Copy them
|
||||||
DocumentMessage::SetSelectedLayers(to_select).into(),
|
PortfolioMessage::Copy { clipboard: Clipboard::System }.into(),
|
||||||
PortfolioMessage::Copy(Clipboard::System).into(),
|
|
||||||
// Paste them into the folder above
|
// Paste them into the folder above
|
||||||
PortfolioMessage::PasteIntoFolder {
|
PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::System,
|
clipboard: Clipboard::System,
|
||||||
path: folder_path[..folder_path.len() - 1].to_vec(),
|
folder_path: folder_path[..folder_path.len() - 1].to_vec(),
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
// Delete parent folder
|
// Delete the parent folder
|
||||||
DocumentMessage::DeleteLayer(folder_path).into(),
|
DocumentMessage::DeleteLayer { layer_path: folder_path }.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Push these messages in reverse due to push_front
|
// Push these messages in reverse due to push_front
|
||||||
@@ -924,12 +974,12 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
|||||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||||
let folder_paths = self.graphene_document.sorted_folders_by_depth(self.selected_layers());
|
let folder_paths = self.graphene_document.sorted_folders_by_depth(self.selected_layers());
|
||||||
for folder_path in folder_paths {
|
for folder_path in folder_paths {
|
||||||
responses.push_back(DocumentMessage::UngroupLayers(folder_path.to_vec()).into());
|
responses.push_back(DocumentMessage::UngroupLayers { folder_path: folder_path.to_vec() }.into());
|
||||||
}
|
}
|
||||||
responses.push_back(DocumentMessage::CommitTransaction.into());
|
responses.push_back(DocumentMessage::CommitTransaction.into());
|
||||||
}
|
}
|
||||||
UpdateLayerMetadata { layer_path: path, layer_metadata } => {
|
UpdateLayerMetadata { layer_path, layer_metadata } => {
|
||||||
self.layer_metadata.insert(path, layer_metadata);
|
self.layer_metadata.insert(layer_path, layer_metadata);
|
||||||
}
|
}
|
||||||
ZoomCanvasToFitAll => {
|
ZoomCanvasToFitAll => {
|
||||||
if let Some(bounds) = self.document_bounds() {
|
if let Some(bounds) = self.document_bounds() {
|
||||||
|
|||||||
@@ -26,12 +26,20 @@ pub enum MovementMessage {
|
|||||||
zoom_from_viewport: Option<DVec2>,
|
zoom_from_viewport: Option<DVec2>,
|
||||||
},
|
},
|
||||||
RotateCanvasBegin,
|
RotateCanvasBegin,
|
||||||
SetCanvasRotation(f64),
|
SetCanvasRotation {
|
||||||
SetCanvasZoom(f64),
|
angle_radians: f64,
|
||||||
|
},
|
||||||
|
SetCanvasZoom {
|
||||||
|
zoom_factor: f64,
|
||||||
|
},
|
||||||
TransformCanvasEnd,
|
TransformCanvasEnd,
|
||||||
TranslateCanvas(DVec2),
|
TranslateCanvas {
|
||||||
|
delta: DVec2,
|
||||||
|
},
|
||||||
TranslateCanvasBegin,
|
TranslateCanvasBegin,
|
||||||
TranslateCanvasByViewportFraction(DVec2),
|
TranslateCanvasByViewportFraction {
|
||||||
|
delta: DVec2,
|
||||||
|
},
|
||||||
WheelCanvasTranslate {
|
WheelCanvasTranslate {
|
||||||
use_y_as_x: bool,
|
use_y_as_x: bool,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ impl MovementMessageHandler {
|
|||||||
let mouse_fraction = mouse / viewport_bounds;
|
let mouse_fraction = mouse / viewport_bounds;
|
||||||
let delta = delta_size * (DVec2::splat(0.5) - mouse_fraction);
|
let delta = delta_size * (DVec2::splat(0.5) - mouse_fraction);
|
||||||
|
|
||||||
MovementMessage::TranslateCanvas(delta).into()
|
MovementMessage::TranslateCanvas { delta }.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
if center_on_mouse {
|
if center_on_mouse {
|
||||||
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), new_scale / self.zoom, ipp.mouse.position));
|
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), new_scale / self.zoom, ipp.mouse.position));
|
||||||
}
|
}
|
||||||
responses.push_back(SetCanvasZoom(new_scale).into());
|
responses.push_back(SetCanvasZoom { zoom_factor: new_scale }.into());
|
||||||
}
|
}
|
||||||
FitViewportToBounds {
|
FitViewportToBounds {
|
||||||
bounds: [bounds_corner_a, bounds_corner_b],
|
bounds: [bounds_corner_a, bounds_corner_b],
|
||||||
@@ -158,7 +158,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
if center_on_mouse {
|
if center_on_mouse {
|
||||||
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), new_scale / self.zoom, ipp.mouse.position));
|
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), new_scale / self.zoom, ipp.mouse.position));
|
||||||
}
|
}
|
||||||
responses.push_back(SetCanvasZoom(new_scale).into());
|
responses.push_back(SetCanvasZoom { zoom_factor: new_scale }.into());
|
||||||
}
|
}
|
||||||
MouseMove {
|
MouseMove {
|
||||||
snap_angle,
|
snap_angle,
|
||||||
@@ -169,7 +169,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
if self.panning {
|
if self.panning {
|
||||||
let delta = ipp.mouse.position - self.mouse_position;
|
let delta = ipp.mouse.position - self.mouse_position;
|
||||||
|
|
||||||
responses.push_back(TranslateCanvas(delta).into());
|
responses.push_back(TranslateCanvas { delta }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tilting {
|
if self.tilting {
|
||||||
@@ -190,7 +190,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
start_vec.angle_between(end_vec)
|
start_vec.angle_between(end_vec)
|
||||||
};
|
};
|
||||||
|
|
||||||
responses.push_back(SetCanvasRotation(self.tilt + rotation).into());
|
responses.push_back(SetCanvasRotation { angle_radians: self.tilt + rotation }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.zooming {
|
if self.zooming {
|
||||||
@@ -210,10 +210,10 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
if let Some(mouse) = zoom_from_viewport {
|
if let Some(mouse) = zoom_from_viewport {
|
||||||
let zoom_factor = self.snapped_scale() / zoom_start;
|
let zoom_factor = self.snapped_scale() / zoom_start;
|
||||||
|
|
||||||
responses.push_back(SetCanvasZoom(self.zoom).into());
|
responses.push_back(SetCanvasZoom { zoom_factor: self.zoom }.into());
|
||||||
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, mouse));
|
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, mouse));
|
||||||
} else {
|
} else {
|
||||||
responses.push_back(SetCanvasZoom(self.zoom).into());
|
responses.push_back(SetCanvasZoom { zoom_factor: self.zoom }.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.mouse_position = ipp.mouse.position;
|
self.mouse_position = ipp.mouse.position;
|
||||||
@@ -222,14 +222,14 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
self.tilting = true;
|
self.tilting = true;
|
||||||
self.mouse_position = ipp.mouse.position;
|
self.mouse_position = ipp.mouse.position;
|
||||||
}
|
}
|
||||||
SetCanvasRotation(new_radians) => {
|
SetCanvasRotation { angle_radians } => {
|
||||||
self.tilt = new_radians;
|
self.tilt = angle_radians;
|
||||||
self.create_document_transform(&ipp.viewport_bounds, responses);
|
self.create_document_transform(&ipp.viewport_bounds, responses);
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
responses.push_back(FrontendMessage::UpdateCanvasRotation { angle_radians: self.snapped_angle() }.into());
|
responses.push_back(FrontendMessage::UpdateCanvasRotation { angle_radians: self.snapped_angle() }.into());
|
||||||
}
|
}
|
||||||
SetCanvasZoom(new) => {
|
SetCanvasZoom { zoom_factor } => {
|
||||||
self.zoom = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
|
self.zoom = zoom_factor.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
|
||||||
responses.push_back(FrontendMessage::UpdateCanvasZoom { factor: self.snapped_scale() }.into());
|
responses.push_back(FrontendMessage::UpdateCanvasZoom { factor: self.snapped_scale() }.into());
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
||||||
@@ -246,7 +246,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
self.tilting = false;
|
self.tilting = false;
|
||||||
self.zooming = false;
|
self.zooming = false;
|
||||||
}
|
}
|
||||||
TranslateCanvas(delta) => {
|
TranslateCanvas { delta } => {
|
||||||
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
|
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
|
||||||
|
|
||||||
self.pan += transformed_delta;
|
self.pan += transformed_delta;
|
||||||
@@ -257,7 +257,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
self.panning = true;
|
self.panning = true;
|
||||||
self.mouse_position = ipp.mouse.position;
|
self.mouse_position = ipp.mouse.position;
|
||||||
}
|
}
|
||||||
TranslateCanvasByViewportFraction(delta) => {
|
TranslateCanvasByViewportFraction { delta } => {
|
||||||
let transformed_delta = document.root.transform.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
|
let transformed_delta = document.root.transform.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
|
||||||
|
|
||||||
self.pan += transformed_delta;
|
self.pan += transformed_delta;
|
||||||
@@ -269,7 +269,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
false => -ipp.mouse.scroll_delta.as_dvec2(),
|
false => -ipp.mouse.scroll_delta.as_dvec2(),
|
||||||
true => (-ipp.mouse.scroll_delta.y as f64, 0.).into(),
|
true => (-ipp.mouse.scroll_delta.y as f64, 0.).into(),
|
||||||
} * VIEWPORT_SCROLL_RATE;
|
} * VIEWPORT_SCROLL_RATE;
|
||||||
responses.push_back(TranslateCanvas(delta).into());
|
responses.push_back(TranslateCanvas { delta }.into());
|
||||||
}
|
}
|
||||||
WheelCanvasZoom => {
|
WheelCanvasZoom => {
|
||||||
let scroll = ipp.mouse.scroll_delta.scroll_delta();
|
let scroll = ipp.mouse.scroll_delta.scroll_delta();
|
||||||
@@ -279,7 +279,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
|||||||
};
|
};
|
||||||
|
|
||||||
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, ipp.mouse.position));
|
responses.push_back(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, ipp.mouse.position));
|
||||||
responses.push_back(SetCanvasZoom(self.zoom * zoom_factor).into());
|
responses.push_back(SetCanvasZoom { zoom_factor: self.zoom * zoom_factor }.into());
|
||||||
}
|
}
|
||||||
ZoomCanvasBegin => {
|
ZoomCanvasBegin => {
|
||||||
self.zooming = true;
|
self.zooming = true;
|
||||||
|
|||||||
@@ -10,14 +10,24 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum PortfolioMessage {
|
pub enum PortfolioMessage {
|
||||||
AutoSaveActiveDocument,
|
AutoSaveActiveDocument,
|
||||||
AutoSaveDocument(u64),
|
AutoSaveDocument {
|
||||||
|
document_id: u64,
|
||||||
|
},
|
||||||
CloseActiveDocumentWithConfirmation,
|
CloseActiveDocumentWithConfirmation,
|
||||||
CloseAllDocuments,
|
CloseAllDocuments,
|
||||||
CloseAllDocumentsWithConfirmation,
|
CloseAllDocumentsWithConfirmation,
|
||||||
CloseDocument(u64),
|
CloseDocument {
|
||||||
CloseDocumentWithConfirmation(u64),
|
document_id: u64,
|
||||||
Copy(Clipboard),
|
},
|
||||||
Cut(Clipboard),
|
CloseDocumentWithConfirmation {
|
||||||
|
document_id: u64,
|
||||||
|
},
|
||||||
|
Copy {
|
||||||
|
clipboard: Clipboard,
|
||||||
|
},
|
||||||
|
Cut {
|
||||||
|
clipboard: Clipboard,
|
||||||
|
},
|
||||||
#[child]
|
#[child]
|
||||||
Document(DocumentMessage),
|
Document(DocumentMessage),
|
||||||
NewDocument,
|
NewDocument,
|
||||||
@@ -25,19 +35,23 @@ pub enum PortfolioMessage {
|
|||||||
OpenDocument,
|
OpenDocument,
|
||||||
OpenDocumentFile(String, String),
|
OpenDocumentFile(String, String),
|
||||||
OpenDocumentFileWithId {
|
OpenDocumentFileWithId {
|
||||||
document: String,
|
|
||||||
document_name: String,
|
|
||||||
document_id: u64,
|
document_id: u64,
|
||||||
|
document_name: String,
|
||||||
document_is_saved: bool,
|
document_is_saved: bool,
|
||||||
|
document_serialized_content: String,
|
||||||
|
},
|
||||||
|
Paste {
|
||||||
|
clipboard: Clipboard,
|
||||||
},
|
},
|
||||||
Paste(Clipboard),
|
|
||||||
PasteIntoFolder {
|
PasteIntoFolder {
|
||||||
clipboard: Clipboard,
|
clipboard: Clipboard,
|
||||||
path: Vec<LayerId>,
|
folder_path: Vec<LayerId>,
|
||||||
insert_index: isize,
|
insert_index: isize,
|
||||||
},
|
},
|
||||||
PrevDocument,
|
PrevDocument,
|
||||||
RequestAboutGraphiteDialog,
|
RequestAboutGraphiteDialog,
|
||||||
SelectDocument(u64),
|
SelectDocument {
|
||||||
|
document_id: u64,
|
||||||
|
},
|
||||||
UpdateOpenDocumentsList,
|
UpdateOpenDocumentsList,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ impl PortfolioMessageHandler {
|
|||||||
fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: u64, replace_first_empty: bool, responses: &mut VecDeque<Message>) {
|
fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: u64, replace_first_empty: bool, responses: &mut VecDeque<Message>) {
|
||||||
// Special case when loading a document on an empty page
|
// Special case when loading a document on an empty page
|
||||||
if replace_first_empty && self.active_document().is_unmodified_default() {
|
if replace_first_empty && self.active_document().is_unmodified_default() {
|
||||||
responses.push_back(PortfolioMessage::CloseDocument(self.active_document_id).into());
|
responses.push_back(PortfolioMessage::CloseDocument { document_id: self.active_document_id }.into());
|
||||||
|
|
||||||
let active_document_index = self
|
let active_document_index = self
|
||||||
.document_ids
|
.document_ids
|
||||||
@@ -92,7 +92,7 @@ impl PortfolioMessageHandler {
|
|||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
||||||
|
|
||||||
responses.push_back(PortfolioMessage::SelectDocument(document_id).into());
|
responses.push_back(PortfolioMessage::SelectDocument { document_id }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over the open documents in order.
|
/// Returns an iterator over the open documents in order.
|
||||||
@@ -129,15 +129,15 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
use PortfolioMessage::*;
|
use PortfolioMessage::*;
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
match message {
|
match message {
|
||||||
AutoSaveActiveDocument => responses.push_back(PortfolioMessage::AutoSaveDocument(self.active_document_id).into()),
|
AutoSaveActiveDocument => responses.push_back(PortfolioMessage::AutoSaveDocument { document_id: self.active_document_id }.into()),
|
||||||
AutoSaveDocument(id) => {
|
AutoSaveDocument { document_id } => {
|
||||||
let document = self.documents.get(&id).unwrap();
|
let document = self.documents.get(&document_id).unwrap();
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
FrontendMessage::TriggerIndexedDbWriteDocument {
|
FrontendMessage::TriggerIndexedDbWriteDocument {
|
||||||
document: document.serialize_document(),
|
document: document.serialize_document(),
|
||||||
details: FrontendDocumentDetails {
|
details: FrontendDocumentDetails {
|
||||||
is_saved: document.is_saved(),
|
is_saved: document.is_saved(),
|
||||||
id,
|
id: document_id,
|
||||||
name: document.name.clone(),
|
name: document.name.clone(),
|
||||||
},
|
},
|
||||||
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
|
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
|
||||||
@@ -146,7 +146,7 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
CloseActiveDocumentWithConfirmation => {
|
CloseActiveDocumentWithConfirmation => {
|
||||||
responses.push_back(PortfolioMessage::CloseDocumentWithConfirmation(self.active_document_id).into());
|
responses.push_back(PortfolioMessage::CloseDocumentWithConfirmation { document_id: self.active_document_id }.into());
|
||||||
}
|
}
|
||||||
CloseAllDocuments => {
|
CloseAllDocuments => {
|
||||||
// Empty the list of internal document data
|
// Empty the list of internal document data
|
||||||
@@ -159,9 +159,9 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
CloseAllDocumentsWithConfirmation => {
|
CloseAllDocumentsWithConfirmation => {
|
||||||
responses.push_back(FrontendMessage::DisplayConfirmationToCloseAllDocuments.into());
|
responses.push_back(FrontendMessage::DisplayConfirmationToCloseAllDocuments.into());
|
||||||
}
|
}
|
||||||
CloseDocument(id) => {
|
CloseDocument { document_id } => {
|
||||||
let document_index = self.document_index(id);
|
let document_index = self.document_index(document_id);
|
||||||
self.documents.remove(&id);
|
self.documents.remove(&document_id);
|
||||||
self.document_ids.remove(document_index);
|
self.document_ids.remove(document_index);
|
||||||
|
|
||||||
// Last tab was closed, so create a new blank tab
|
// Last tab was closed, so create a new blank tab
|
||||||
@@ -171,7 +171,7 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
self.documents.insert(new_id, DocumentMessageHandler::default());
|
self.documents.insert(new_id, DocumentMessageHandler::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.active_document_id = if id != self.active_document_id {
|
self.active_document_id = if document_id != self.active_document_id {
|
||||||
// If we are not closing the active document, stay on it
|
// If we are not closing the active document, stay on it
|
||||||
self.active_document_id
|
self.active_document_id
|
||||||
} else if document_index >= self.document_ids.len() {
|
} else if document_index >= self.document_ids.len() {
|
||||||
@@ -197,24 +197,24 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
|
|
||||||
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
|
||||||
responses.push_back(FrontendMessage::UpdateActiveDocument { document_id: self.active_document_id }.into());
|
responses.push_back(FrontendMessage::UpdateActiveDocument { document_id: self.active_document_id }.into());
|
||||||
responses.push_back(FrontendMessage::TriggerIndexedDbRemoveDocument { document_id: id }.into());
|
responses.push_back(FrontendMessage::TriggerIndexedDbRemoveDocument { document_id }.into());
|
||||||
responses.push_back(RenderDocument.into());
|
responses.push_back(RenderDocument.into());
|
||||||
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
||||||
for layer in self.active_document().layer_metadata.keys() {
|
for layer in self.active_document().layer_metadata.keys() {
|
||||||
responses.push_back(DocumentMessage::LayerChanged(layer.clone()).into());
|
responses.push_back(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseDocumentWithConfirmation(id) => {
|
CloseDocumentWithConfirmation { document_id } => {
|
||||||
let target_document = self.documents.get(&id).unwrap();
|
let target_document = self.documents.get(&document_id).unwrap();
|
||||||
if target_document.is_saved() {
|
if target_document.is_saved() {
|
||||||
responses.push_back(PortfolioMessage::CloseDocument(id).into());
|
responses.push_back(PortfolioMessage::CloseDocument { document_id }.into());
|
||||||
} else {
|
} else {
|
||||||
responses.push_back(FrontendMessage::DisplayConfirmationToCloseDocument { document_id: id }.into());
|
responses.push_back(FrontendMessage::DisplayConfirmationToCloseDocument { document_id }.into());
|
||||||
// Select the document being closed
|
// Select the document being closed
|
||||||
responses.push_back(PortfolioMessage::SelectDocument(id).into());
|
responses.push_back(PortfolioMessage::SelectDocument { document_id }.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Copy(clipboard) => {
|
Copy { clipboard } => {
|
||||||
// We can't use `self.active_document()` because it counts as an immutable borrow of the entirety of `self`
|
// We can't use `self.active_document()` because it counts as an immutable borrow of the entirety of `self`
|
||||||
let active_document = self.documents.get(&self.active_document_id).unwrap();
|
let active_document = self.documents.get(&self.active_document_id).unwrap();
|
||||||
|
|
||||||
@@ -230,8 +230,8 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cut(clipboard) => {
|
Cut { clipboard } => {
|
||||||
responses.push_back(Copy(clipboard).into());
|
responses.push_back(Copy { clipboard }.into());
|
||||||
responses.push_back(DeleteSelectedLayers.into());
|
responses.push_back(DeleteSelectedLayers.into());
|
||||||
}
|
}
|
||||||
Document(message) => self.active_document_mut().process_action(message, ipp, responses),
|
Document(message) => self.active_document_mut().process_action(message, ipp, responses),
|
||||||
@@ -246,29 +246,29 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
let current_index = self.document_index(self.active_document_id);
|
let current_index = self.document_index(self.active_document_id);
|
||||||
let next_index = (current_index + 1) % self.document_ids.len();
|
let next_index = (current_index + 1) % self.document_ids.len();
|
||||||
let next_id = self.document_ids[next_index];
|
let next_id = self.document_ids[next_index];
|
||||||
responses.push_back(PortfolioMessage::SelectDocument(next_id).into());
|
responses.push_back(PortfolioMessage::SelectDocument { document_id: next_id }.into());
|
||||||
}
|
}
|
||||||
OpenDocument => {
|
OpenDocument => {
|
||||||
responses.push_back(FrontendMessage::TriggerFileUpload.into());
|
responses.push_back(FrontendMessage::TriggerFileUpload.into());
|
||||||
}
|
}
|
||||||
OpenDocumentFile(document_name, document) => {
|
OpenDocumentFile(document_name, document_serialized_content) => {
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
PortfolioMessage::OpenDocumentFileWithId {
|
PortfolioMessage::OpenDocumentFileWithId {
|
||||||
document,
|
|
||||||
document_name,
|
|
||||||
document_id: generate_uuid(),
|
document_id: generate_uuid(),
|
||||||
|
document_name,
|
||||||
document_is_saved: true,
|
document_is_saved: true,
|
||||||
|
document_serialized_content,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
OpenDocumentFileWithId {
|
OpenDocumentFileWithId {
|
||||||
document_name,
|
|
||||||
document_id,
|
document_id,
|
||||||
document,
|
document_name,
|
||||||
document_is_saved,
|
document_is_saved,
|
||||||
|
document_serialized_content,
|
||||||
} => {
|
} => {
|
||||||
let document = DocumentMessageHandler::with_name_and_content(document_name, document);
|
let document = DocumentMessageHandler::with_name_and_content(document_name, document_serialized_content);
|
||||||
match document {
|
match document {
|
||||||
Ok(mut document) => {
|
Ok(mut document) => {
|
||||||
document.set_save_state(document_is_saved);
|
document.set_save_state(document_is_saved);
|
||||||
@@ -283,7 +283,7 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Paste(clipboard) => {
|
Paste { clipboard } => {
|
||||||
let document = self.active_document();
|
let document = self.active_document();
|
||||||
let shallowest_common_folder = document
|
let shallowest_common_folder = document
|
||||||
.graphene_document
|
.graphene_document
|
||||||
@@ -294,14 +294,18 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
responses.push_back(
|
responses.push_back(
|
||||||
PasteIntoFolder {
|
PasteIntoFolder {
|
||||||
clipboard,
|
clipboard,
|
||||||
path: shallowest_common_folder.to_vec(),
|
folder_path: shallowest_common_folder.to_vec(),
|
||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
responses.push_back(CommitTransaction.into());
|
responses.push_back(CommitTransaction.into());
|
||||||
}
|
}
|
||||||
PasteIntoFolder { clipboard, path, insert_index } => {
|
PasteIntoFolder {
|
||||||
|
clipboard,
|
||||||
|
folder_path: path,
|
||||||
|
insert_index,
|
||||||
|
} => {
|
||||||
let paste = |entry: &CopyBufferEntry, responses: &mut VecDeque<_>| {
|
let paste = |entry: &CopyBufferEntry, responses: &mut VecDeque<_>| {
|
||||||
log::trace!("Pasting into folder {:?} as index: {}", &path, insert_index);
|
log::trace!("Pasting into folder {:?} as index: {}", &path, insert_index);
|
||||||
|
|
||||||
@@ -339,22 +343,22 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
|||||||
let current_index = self.document_index(self.active_document_id);
|
let current_index = self.document_index(self.active_document_id);
|
||||||
let prev_index = (current_index + len - 1) % len;
|
let prev_index = (current_index + len - 1) % len;
|
||||||
let prev_id = self.document_ids[prev_index];
|
let prev_id = self.document_ids[prev_index];
|
||||||
responses.push_back(PortfolioMessage::SelectDocument(prev_id).into());
|
responses.push_back(PortfolioMessage::SelectDocument { document_id: prev_id }.into());
|
||||||
}
|
}
|
||||||
RequestAboutGraphiteDialog => {
|
RequestAboutGraphiteDialog => {
|
||||||
responses.push_back(FrontendMessage::DisplayDialogAboutGraphite.into());
|
responses.push_back(FrontendMessage::DisplayDialogAboutGraphite.into());
|
||||||
}
|
}
|
||||||
SelectDocument(id) => {
|
SelectDocument { document_id } => {
|
||||||
let active_document = self.active_document();
|
let active_document = self.active_document();
|
||||||
if !active_document.is_saved() {
|
if !active_document.is_saved() {
|
||||||
responses.push_back(PortfolioMessage::AutoSaveDocument(self.active_document_id).into());
|
responses.push_back(PortfolioMessage::AutoSaveDocument { document_id: self.active_document_id }.into());
|
||||||
}
|
}
|
||||||
self.active_document_id = id;
|
self.active_document_id = document_id;
|
||||||
responses.push_back(FrontendMessage::UpdateActiveDocument { document_id: id }.into());
|
responses.push_back(FrontendMessage::UpdateActiveDocument { document_id }.into());
|
||||||
responses.push_back(RenderDocument.into());
|
responses.push_back(RenderDocument.into());
|
||||||
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
||||||
for layer in self.active_document().layer_metadata.keys() {
|
for layer in self.active_document().layer_metadata.keys() {
|
||||||
responses.push_back(DocumentMessage::LayerChanged(layer.clone()).into());
|
responses.push_back(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }.into());
|
||||||
}
|
}
|
||||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ pub enum TransformLayerMessage {
|
|||||||
MouseMove { slow_key: Key, snap_key: Key },
|
MouseMove { slow_key: Key, snap_key: Key },
|
||||||
TypeBackspace,
|
TypeBackspace,
|
||||||
TypeDecimalPoint,
|
TypeDecimalPoint,
|
||||||
|
TypeDigit { digit: u8 },
|
||||||
TypeNegate,
|
TypeNegate,
|
||||||
TypeNumber(u8),
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,8 +157,8 @@ impl MessageHandler<TransformLayerMessage, (&mut HashMap<Vec<LayerId>, LayerMeta
|
|||||||
}
|
}
|
||||||
TypeBackspace => self.transform_operation.handle_typed(self.typing.type_backspace(), &mut selected, self.snap),
|
TypeBackspace => self.transform_operation.handle_typed(self.typing.type_backspace(), &mut selected, self.snap),
|
||||||
TypeDecimalPoint => self.transform_operation.handle_typed(self.typing.type_decimal_point(), &mut selected, self.snap),
|
TypeDecimalPoint => self.transform_operation.handle_typed(self.typing.type_decimal_point(), &mut selected, self.snap),
|
||||||
|
TypeDigit { digit } => self.transform_operation.handle_typed(self.typing.type_number(digit), &mut selected, self.snap),
|
||||||
TypeNegate => self.transform_operation.handle_typed(self.typing.type_negate(), &mut selected, self.snap),
|
TypeNegate => self.transform_operation.handle_typed(self.typing.type_negate(), &mut selected, self.snap),
|
||||||
TypeNumber(number) => self.transform_operation.handle_typed(self.typing.type_number(number), &mut selected, self.snap),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ impl MessageHandler<TransformLayerMessage, (&mut HashMap<Vec<LayerId>, LayerMeta
|
|||||||
MouseMove,
|
MouseMove,
|
||||||
CancelTransformOperation,
|
CancelTransformOperation,
|
||||||
ApplyTransformOperation,
|
ApplyTransformOperation,
|
||||||
TypeNumber,
|
TypeDigit,
|
||||||
TypeBackspace,
|
TypeBackspace,
|
||||||
TypeDecimalPoint,
|
TypeDecimalPoint,
|
||||||
TypeNegate,
|
TypeNegate,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ impl Default for Mapping {
|
|||||||
|
|
||||||
let mappings = mapping![
|
let mappings = mapping![
|
||||||
// Higher priority than entries in sections below
|
// Higher priority than entries in sections below
|
||||||
entry! {action=PortfolioMessage::Paste(Clipboard::User), key_down=KeyV, modifiers=[KeyControl]},
|
entry! {action=PortfolioMessage::Paste { clipboard: Clipboard::User }, key_down=KeyV, modifiers=[KeyControl]},
|
||||||
// Transform layers
|
// Transform layers
|
||||||
entry! {action=TransformLayerMessage::ApplyTransformOperation, key_down=KeyEnter},
|
entry! {action=TransformLayerMessage::ApplyTransformOperation, key_down=KeyEnter},
|
||||||
entry! {action=TransformLayerMessage::ApplyTransformOperation, key_down=Lmb},
|
entry! {action=TransformLayerMessage::ApplyTransformOperation, key_down=Lmb},
|
||||||
@@ -98,28 +98,28 @@ impl Default for Mapping {
|
|||||||
entry! {action=FillMessage::LeftMouseDown, key_down=Lmb},
|
entry! {action=FillMessage::LeftMouseDown, key_down=Lmb},
|
||||||
entry! {action=FillMessage::RightMouseDown, key_down=Rmb},
|
entry! {action=FillMessage::RightMouseDown, key_down=Rmb},
|
||||||
// Tool Actions
|
// Tool Actions
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Select), key_down=KeyV},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Select }, key_down=KeyV},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Navigate), key_down=KeyZ},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Navigate }, key_down=KeyZ},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Eyedropper), key_down=KeyI},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Eyedropper }, key_down=KeyI},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Fill), key_down=KeyF},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Fill }, key_down=KeyF},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Path), key_down=KeyA},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Path }, key_down=KeyA},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Pen), key_down=KeyP},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Pen }, key_down=KeyP},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Line), key_down=KeyL},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Line }, key_down=KeyL},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Rectangle), key_down=KeyM},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Rectangle }, key_down=KeyM},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Ellipse), key_down=KeyE},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Ellipse }, key_down=KeyE},
|
||||||
entry! {action=ToolMessage::ActivateTool(ToolType::Shape), key_down=KeyY},
|
entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Shape }, key_down=KeyY},
|
||||||
// Colors
|
// Colors
|
||||||
entry! {action=ToolMessage::ResetColors, key_down=KeyX, modifiers=[KeyShift, KeyControl]},
|
entry! {action=ToolMessage::ResetColors, key_down=KeyX, modifiers=[KeyShift, KeyControl]},
|
||||||
entry! {action=ToolMessage::SwapColors, key_down=KeyX, modifiers=[KeyShift]},
|
entry! {action=ToolMessage::SwapColors, key_down=KeyX, modifiers=[KeyShift]},
|
||||||
// Editor Actions
|
// Editor Actions
|
||||||
entry! {action=FrontendMessage::TriggerFileUpload, key_down=KeyO, modifiers=[KeyControl]},
|
entry! {action=FrontendMessage::TriggerFileUpload, key_down=KeyO, modifiers=[KeyControl]},
|
||||||
// Document Actions
|
// Document Actions
|
||||||
entry! {action=PortfolioMessage::Paste(Clipboard::User), key_down=KeyV, modifiers=[KeyControl]},
|
entry! {action=PortfolioMessage::Paste { clipboard: Clipboard::User }, key_down=KeyV, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::Redo, key_down=KeyZ, modifiers=[KeyControl, KeyShift]},
|
entry! {action=DocumentMessage::Redo, key_down=KeyZ, modifiers=[KeyControl, KeyShift]},
|
||||||
entry! {action=DocumentMessage::Undo, key_down=KeyZ, modifiers=[KeyControl]},
|
entry! {action=DocumentMessage::Undo, key_down=KeyZ, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::DeselectAllLayers, key_down=KeyA, modifiers=[KeyControl, KeyAlt]},
|
entry! {action=DocumentMessage::DeselectAllLayers, key_down=KeyA, modifiers=[KeyControl, KeyAlt]},
|
||||||
entry! {action=DocumentMessage::SelectAllLayers, key_down=KeyA, modifiers=[KeyControl]},
|
entry! {action=DocumentMessage::SelectAllLayers, key_down=KeyA, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::CreateEmptyFolder(vec![]), key_down=KeyN, modifiers=[KeyControl, KeyShift]},
|
entry! {action=DocumentMessage::CreateEmptyFolder { container_path: vec![] }, key_down=KeyN, modifiers=[KeyControl, KeyShift]},
|
||||||
entry! {action=DocumentMessage::DeleteSelectedLayers, key_down=KeyDelete},
|
entry! {action=DocumentMessage::DeleteSelectedLayers, key_down=KeyDelete},
|
||||||
entry! {action=DocumentMessage::DeleteSelectedLayers, key_down=KeyX},
|
entry! {action=DocumentMessage::DeleteSelectedLayers, key_down=KeyX},
|
||||||
entry! {action=DocumentMessage::DeleteSelectedLayers, key_down=KeyBackspace},
|
entry! {action=DocumentMessage::DeleteSelectedLayers, key_down=KeyBackspace},
|
||||||
@@ -143,15 +143,15 @@ impl Default for Mapping {
|
|||||||
entry! {action=MovementMessage::IncreaseCanvasZoom { center_on_mouse: false }, key_down=KeyPlus, modifiers=[KeyControl]},
|
entry! {action=MovementMessage::IncreaseCanvasZoom { center_on_mouse: false }, key_down=KeyPlus, modifiers=[KeyControl]},
|
||||||
entry! {action=MovementMessage::IncreaseCanvasZoom { center_on_mouse: false }, key_down=KeyEquals, modifiers=[KeyControl]},
|
entry! {action=MovementMessage::IncreaseCanvasZoom { center_on_mouse: false }, key_down=KeyEquals, modifiers=[KeyControl]},
|
||||||
entry! {action=MovementMessage::DecreaseCanvasZoom { center_on_mouse: false }, key_down=KeyMinus, modifiers=[KeyControl]},
|
entry! {action=MovementMessage::DecreaseCanvasZoom { center_on_mouse: false }, key_down=KeyMinus, modifiers=[KeyControl]},
|
||||||
entry! {action=MovementMessage::SetCanvasZoom(1.), key_down=Key1, modifiers=[KeyControl]},
|
entry! {action=MovementMessage::SetCanvasZoom { zoom_factor: 1. }, key_down=Key1, modifiers=[KeyControl]},
|
||||||
entry! {action=MovementMessage::SetCanvasZoom(2.), key_down=Key2, modifiers=[KeyControl]},
|
entry! {action=MovementMessage::SetCanvasZoom { zoom_factor: 2. }, key_down=Key2, modifiers=[KeyControl]},
|
||||||
entry! {action=MovementMessage::WheelCanvasZoom, message=InputMapperMessage::MouseScroll, modifiers=[KeyControl]},
|
entry! {action=MovementMessage::WheelCanvasZoom, message=InputMapperMessage::MouseScroll, modifiers=[KeyControl]},
|
||||||
entry! {action=MovementMessage::WheelCanvasTranslate { use_y_as_x: true }, message=InputMapperMessage::MouseScroll, modifiers=[KeyShift]},
|
entry! {action=MovementMessage::WheelCanvasTranslate { use_y_as_x: true }, message=InputMapperMessage::MouseScroll, modifiers=[KeyShift]},
|
||||||
entry! {action=MovementMessage::WheelCanvasTranslate { use_y_as_x: false }, message=InputMapperMessage::MouseScroll},
|
entry! {action=MovementMessage::WheelCanvasTranslate { use_y_as_x: false }, message=InputMapperMessage::MouseScroll},
|
||||||
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(1., 0.)), key_down=KeyPageUp, modifiers=[KeyShift]},
|
entry! {action=MovementMessage::TranslateCanvasByViewportFraction { delta: DVec2::new(1., 0.) }, key_down=KeyPageUp, modifiers=[KeyShift]},
|
||||||
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(-1., 0.)), key_down=KeyPageDown, modifiers=[KeyShift]},
|
entry! {action=MovementMessage::TranslateCanvasByViewportFraction { delta: DVec2::new(-1., 0.) }, key_down=KeyPageDown, modifiers=[KeyShift]},
|
||||||
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(0., 1.)), key_down=KeyPageUp},
|
entry! {action=MovementMessage::TranslateCanvasByViewportFraction { delta: DVec2::new(0., 1.) }, key_down=KeyPageUp},
|
||||||
entry! {action=MovementMessage::TranslateCanvasByViewportFraction(DVec2::new(0., -1.)), key_down=KeyPageDown},
|
entry! {action=MovementMessage::TranslateCanvasByViewportFraction { delta: DVec2::new(0., -1.) }, key_down=KeyPageDown},
|
||||||
// Document actions
|
// Document actions
|
||||||
entry! {action=PortfolioMessage::NewDocument, key_down=KeyN, modifiers=[KeyControl]},
|
entry! {action=PortfolioMessage::NewDocument, key_down=KeyN, modifiers=[KeyControl]},
|
||||||
entry! {action=PortfolioMessage::NextDocument, key_down=KeyTab, modifiers=[KeyControl]},
|
entry! {action=PortfolioMessage::NextDocument, key_down=KeyTab, modifiers=[KeyControl]},
|
||||||
@@ -159,58 +159,60 @@ impl Default for Mapping {
|
|||||||
entry! {action=PortfolioMessage::CloseAllDocumentsWithConfirmation, key_down=KeyW, modifiers=[KeyControl, KeyAlt]},
|
entry! {action=PortfolioMessage::CloseAllDocumentsWithConfirmation, key_down=KeyW, modifiers=[KeyControl, KeyAlt]},
|
||||||
entry! {action=PortfolioMessage::CloseActiveDocumentWithConfirmation, key_down=KeyW, modifiers=[KeyControl]},
|
entry! {action=PortfolioMessage::CloseActiveDocumentWithConfirmation, key_down=KeyW, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::DuplicateSelectedLayers, key_down=KeyD, modifiers=[KeyControl]},
|
entry! {action=DocumentMessage::DuplicateSelectedLayers, key_down=KeyD, modifiers=[KeyControl]},
|
||||||
entry! {action=PortfolioMessage::Copy(Clipboard::User), key_down=KeyC, modifiers=[KeyControl]},
|
entry! {action=PortfolioMessage::Copy { clipboard: Clipboard::User }, key_down=KeyC, modifiers=[KeyControl]},
|
||||||
entry! {action=PortfolioMessage::Cut(Clipboard::User), key_down=KeyX, modifiers=[KeyControl]},
|
entry! {action=PortfolioMessage::Cut { clipboard: Clipboard::User }, key_down=KeyX, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::GroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl]},
|
entry! {action=DocumentMessage::GroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::UngroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl, KeyShift]},
|
entry! {action=DocumentMessage::UngroupSelectedLayers, key_down=KeyG, modifiers=[KeyControl, KeyShift]},
|
||||||
// Nudging
|
// Nudging
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowLeft]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -SHIFT_NUDGE_AMOUNT, delta_y: -SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowLeft]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowRight]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: SHIFT_NUDGE_AMOUNT, delta_y: -SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowUp, modifiers=[KeyShift, KeyArrowRight]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(0., -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyShift]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowUp, modifiers=[KeyShift]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, SHIFT_NUDGE_AMOUNT), key_down=KeyArrowDown, modifiers=[KeyShift, KeyArrowLeft]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -SHIFT_NUDGE_AMOUNT, delta_y: SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowDown, modifiers=[KeyShift, KeyArrowLeft]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(SHIFT_NUDGE_AMOUNT, SHIFT_NUDGE_AMOUNT), key_down=KeyArrowDown, modifiers=[KeyShift, KeyArrowRight]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: SHIFT_NUDGE_AMOUNT, delta_y: SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowDown, modifiers=[KeyShift, KeyArrowRight]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(0., SHIFT_NUDGE_AMOUNT), key_down=KeyArrowDown, modifiers=[KeyShift]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowDown, modifiers=[KeyShift]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowLeft, modifiers=[KeyShift, KeyArrowUp]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -SHIFT_NUDGE_AMOUNT, delta_y: -SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowLeft, modifiers=[KeyShift, KeyArrowUp]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, SHIFT_NUDGE_AMOUNT), key_down=KeyArrowLeft, modifiers=[KeyShift, KeyArrowDown]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -SHIFT_NUDGE_AMOUNT, delta_y: SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowLeft, modifiers=[KeyShift, KeyArrowDown]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-SHIFT_NUDGE_AMOUNT, 0.), key_down=KeyArrowLeft, modifiers=[KeyShift]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -SHIFT_NUDGE_AMOUNT, delta_y: 0. }, key_down=KeyArrowLeft, modifiers=[KeyShift]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(SHIFT_NUDGE_AMOUNT, -SHIFT_NUDGE_AMOUNT), key_down=KeyArrowRight, modifiers=[KeyShift, KeyArrowUp]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: SHIFT_NUDGE_AMOUNT, delta_y: -SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowRight, modifiers=[KeyShift, KeyArrowUp]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(SHIFT_NUDGE_AMOUNT, SHIFT_NUDGE_AMOUNT), key_down=KeyArrowRight, modifiers=[KeyShift, KeyArrowDown]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: SHIFT_NUDGE_AMOUNT, delta_y: SHIFT_NUDGE_AMOUNT }, key_down=KeyArrowRight, modifiers=[KeyShift, KeyArrowDown]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(SHIFT_NUDGE_AMOUNT, 0.), key_down=KeyArrowRight, modifiers=[KeyShift]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: SHIFT_NUDGE_AMOUNT, delta_y: 0. }, key_down=KeyArrowRight, modifiers=[KeyShift]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-NUDGE_AMOUNT, -NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyArrowLeft]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }, key_down=KeyArrowUp, modifiers=[KeyArrowLeft]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(NUDGE_AMOUNT, -NUDGE_AMOUNT), key_down=KeyArrowUp, modifiers=[KeyArrowRight]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }, key_down=KeyArrowUp, modifiers=[KeyArrowRight]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(0., -NUDGE_AMOUNT), key_down=KeyArrowUp},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -NUDGE_AMOUNT }, key_down=KeyArrowUp},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-NUDGE_AMOUNT, NUDGE_AMOUNT), key_down=KeyArrowDown, modifiers=[KeyArrowLeft]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }, key_down=KeyArrowDown, modifiers=[KeyArrowLeft]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(NUDGE_AMOUNT, NUDGE_AMOUNT), key_down=KeyArrowDown, modifiers=[KeyArrowRight]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }, key_down=KeyArrowDown, modifiers=[KeyArrowRight]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(0., NUDGE_AMOUNT), key_down=KeyArrowDown},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: 0., delta_y: NUDGE_AMOUNT }, key_down=KeyArrowDown},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-NUDGE_AMOUNT, -NUDGE_AMOUNT), key_down=KeyArrowLeft, modifiers=[KeyArrowUp]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }, key_down=KeyArrowLeft, modifiers=[KeyArrowUp]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-NUDGE_AMOUNT, NUDGE_AMOUNT), key_down=KeyArrowLeft, modifiers=[KeyArrowDown]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }, key_down=KeyArrowLeft, modifiers=[KeyArrowDown]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(-NUDGE_AMOUNT, 0.), key_down=KeyArrowLeft},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: 0. }, key_down=KeyArrowLeft},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(NUDGE_AMOUNT, -NUDGE_AMOUNT), key_down=KeyArrowRight, modifiers=[KeyArrowUp]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT }, key_down=KeyArrowRight, modifiers=[KeyArrowUp]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(NUDGE_AMOUNT, NUDGE_AMOUNT), key_down=KeyArrowRight, modifiers=[KeyArrowDown]},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT }, key_down=KeyArrowRight, modifiers=[KeyArrowDown]},
|
||||||
entry! {action=DocumentMessage::NudgeSelectedLayers(NUDGE_AMOUNT, 0.), key_down=KeyArrowRight},
|
entry! {action=DocumentMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: 0. }, key_down=KeyArrowRight},
|
||||||
// Reorder Layers
|
// Reorder Layers
|
||||||
entry! {action=DocumentMessage::ReorderSelectedLayers(i32::MAX), key_down=KeyRightCurlyBracket, modifiers=[KeyControl]}, // TODO: Use KeyRightBracket with ctrl+shift modifiers once input system is fixed
|
entry! {action=DocumentMessage::ReorderSelectedLayers { relative_index_offset: isize::MAX }, key_down=KeyRightCurlyBracket, modifiers=[KeyControl]}, // TODO: Use KeyRightBracket with ctrl+shift modifiers once input system is fixed
|
||||||
entry! {action=DocumentMessage::ReorderSelectedLayers(1), key_down=KeyRightBracket, modifiers=[KeyControl]},
|
entry! {action=DocumentMessage::ReorderSelectedLayers { relative_index_offset: 1 }, key_down=KeyRightBracket, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::ReorderSelectedLayers(-1), key_down=KeyLeftBracket, modifiers=[KeyControl]},
|
entry! {action=DocumentMessage::ReorderSelectedLayers { relative_index_offset: -1 }, key_down=KeyLeftBracket, modifiers=[KeyControl]},
|
||||||
entry! {action=DocumentMessage::ReorderSelectedLayers(i32::MIN), key_down=KeyLeftCurlyBracket, modifiers=[KeyControl]}, // TODO: Use KeyLeftBracket with ctrl+shift modifiers once input system is fixed
|
entry! {action=DocumentMessage::ReorderSelectedLayers { relative_index_offset: isize::MIN }, key_down=KeyLeftCurlyBracket, modifiers=[KeyControl]}, // TODO: Use KeyLeftBracket with ctrl+shift modifiers once input system is fixed
|
||||||
// Global Actions
|
// Global Actions
|
||||||
entry! {action=GlobalMessage::LogInfo, key_down=Key1},
|
entry! {action=GlobalMessage::LogInfo, key_down=Key1},
|
||||||
entry! {action=GlobalMessage::LogDebug, key_down=Key2},
|
entry! {action=GlobalMessage::LogDebug, key_down=Key2},
|
||||||
entry! {action=GlobalMessage::LogTrace, key_down=Key3},
|
entry! {action=GlobalMessage::LogTrace, key_down=Key3},
|
||||||
];
|
];
|
||||||
|
|
||||||
let (mut key_up, mut key_down, mut pointer_move, mut mouse_scroll) = mappings;
|
let (mut key_up, mut key_down, mut pointer_move, mut mouse_scroll) = mappings;
|
||||||
|
|
||||||
|
// TODO: Hardcode these 10 lines into 10 lines of declarations, or make this use a macro to do all 10 in one line
|
||||||
const NUMBER_KEYS: [Key; 10] = [Key0, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9];
|
const NUMBER_KEYS: [Key; 10] = [Key0, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9];
|
||||||
for (i, key) in NUMBER_KEYS.iter().enumerate() {
|
for (i, key) in NUMBER_KEYS.iter().enumerate() {
|
||||||
key_down[*key as usize].0.insert(
|
key_down[*key as usize].0.insert(
|
||||||
0,
|
0,
|
||||||
MappingEntry {
|
MappingEntry {
|
||||||
|
action: TransformLayerMessage::TypeDigit { digit: i as u8 }.into(),
|
||||||
trigger: InputMapperMessage::KeyDown(*key),
|
trigger: InputMapperMessage::KeyDown(*key),
|
||||||
modifiers: modifiers! {},
|
modifiers: modifiers! {},
|
||||||
action: TransformLayerMessage::TypeNumber(i as u8).into(),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sort = |list: &mut KeyMappingEntries| list.0.sort_by(|u, v| v.modifiers.ones().cmp(&u.modifiers.ones()));
|
let sort = |list: &mut KeyMappingEntries| list.0.sort_by(|u, v| v.modifiers.ones().cmp(&u.modifiers.ones()));
|
||||||
for list in [&mut key_up, &mut key_down] {
|
for list in [&mut key_up, &mut key_down] {
|
||||||
for sublist in list {
|
for sublist in list {
|
||||||
@@ -219,6 +221,7 @@ impl Default for Mapping {
|
|||||||
}
|
}
|
||||||
sort(&mut pointer_move);
|
sort(&mut pointer_move);
|
||||||
sort(&mut mouse_scroll);
|
sort(&mut mouse_scroll);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
key_up,
|
key_up,
|
||||||
key_down,
|
key_down,
|
||||||
|
|||||||
@@ -23,19 +23,20 @@ bitflags! {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::input::input_preprocessor::ModifierKeys;
|
use crate::input::input_preprocessor::ModifierKeys;
|
||||||
use crate::input::keyboard::Key;
|
use crate::input::keyboard::Key;
|
||||||
use crate::input::mouse::{EditorMouseState, ViewportPosition};
|
use crate::input::mouse::EditorMouseState;
|
||||||
use crate::input::InputPreprocessorMessageHandler;
|
use crate::input::{InputMapperMessage, InputPreprocessorMessage, InputPreprocessorMessageHandler};
|
||||||
use crate::message_prelude::MessageHandler;
|
use crate::message_prelude::MessageHandler;
|
||||||
use crate::message_prelude::*;
|
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn process_action_mouse_move_handle_modifier_keys() {
|
fn process_action_mouse_move_handle_modifier_keys() {
|
||||||
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
||||||
let mut editor_mouse_state = EditorMouseState::new();
|
|
||||||
editor_mouse_state.editor_position = ViewportPosition::new(4., 809.);
|
let editor_mouse_state = EditorMouseState::from_editor_position(4., 809.);
|
||||||
let message = InputPreprocessorMessage::MouseMove(editor_mouse_state, ModifierKeys::ALT);
|
let modifier_keys = ModifierKeys::ALT;
|
||||||
|
let message = InputPreprocessorMessage::MouseMove { editor_mouse_state, modifier_keys };
|
||||||
|
|
||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
input_preprocessor.process_action(message, (), &mut responses);
|
input_preprocessor.process_action(message, (), &mut responses);
|
||||||
@@ -47,7 +48,11 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn process_action_mouse_down_handle_modifier_keys() {
|
fn process_action_mouse_down_handle_modifier_keys() {
|
||||||
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
||||||
let message = InputPreprocessorMessage::MouseDown(EditorMouseState::new(), ModifierKeys::CONTROL);
|
|
||||||
|
let editor_mouse_state = EditorMouseState::new();
|
||||||
|
let modifier_keys = ModifierKeys::CONTROL;
|
||||||
|
let message = InputPreprocessorMessage::MouseDown { editor_mouse_state, modifier_keys };
|
||||||
|
|
||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
input_preprocessor.process_action(message, (), &mut responses);
|
input_preprocessor.process_action(message, (), &mut responses);
|
||||||
@@ -59,7 +64,11 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn process_action_mouse_up_handle_modifier_keys() {
|
fn process_action_mouse_up_handle_modifier_keys() {
|
||||||
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
||||||
let message = InputPreprocessorMessage::MouseUp(EditorMouseState::new(), ModifierKeys::SHIFT);
|
|
||||||
|
let editor_mouse_state = EditorMouseState::new();
|
||||||
|
let modifier_keys = ModifierKeys::SHIFT;
|
||||||
|
let message = InputPreprocessorMessage::MouseUp { editor_mouse_state, modifier_keys };
|
||||||
|
|
||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
input_preprocessor.process_action(message, (), &mut responses);
|
input_preprocessor.process_action(message, (), &mut responses);
|
||||||
@@ -72,7 +81,11 @@ mod test {
|
|||||||
fn process_action_key_down_handle_modifier_keys() {
|
fn process_action_key_down_handle_modifier_keys() {
|
||||||
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
||||||
input_preprocessor.keyboard.set(Key::KeyControl as usize);
|
input_preprocessor.keyboard.set(Key::KeyControl as usize);
|
||||||
let message = InputPreprocessorMessage::KeyDown(Key::KeyA, ModifierKeys::empty());
|
|
||||||
|
let key = Key::KeyA;
|
||||||
|
let modifier_keys = ModifierKeys::empty();
|
||||||
|
let message = InputPreprocessorMessage::KeyDown { key, modifier_keys };
|
||||||
|
|
||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
input_preprocessor.process_action(message, (), &mut responses);
|
input_preprocessor.process_action(message, (), &mut responses);
|
||||||
@@ -84,7 +97,11 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn process_action_key_up_handle_modifier_keys() {
|
fn process_action_key_up_handle_modifier_keys() {
|
||||||
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
let mut input_preprocessor = InputPreprocessorMessageHandler::default();
|
||||||
let message = InputPreprocessorMessage::KeyUp(Key::KeyS, ModifierKeys::CONTROL | ModifierKeys::SHIFT);
|
|
||||||
|
let key = Key::KeyS;
|
||||||
|
let modifier_keys = ModifierKeys::CONTROL | ModifierKeys::SHIFT;
|
||||||
|
let message = InputPreprocessorMessage::KeyUp { key, modifier_keys };
|
||||||
|
|
||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
input_preprocessor.process_action(message, (), &mut responses);
|
input_preprocessor.process_action(message, (), &mut responses);
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[impl_message(Message, InputPreprocessor)]
|
#[impl_message(Message, InputPreprocessor)]
|
||||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum InputPreprocessorMessage {
|
pub enum InputPreprocessorMessage {
|
||||||
BoundsOfViewports(Vec<ViewportBounds>),
|
BoundsOfViewports { bounds_of_viewports: Vec<ViewportBounds> },
|
||||||
KeyDown(Key, ModifierKeys),
|
KeyDown { key: Key, modifier_keys: ModifierKeys },
|
||||||
KeyUp(Key, ModifierKeys),
|
KeyUp { key: Key, modifier_keys: ModifierKeys },
|
||||||
MouseDown(EditorMouseState, ModifierKeys),
|
MouseDown { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
|
||||||
MouseMove(EditorMouseState, ModifierKeys),
|
MouseMove { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
|
||||||
MouseScroll(EditorMouseState, ModifierKeys),
|
MouseScroll { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
|
||||||
MouseUp(EditorMouseState, ModifierKeys),
|
MouseUp { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
|
|||||||
fn process_action(&mut self, message: InputPreprocessorMessage, _data: (), responses: &mut VecDeque<Message>) {
|
fn process_action(&mut self, message: InputPreprocessorMessage, _data: (), responses: &mut VecDeque<Message>) {
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
match message {
|
match message {
|
||||||
InputPreprocessorMessage::BoundsOfViewports(bounds_of_viewports) => {
|
InputPreprocessorMessage::BoundsOfViewports { bounds_of_viewports } => {
|
||||||
assert_eq!(bounds_of_viewports.len(), 1, "Only one viewport is currently supported");
|
assert_eq!(bounds_of_viewports.len(), 1, "Only one viewport is currently supported");
|
||||||
|
|
||||||
for bounds in bounds_of_viewports {
|
for bounds in bounds_of_viewports {
|
||||||
@@ -59,17 +59,17 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::KeyDown(key, modifier_keys) => {
|
InputPreprocessorMessage::KeyDown { key, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, responses);
|
self.handle_modifier_keys(modifier_keys, responses);
|
||||||
self.keyboard.set(key as usize);
|
self.keyboard.set(key as usize);
|
||||||
responses.push_back(InputMapperMessage::KeyDown(key).into());
|
responses.push_back(InputMapperMessage::KeyDown(key).into());
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::KeyUp(key, modifier_keys) => {
|
InputPreprocessorMessage::KeyUp { key, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, responses);
|
self.handle_modifier_keys(modifier_keys, responses);
|
||||||
self.keyboard.unset(key as usize);
|
self.keyboard.unset(key as usize);
|
||||||
responses.push_back(InputMapperMessage::KeyUp(key).into());
|
responses.push_back(InputMapperMessage::KeyUp(key).into());
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::MouseDown(editor_mouse_state, modifier_keys) => {
|
InputPreprocessorMessage::MouseDown { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, responses);
|
self.handle_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
@@ -79,7 +79,7 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
|
|||||||
responses.push_back(message);
|
responses.push_back(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::MouseMove(editor_mouse_state, modifier_keys) => {
|
InputPreprocessorMessage::MouseMove { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, responses);
|
self.handle_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
@@ -87,7 +87,7 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
|
|||||||
|
|
||||||
responses.push_back(InputMapperMessage::PointerMove.into());
|
responses.push_back(InputMapperMessage::PointerMove.into());
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::MouseScroll(editor_mouse_state, modifier_keys) => {
|
InputPreprocessorMessage::MouseScroll { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, responses);
|
self.handle_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
@@ -96,7 +96,7 @@ impl MessageHandler<InputPreprocessorMessage, ()> for InputPreprocessorMessageHa
|
|||||||
|
|
||||||
responses.push_back(InputMapperMessage::MouseScroll.into());
|
responses.push_back(InputMapperMessage::MouseScroll.into());
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::MouseUp(editor_mouse_state, modifier_keys) => {
|
InputPreprocessorMessage::MouseUp { editor_mouse_state, modifier_keys } => {
|
||||||
self.handle_modifier_keys(modifier_keys, responses);
|
self.handle_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const KEY_MASK_STORAGE_LENGTH: usize = (NUMBER_OF_KEYS + STORAGE_SIZE_BITS - 1)
|
|||||||
|
|
||||||
pub type KeyStates = BitVector<KEY_MASK_STORAGE_LENGTH>;
|
pub type KeyStates = BitVector<KEY_MASK_STORAGE_LENGTH>;
|
||||||
|
|
||||||
|
// TODO: Consider renaming to `KeyMessage` for consistency with other messages that implement `#[impl_message(..)]`
|
||||||
#[impl_message(Message, InputMapperMessage, KeyDown)]
|
#[impl_message(Message, InputMapperMessage, KeyDown)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ pub mod message_prelude {
|
|||||||
pub use crate::viewport_tools::tools::rectangle::{RectangleMessage, RectangleMessageDiscriminant};
|
pub use crate::viewport_tools::tools::rectangle::{RectangleMessage, RectangleMessageDiscriminant};
|
||||||
pub use crate::viewport_tools::tools::select::{SelectMessage, SelectMessageDiscriminant};
|
pub use crate::viewport_tools::tools::select::{SelectMessage, SelectMessageDiscriminant};
|
||||||
pub use crate::viewport_tools::tools::shape::{ShapeMessage, ShapeMessageDiscriminant};
|
pub use crate::viewport_tools::tools::shape::{ShapeMessage, ShapeMessageDiscriminant};
|
||||||
|
|
||||||
pub use graphite_proc_macros::*;
|
pub use graphite_proc_macros::*;
|
||||||
|
|
||||||
pub use std::collections::VecDeque;
|
pub use std::collections::VecDeque;
|
||||||
|
|||||||
@@ -51,15 +51,18 @@ impl EditorTestUtils for Editor {
|
|||||||
fn move_mouse(&mut self, x: f64, y: f64) {
|
fn move_mouse(&mut self, x: f64, y: f64) {
|
||||||
let mut editor_mouse_state = EditorMouseState::new();
|
let mut editor_mouse_state = EditorMouseState::new();
|
||||||
editor_mouse_state.editor_position = ViewportPosition::new(x, y);
|
editor_mouse_state.editor_position = ViewportPosition::new(x, y);
|
||||||
self.input(InputPreprocessorMessage::MouseMove(editor_mouse_state, ModifierKeys::default()));
|
let modifier_keys = ModifierKeys::default();
|
||||||
|
self.input(InputPreprocessorMessage::MouseMove { editor_mouse_state, modifier_keys });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mousedown(&mut self, state: EditorMouseState) {
|
fn mousedown(&mut self, editor_mouse_state: EditorMouseState) {
|
||||||
self.input(InputPreprocessorMessage::MouseDown(state, ModifierKeys::default()));
|
let modifier_keys = ModifierKeys::default();
|
||||||
|
self.input(InputPreprocessorMessage::MouseDown { editor_mouse_state, modifier_keys });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouseup(&mut self, state: EditorMouseState) {
|
fn mouseup(&mut self, editor_mouse_state: EditorMouseState) {
|
||||||
self.handle_message(InputPreprocessorMessage::MouseUp(state, ModifierKeys::default()));
|
let modifier_keys = ModifierKeys::default();
|
||||||
|
self.handle_message(InputPreprocessorMessage::MouseUp { editor_mouse_state, modifier_keys });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lmb_mousedown(&mut self, x: f64, y: f64) {
|
fn lmb_mousedown(&mut self, x: f64, y: f64) {
|
||||||
@@ -74,11 +77,11 @@ impl EditorTestUtils for Editor {
|
|||||||
self.handle_message(Message::InputPreprocessor(message));
|
self.handle_message(Message::InputPreprocessor(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_tool(&mut self, typ: ToolType) {
|
fn select_tool(&mut self, tool_type: ToolType) {
|
||||||
self.handle_message(Message::Tool(ToolMessage::ActivateTool(typ)));
|
self.handle_message(Message::Tool(ToolMessage::ActivateTool { tool_type }));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_primary_color(&mut self, color: Color) {
|
fn select_primary_color(&mut self, color: Color) {
|
||||||
self.handle_message(Message::Tool(ToolMessage::SelectPrimaryColor(color)));
|
self.handle_message(Message::Tool(ToolMessage::SelectPrimaryColor { color }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[impl_message(Message, Tool)]
|
#[impl_message(Message, Tool)]
|
||||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum ToolMessage {
|
pub enum ToolMessage {
|
||||||
ActivateTool(ToolType),
|
ActivateTool {
|
||||||
|
tool_type: ToolType,
|
||||||
|
},
|
||||||
#[child]
|
#[child]
|
||||||
Crop(CropMessage),
|
Crop(CropMessage),
|
||||||
DocumentIsDirty,
|
DocumentIsDirty,
|
||||||
@@ -34,9 +36,16 @@ pub enum ToolMessage {
|
|||||||
ResetColors,
|
ResetColors,
|
||||||
#[child]
|
#[child]
|
||||||
Select(SelectMessage),
|
Select(SelectMessage),
|
||||||
SelectPrimaryColor(Color),
|
SelectPrimaryColor {
|
||||||
SelectSecondaryColor(Color),
|
color: Color,
|
||||||
SetToolOptions(ToolType, ToolOptions),
|
},
|
||||||
|
SelectSecondaryColor {
|
||||||
|
color: Color,
|
||||||
|
},
|
||||||
|
SetToolOptions {
|
||||||
|
tool_type: ToolType,
|
||||||
|
tool_options: ToolOptions,
|
||||||
|
},
|
||||||
#[child]
|
#[child]
|
||||||
Shape(ShapeMessage),
|
Shape(ShapeMessage),
|
||||||
SwapColors,
|
SwapColors,
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMes
|
|||||||
let (document, input) = data;
|
let (document, input) = data;
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
match message {
|
match message {
|
||||||
ActivateTool(new_tool) => {
|
ActivateTool { tool_type } => {
|
||||||
let tool_data = &mut self.tool_state.tool_data;
|
let tool_data = &mut self.tool_state.tool_data;
|
||||||
let document_data = &self.tool_state.document_tool_data;
|
let document_data = &self.tool_state.document_tool_data;
|
||||||
let old_tool = tool_data.active_tool_type;
|
let old_tool = tool_data.active_tool_type;
|
||||||
|
|
||||||
// Do nothing if switching to the same tool
|
// Do nothing if switching to the same tool
|
||||||
if new_tool == old_tool {
|
if tool_type == old_tool {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,24 +41,24 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMes
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Send the old and new tools a transition to their FSM Abort states
|
// Send the old and new tools a transition to their FSM Abort states
|
||||||
if let Some(tool_message) = standard_tool_message(new_tool, StandardToolMessageType::Abort) {
|
if let Some(tool_message) = standard_tool_message(tool_type, StandardToolMessageType::Abort) {
|
||||||
send_abort_to_tool(new_tool, tool_message, true);
|
send_abort_to_tool(tool_type, tool_message, true);
|
||||||
}
|
}
|
||||||
if let Some(tool_message) = standard_tool_message(old_tool, StandardToolMessageType::Abort) {
|
if let Some(tool_message) = standard_tool_message(old_tool, StandardToolMessageType::Abort) {
|
||||||
send_abort_to_tool(old_tool, tool_message, false);
|
send_abort_to_tool(old_tool, tool_message, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the DocumentIsDirty message to the active tool's sub-tool message handler
|
// Send the DocumentIsDirty message to the active tool's sub-tool message handler
|
||||||
if let Some(message) = standard_tool_message(new_tool, StandardToolMessageType::DocumentIsDirty) {
|
if let Some(message) = standard_tool_message(tool_type, StandardToolMessageType::DocumentIsDirty) {
|
||||||
responses.push_back(message.into());
|
responses.push_back(message.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the new active tool
|
// Store the new active tool
|
||||||
tool_data.active_tool_type = new_tool;
|
tool_data.active_tool_type = tool_type;
|
||||||
|
|
||||||
// Notify the frontend about the new active tool to be displayed
|
// Notify the frontend about the new active tool to be displayed
|
||||||
let tool_name = new_tool.to_string();
|
let tool_name = tool_type.to_string();
|
||||||
let tool_options = self.tool_state.document_tool_data.tool_options.get(&new_tool).copied();
|
let tool_options = self.tool_state.document_tool_data.tool_options.get(&tool_type).copied();
|
||||||
responses.push_back(FrontendMessage::UpdateActiveTool { tool_name, tool_options }.into());
|
responses.push_back(FrontendMessage::UpdateActiveTool { tool_name, tool_options }.into());
|
||||||
}
|
}
|
||||||
DocumentIsDirty => {
|
DocumentIsDirty => {
|
||||||
@@ -76,19 +76,19 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, &InputPreprocessorMes
|
|||||||
|
|
||||||
update_working_colors(document_data, responses);
|
update_working_colors(document_data, responses);
|
||||||
}
|
}
|
||||||
SelectPrimaryColor(color) => {
|
SelectPrimaryColor { color } => {
|
||||||
let document_data = &mut self.tool_state.document_tool_data;
|
let document_data = &mut self.tool_state.document_tool_data;
|
||||||
document_data.primary_color = color;
|
document_data.primary_color = color;
|
||||||
|
|
||||||
update_working_colors(&self.tool_state.document_tool_data, responses);
|
update_working_colors(&self.tool_state.document_tool_data, responses);
|
||||||
}
|
}
|
||||||
SelectSecondaryColor(color) => {
|
SelectSecondaryColor { color } => {
|
||||||
let document_data = &mut self.tool_state.document_tool_data;
|
let document_data = &mut self.tool_state.document_tool_data;
|
||||||
document_data.secondary_color = color;
|
document_data.secondary_color = color;
|
||||||
|
|
||||||
update_working_colors(document_data, responses);
|
update_working_colors(document_data, responses);
|
||||||
}
|
}
|
||||||
SetToolOptions(tool_type, tool_options) => {
|
SetToolOptions { tool_type, tool_options } => {
|
||||||
let document_data = &mut self.tool_state.document_tool_data;
|
let document_data = &mut self.tool_state.document_tool_data;
|
||||||
|
|
||||||
document_data.tool_options.insert(tool_type, tool_options);
|
document_data.tool_options.insert(tool_type, tool_options);
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ impl Fsm for EyedropperToolFsmState {
|
|||||||
if let Some(fill) = shape.style.fill() {
|
if let Some(fill) = shape.style.fill() {
|
||||||
if let Some(color) = fill.color() {
|
if let Some(color) = fill.color() {
|
||||||
match lmb_or_rmb {
|
match lmb_or_rmb {
|
||||||
EyedropperMessage::LeftMouseDown => responses.push_back(ToolMessage::SelectPrimaryColor(color).into()),
|
EyedropperMessage::LeftMouseDown => responses.push_back(ToolMessage::SelectPrimaryColor { color }.into()),
|
||||||
EyedropperMessage::RightMouseDown => responses.push_back(ToolMessage::SelectSecondaryColor(color).into()),
|
EyedropperMessage::RightMouseDown => responses.push_back(ToolMessage::SelectSecondaryColor { color }.into()),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
use crate::document::DocumentMessageHandler;
|
||||||
|
use crate::input::keyboard::Key;
|
||||||
|
use crate::input::mouse::ViewportPosition;
|
||||||
|
use crate::input::InputPreprocessorMessageHandler;
|
||||||
|
use crate::message_prelude::*;
|
||||||
|
use crate::viewport_tools::snapping::SnapHandler;
|
||||||
|
|
||||||
|
use graphene::Operation;
|
||||||
|
|
||||||
|
use glam::{DAffine2, DVec2, Vec2Swizzles};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct Resize {
|
||||||
|
pub drag_start: ViewportPosition,
|
||||||
|
pub path: Option<Vec<LayerId>>,
|
||||||
|
snap_handler: SnapHandler,
|
||||||
|
}
|
||||||
|
impl Resize {
|
||||||
|
/// Starts a resize, assigning the snap targets and snapping the starting position.
|
||||||
|
pub fn start(&mut self, document: &DocumentMessageHandler, mouse_position: DVec2) {
|
||||||
|
let layers = document.all_layers_sorted();
|
||||||
|
self.snap_handler.start_snap(document, layers, &[]);
|
||||||
|
self.drag_start = self.snap_handler.snap_position(document, mouse_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate_transform(&self, document: &DocumentMessageHandler, center: Key, lock_ratio: Key, ipp: &InputPreprocessorMessageHandler) -> Option<Message> {
|
||||||
|
if let Some(path) = &self.path {
|
||||||
|
let mut start = self.drag_start;
|
||||||
|
|
||||||
|
let stop = self.snap_handler.snap_position(document, ipp.mouse.position);
|
||||||
|
|
||||||
|
let mut size = stop - start;
|
||||||
|
if ipp.keyboard.get(lock_ratio as usize) {
|
||||||
|
size = size.abs().max(size.abs().yx()) * size.signum();
|
||||||
|
}
|
||||||
|
if ipp.keyboard.get(center as usize) {
|
||||||
|
start -= size;
|
||||||
|
size *= 2.;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
Operation::SetLayerTransformInViewport {
|
||||||
|
path: path.to_vec(),
|
||||||
|
transform: DAffine2::from_scale_angle_translation(size, 0., start).to_cols_array(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup(&mut self) {
|
||||||
|
self.snap_handler.cleanup();
|
||||||
|
self.path = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@ pub enum SelectMessage {
|
|||||||
DragStop,
|
DragStop,
|
||||||
MouseMove { snap_angle: Key },
|
MouseMove { snap_angle: Key },
|
||||||
|
|
||||||
Align(AlignAxis, AlignAggregate),
|
Align { axis: AlignAxis, aggregate: AlignAggregate },
|
||||||
FlipHorizontal,
|
FlipHorizontal,
|
||||||
FlipVertical,
|
FlipVertical,
|
||||||
}
|
}
|
||||||
@@ -180,7 +180,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
|
|
||||||
if let Some(intersection) = intersection.pop() {
|
if let Some(intersection) = intersection.pop() {
|
||||||
selected = vec![intersection];
|
selected = vec![intersection];
|
||||||
buffer.push(DocumentMessage::AddSelectedLayers(selected.clone()).into());
|
buffer.push(DocumentMessage::AddSelectedLayers { additional_layers: selected.clone() }.into());
|
||||||
buffer.push(DocumentMessage::StartTransaction.into());
|
buffer.push(DocumentMessage::StartTransaction.into());
|
||||||
data.layers_dragging.append(&mut selected);
|
data.layers_dragging.append(&mut selected);
|
||||||
Dragging
|
Dragging
|
||||||
@@ -258,7 +258,12 @@ impl Fsm for SelectToolFsmState {
|
|||||||
}
|
}
|
||||||
(DrawingBox, DragStop) => {
|
(DrawingBox, DragStop) => {
|
||||||
let quad = data.selection_quad();
|
let quad = data.selection_quad();
|
||||||
responses.push_front(DocumentMessage::AddSelectedLayers(document.graphene_document.intersects_quad_root(quad)).into());
|
responses.push_front(
|
||||||
|
DocumentMessage::AddSelectedLayers {
|
||||||
|
additional_layers: document.graphene_document.intersects_quad_root(quad),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
responses.push_front(
|
responses.push_front(
|
||||||
DocumentMessage::Overlays(
|
DocumentMessage::Overlays(
|
||||||
Operation::DeleteLayer {
|
Operation::DeleteLayer {
|
||||||
@@ -276,18 +281,18 @@ impl Fsm for SelectToolFsmState {
|
|||||||
delete(&mut data.bounding_box_overlay_layer);
|
delete(&mut data.bounding_box_overlay_layer);
|
||||||
Ready
|
Ready
|
||||||
}
|
}
|
||||||
(_, Align(axis, aggregate)) => {
|
(_, Align { axis, aggregate }) => {
|
||||||
responses.push_back(DocumentMessage::AlignSelectedLayers(axis, aggregate).into());
|
responses.push_back(DocumentMessage::AlignSelectedLayers { axis, aggregate }.into());
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, FlipHorizontal) => {
|
(_, FlipHorizontal) => {
|
||||||
responses.push_back(DocumentMessage::FlipSelectedLayers(FlipAxis::X).into());
|
responses.push_back(DocumentMessage::FlipSelectedLayers { flip_axis: FlipAxis::X }.into());
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, FlipVertical) => {
|
(_, FlipVertical) => {
|
||||||
responses.push_back(DocumentMessage::FlipSelectedLayers(FlipAxis::Y).into());
|
responses.push_back(DocumentMessage::FlipSelectedLayers { flip_axis: FlipAxis::Y }.into());
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,15 +95,15 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
const toolOptionsWidgets: Record<ToolName, WidgetRow> = {
|
const toolOptionsWidgets: Record<ToolName, WidgetRow> = {
|
||||||
Select: [
|
Select: [
|
||||||
{ kind: "IconButton", message: { Align: ["X", "Min"] }, tooltip: "Align Left", props: { icon: "AlignLeft", size: 24 } },
|
{ kind: "IconButton", message: { Align: { axis: "X", aggregate: "Min" } }, tooltip: "Align Left", props: { icon: "AlignLeft", size: 24 } },
|
||||||
{ kind: "IconButton", message: { Align: ["X", "Center"] }, tooltip: "Align Horizontal Center", props: { icon: "AlignHorizontalCenter", size: 24 } },
|
{ kind: "IconButton", message: { Align: { axis: "X", aggregate: "Center" } }, tooltip: "Align Horizontal Center", props: { icon: "AlignHorizontalCenter", size: 24 } },
|
||||||
{ kind: "IconButton", message: { Align: ["X", "Max"] }, tooltip: "Align Right", props: { icon: "AlignRight", size: 24 } },
|
{ kind: "IconButton", message: { Align: { axis: "X", aggregate: "Max" } }, tooltip: "Align Right", props: { icon: "AlignRight", size: 24 } },
|
||||||
|
|
||||||
{ kind: "Separator", props: { type: "Unrelated" } },
|
{ kind: "Separator", props: { type: "Unrelated" } },
|
||||||
|
|
||||||
{ kind: "IconButton", message: { Align: ["Y", "Min"] }, tooltip: "Align Top", props: { icon: "AlignTop", size: 24 } },
|
{ kind: "IconButton", message: { Align: { axis: "Y", aggregate: "Min" } }, tooltip: "Align Top", props: { icon: "AlignTop", size: 24 } },
|
||||||
{ kind: "IconButton", message: { Align: ["Y", "Center"] }, tooltip: "Align Vertical Center", props: { icon: "AlignVerticalCenter", size: 24 } },
|
{ kind: "IconButton", message: { Align: { axis: "Y", aggregate: "Center" } }, tooltip: "Align Vertical Center", props: { icon: "AlignVerticalCenter", size: 24 } },
|
||||||
{ kind: "IconButton", message: { Align: ["Y", "Max"] }, tooltip: "Align Bottom", props: { icon: "AlignBottom", size: 24 } },
|
{ kind: "IconButton", message: { Align: { axis: "Y", aggregate: "Max" } }, tooltip: "Align Bottom", props: { icon: "AlignBottom", size: 24 } },
|
||||||
|
|
||||||
{ kind: "Separator", props: { type: "Related" } },
|
{ kind: "Separator", props: { type: "Related" } },
|
||||||
|
|
||||||
|
|||||||
+70
-72
@@ -95,8 +95,8 @@ impl JsEditorHandle {
|
|||||||
/// Modify the currently selected tool in the document state store
|
/// Modify the currently selected tool in the document state store
|
||||||
pub fn select_tool(&self, tool: String) -> Result<(), JsValue> {
|
pub fn select_tool(&self, tool: String) -> Result<(), JsValue> {
|
||||||
match translate_tool_type(&tool) {
|
match translate_tool_type(&tool) {
|
||||||
Some(tool) => {
|
Some(tool_type) => {
|
||||||
let message = ToolMessage::ActivateTool(tool);
|
let message = ToolMessage::ActivateTool { tool_type };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -108,9 +108,9 @@ impl JsEditorHandle {
|
|||||||
/// Update the options for a given tool
|
/// Update the options for a given tool
|
||||||
pub fn set_tool_options(&self, tool: String, options: &JsValue) -> Result<(), JsValue> {
|
pub fn set_tool_options(&self, tool: String, options: &JsValue) -> Result<(), JsValue> {
|
||||||
match serde_wasm_bindgen::from_value::<ToolOptions>(options.clone()) {
|
match serde_wasm_bindgen::from_value::<ToolOptions>(options.clone()) {
|
||||||
Ok(options) => match translate_tool_type(&tool) {
|
Ok(tool_options) => match translate_tool_type(&tool) {
|
||||||
Some(tool) => {
|
Some(tool_type) => {
|
||||||
let message = ToolMessage::SetToolOptions(tool, options);
|
let message = ToolMessage::SetToolOptions { tool_type, tool_options };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -145,7 +145,7 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_document(&self, document_id: u64) {
|
pub fn select_document(&self, document_id: u64) {
|
||||||
let message = PortfolioMessage::SelectDocument(document_id);
|
let message = PortfolioMessage::SelectDocument { document_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,12 +169,12 @@ impl JsEditorHandle {
|
|||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_auto_saved_document(&self, document_id: u64, document_name: String, document_is_saved: bool, document: String) {
|
pub fn open_auto_saved_document(&self, document_id: u64, document_name: String, document_is_saved: bool, document_serialized_content: String) {
|
||||||
let message = PortfolioMessage::OpenDocumentFileWithId {
|
let message = PortfolioMessage::OpenDocumentFileWithId {
|
||||||
document_id,
|
document_id,
|
||||||
document_name,
|
document_name,
|
||||||
document_is_saved,
|
document_is_saved,
|
||||||
document,
|
document_serialized_content,
|
||||||
};
|
};
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
@@ -185,12 +185,12 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trigger_auto_save(&self, document_id: u64) {
|
pub fn trigger_auto_save(&self, document_id: u64) {
|
||||||
let message = PortfolioMessage::AutoSaveDocument(document_id);
|
let message = PortfolioMessage::AutoSaveDocument { document_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_document(&self, document_id: u64) {
|
pub fn close_document(&self, document_id: u64) {
|
||||||
let message = PortfolioMessage::CloseDocument(document_id);
|
let message = PortfolioMessage::CloseDocument { document_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_document_with_confirmation(&self, document_id: u64) {
|
pub fn close_document_with_confirmation(&self, document_id: u64) {
|
||||||
let message = PortfolioMessage::CloseDocumentWithConfirmation(document_id);
|
let message = PortfolioMessage::CloseDocumentWithConfirmation { document_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ impl JsEditorHandle {
|
|||||||
pub fn bounds_of_viewports(&self, bounds_of_viewports: &[f64]) {
|
pub fn bounds_of_viewports(&self, bounds_of_viewports: &[f64]) {
|
||||||
let chunked: Vec<_> = bounds_of_viewports.chunks(4).map(ViewportBounds::from_slice).collect();
|
let chunked: Vec<_> = bounds_of_viewports.chunks(4).map(ViewportBounds::from_slice).collect();
|
||||||
|
|
||||||
let message = InputPreprocessorMessage::BoundsOfViewports(chunked);
|
let message = InputPreprocessorMessage::BoundsOfViewports { bounds_of_viewports: chunked };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
||||||
|
|
||||||
let message = InputPreprocessorMessage::MouseMove(editor_mouse_state, modifier_keys);
|
let message = InputPreprocessorMessage::MouseMove { editor_mouse_state, modifier_keys };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
||||||
|
|
||||||
let message = InputPreprocessorMessage::MouseScroll(editor_mouse_state, modifier_keys);
|
let message = InputPreprocessorMessage::MouseScroll { editor_mouse_state, modifier_keys };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
||||||
|
|
||||||
let message = InputPreprocessorMessage::MouseDown(editor_mouse_state, modifier_keys);
|
let message = InputPreprocessorMessage::MouseDown { editor_mouse_state, modifier_keys };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,29 +267,29 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
||||||
|
|
||||||
let message = InputPreprocessorMessage::MouseUp(editor_mouse_state, modifier_keys);
|
let message = InputPreprocessorMessage::MouseUp { editor_mouse_state, modifier_keys };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A keyboard button depressed within screenspace the bounds of the viewport
|
/// A keyboard button depressed within screenspace the bounds of the viewport
|
||||||
pub fn on_key_down(&self, name: String, modifiers: u8) {
|
pub fn on_key_down(&self, name: String, modifiers: u8) {
|
||||||
let key = translate_key(&name);
|
let key = translate_key(&name);
|
||||||
let modifiers = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
||||||
|
|
||||||
log::trace!("Key down {:?}, name: {}, modifiers: {:?}", key, name, modifiers);
|
log::trace!("Key down {:?}, name: {}, modifiers: {:?}", key, name, modifiers);
|
||||||
|
|
||||||
let message = InputPreprocessorMessage::KeyDown(key, modifiers);
|
let message = InputPreprocessorMessage::KeyDown { key, modifier_keys };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A keyboard button released
|
/// A keyboard button released
|
||||||
pub fn on_key_up(&self, name: String, modifiers: u8) {
|
pub fn on_key_up(&self, name: String, modifiers: u8) {
|
||||||
let key = translate_key(&name);
|
let key = translate_key(&name);
|
||||||
let modifiers = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys");
|
||||||
|
|
||||||
log::trace!("Key up {:?}, name: {}, modifiers: {:?}", key, name, modifiers);
|
log::trace!("Key up {:?}, name: {}, modifiers: {:?}", key, name, modifier_keys);
|
||||||
|
|
||||||
let message = InputPreprocessorMessage::KeyUp(key, modifiers);
|
let message = InputPreprocessorMessage::KeyUp { key, modifier_keys };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +300,7 @@ impl JsEditorHandle {
|
|||||||
None => return Err(Error::new("Invalid color").into()),
|
None => return Err(Error::new("Invalid color").into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = ToolMessage::SelectPrimaryColor(primary_color);
|
let message = ToolMessage::SelectPrimaryColor { color: primary_color };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -313,7 +313,7 @@ impl JsEditorHandle {
|
|||||||
None => return Err(Error::new("Invalid color").into()),
|
None => return Err(Error::new("Invalid color").into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = ToolMessage::SelectSecondaryColor(secondary_color);
|
let message = ToolMessage::SelectSecondaryColor { color: secondary_color };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -345,24 +345,24 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
/// Cut selected layers
|
/// Cut selected layers
|
||||||
pub fn cut(&self) {
|
pub fn cut(&self) {
|
||||||
let message = PortfolioMessage::Cut(Clipboard::User);
|
let message = PortfolioMessage::Cut { clipboard: Clipboard::User };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy selected layers
|
/// Copy selected layers
|
||||||
pub fn copy(&self) {
|
pub fn copy(&self) {
|
||||||
let message = PortfolioMessage::Copy(Clipboard::User);
|
let message = PortfolioMessage::Copy { clipboard: Clipboard::User };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paste selected layers
|
/// Paste selected layers
|
||||||
pub fn paste(&self) {
|
pub fn paste(&self) {
|
||||||
let message = PortfolioMessage::Paste(Clipboard::User);
|
let message = PortfolioMessage::Paste { clipboard: Clipboard::User };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_layer(&self, paths: Vec<LayerId>, ctrl: bool, shift: bool) {
|
pub fn select_layer(&self, layer_path: Vec<LayerId>, ctrl: bool, shift: bool) {
|
||||||
let message = DocumentMessage::SelectLayer(paths, ctrl, shift);
|
let message = DocumentMessage::SelectLayer { layer_path, ctrl, shift };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,35 +379,33 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reorder selected layer
|
/// Reorder selected layer
|
||||||
pub fn reorder_selected_layers(&self, delta: i32) {
|
pub fn reorder_selected_layers(&self, relative_index_offset: isize) {
|
||||||
let message = DocumentMessage::ReorderSelectedLayers(delta);
|
let message = DocumentMessage::ReorderSelectedLayers { relative_index_offset };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move a layer to be next to the specified neighbor
|
/// Move a layer to be next to the specified neighbor
|
||||||
pub fn move_layer_in_tree(&self, path: Vec<LayerId>, insert_index: isize) {
|
pub fn move_layer_in_tree(&self, folder_path: Vec<LayerId>, insert_index: isize) {
|
||||||
let message = DocumentMessage::MoveSelectedLayersTo { path, insert_index };
|
let message = DocumentMessage::MoveSelectedLayersTo { folder_path, insert_index };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the blend mode for the selected layers
|
/// Set the blend mode for the selected layers
|
||||||
pub fn set_blend_mode_for_selected_layers(&self, blend_mode_svg_style_name: String) -> Result<(), JsValue> {
|
pub fn set_blend_mode_for_selected_layers(&self, blend_mode_svg_style_name: String) -> Result<(), JsValue> {
|
||||||
let blend_mode = translate_blend_mode(blend_mode_svg_style_name.as_str());
|
if let Some(blend_mode) = translate_blend_mode(blend_mode_svg_style_name.as_str()) {
|
||||||
|
let message = DocumentMessage::SetBlendModeForSelectedLayers { blend_mode };
|
||||||
|
self.dispatch(message);
|
||||||
|
|
||||||
match blend_mode {
|
Ok(())
|
||||||
Some(mode) => {
|
} else {
|
||||||
let message = DocumentMessage::SetBlendModeForSelectedLayers(mode);
|
Err(Error::new(&EditorError::Misc("UnknownBlendMode".to_string()).to_string()).into())
|
||||||
self.dispatch(message);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
None => Err(Error::new(&EditorError::Misc("UnknownBlendMode".to_string()).to_string()).into()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the opacity for the selected layers
|
/// Set the opacity for the selected layers
|
||||||
pub fn set_opacity_for_selected_layers(&self, opacity_percent: f64) {
|
pub fn set_opacity_for_selected_layers(&self, opacity_percent: f64) {
|
||||||
let message = DocumentMessage::SetOpacityForSelectedLayers(opacity_percent / 100.);
|
let opacity = opacity_percent / 100.;
|
||||||
|
let message = DocumentMessage::SetOpacityForSelectedLayers { opacity };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,23 +416,24 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set snapping disabled / enabled
|
/// Set snapping disabled / enabled
|
||||||
pub fn set_snapping(&self, new_status: bool) {
|
pub fn set_snapping(&self, snap: bool) {
|
||||||
let message = DocumentMessage::SetSnapping(new_status);
|
let message = DocumentMessage::SetSnapping { snap };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the view mode to change the way layers are drawn in the viewport
|
/// Set the view mode to change the way layers are drawn in the viewport
|
||||||
pub fn set_view_mode(&self, new_mode: String) -> Result<(), JsValue> {
|
pub fn set_view_mode(&self, view_mode: String) -> Result<(), JsValue> {
|
||||||
match translate_view_mode(new_mode.as_str()) {
|
if let Some(view_mode) = translate_view_mode(view_mode.as_str()) {
|
||||||
Some(view_mode) => self.dispatch(DocumentMessage::SetViewMode(view_mode)),
|
self.dispatch(DocumentMessage::SetViewMode { view_mode });
|
||||||
None => return Err(Error::new("Invalid view mode").into()),
|
Ok(())
|
||||||
};
|
} else {
|
||||||
Ok(())
|
Err(Error::new("Invalid view mode").into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the zoom to the value
|
/// Sets the zoom to the value
|
||||||
pub fn set_canvas_zoom(&self, new_zoom: f64) {
|
pub fn set_canvas_zoom(&self, zoom_factor: f64) {
|
||||||
let message = MovementMessage::SetCanvasZoom(new_zoom);
|
let message = MovementMessage::SetCanvasZoom { zoom_factor };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,58 +450,57 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the rotation to the new value (in radians)
|
/// Sets the rotation to the new value (in radians)
|
||||||
pub fn set_rotation(&self, new_radians: f64) {
|
pub fn set_rotation(&self, angle_radians: f64) {
|
||||||
let message = MovementMessage::SetCanvasRotation(new_radians);
|
let message = MovementMessage::SetCanvasRotation { angle_radians };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates document (in viewport coords)
|
/// Translates document (in viewport coords)
|
||||||
pub fn translate_canvas(&self, delta_x: f64, delta_y: f64) {
|
pub fn translate_canvas(&self, delta_x: f64, delta_y: f64) {
|
||||||
let message = MovementMessage::TranslateCanvas((delta_x, delta_y).into());
|
let message = MovementMessage::TranslateCanvas { delta: (delta_x, delta_y).into() };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates document (in viewport coords)
|
/// Translates document (in viewport coords)
|
||||||
pub fn translate_canvas_by_fraction(&self, delta_x: f64, delta_y: f64) {
|
pub fn translate_canvas_by_fraction(&self, delta_x: f64, delta_y: f64) {
|
||||||
let message = MovementMessage::TranslateCanvasByViewportFraction((delta_x, delta_y).into());
|
let message = MovementMessage::TranslateCanvasByViewportFraction { delta: (delta_x, delta_y).into() };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the list of selected layers. The layer paths have to be stored in one array and are separated by LayerId::MAX
|
/// Update the list of selected layers. The layer paths have to be stored in one array and are separated by LayerId::MAX
|
||||||
pub fn select_layers(&self, paths: Vec<LayerId>) {
|
pub fn select_layers(&self, paths: Vec<LayerId>) {
|
||||||
let paths = paths.split(|id| *id == LayerId::MAX).map(|path| path.to_vec()).collect();
|
let replacement_selected_layers = paths.split(|id| *id == LayerId::MAX).map(|path| path.to_vec()).collect();
|
||||||
|
let message = DocumentMessage::SetSelectedLayers { replacement_selected_layers };
|
||||||
let message = DocumentMessage::SetSelectedLayers(paths);
|
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle visibility of a layer from the layer list
|
/// Toggle visibility of a layer from the layer list
|
||||||
pub fn toggle_layer_visibility(&self, path: Vec<LayerId>) {
|
pub fn toggle_layer_visibility(&self, layer_path: Vec<LayerId>) {
|
||||||
let message = DocumentMessage::ToggleLayerVisibility(path);
|
let message = DocumentMessage::ToggleLayerVisibility { layer_path };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle expansions state of a layer from the layer list
|
/// Toggle expansions state of a layer from the layer list
|
||||||
pub fn toggle_layer_expansion(&self, path: Vec<LayerId>) {
|
pub fn toggle_layer_expansion(&self, layer_path: Vec<LayerId>) {
|
||||||
let message = DocumentMessage::ToggleLayerExpansion(path);
|
let message = DocumentMessage::ToggleLayerExpansion { layer_path };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renames a layer from the layer list
|
/// Renames a layer from the layer list
|
||||||
pub fn rename_layer(&self, path: Vec<LayerId>, new_name: String) {
|
pub fn rename_layer(&self, layer_path: Vec<LayerId>, new_name: String) {
|
||||||
let message = DocumentMessage::RenameLayer(path, new_name);
|
let message = DocumentMessage::RenameLayer { layer_path, new_name };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes a layer from the layer list
|
/// Deletes a layer from the layer list
|
||||||
pub fn delete_layer(&self, path: Vec<LayerId>) {
|
pub fn delete_layer(&self, layer_path: Vec<LayerId>) {
|
||||||
let message = DocumentMessage::DeleteLayer(path);
|
let message = DocumentMessage::DeleteLayer { layer_path };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requests the backend to add a layer to the layer list
|
/// Requests the backend to add an empty folder inside the provided containing folder
|
||||||
pub fn add_folder(&self, path: Vec<LayerId>) {
|
pub fn add_folder(&self, container_path: Vec<LayerId>) {
|
||||||
let message = DocumentMessage::CreateEmptyFolder(path);
|
let message = DocumentMessage::CreateEmptyFolder { container_path };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,13 +550,13 @@ pub fn file_save_suffix() -> String {
|
|||||||
pub fn graphite_version() -> String {
|
pub fn graphite_version() -> String {
|
||||||
GRAPHITE_DOCUMENT_VERSION.to_string()
|
GRAPHITE_DOCUMENT_VERSION.to_string()
|
||||||
}
|
}
|
||||||
/// Get the constant i32::MAX
|
/// Get the constant `i32::MAX`
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn i32_max() -> i32 {
|
pub fn i32_max() -> i32 {
|
||||||
i32::MAX
|
i32::MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the constant i32::MIN
|
/// Get the constant `i32::MIN`
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn i32_min() -> i32 {
|
pub fn i32_min() -> i32 {
|
||||||
i32::MIN
|
i32::MIN
|
||||||
|
|||||||
@@ -537,7 +537,7 @@ impl Document {
|
|||||||
return Err(DocumentError::IndexOutOfBounds);
|
return Err(DocumentError::IndexOutOfBounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::RenameLayer { path, name } => {
|
Operation::RenameLayer { layer_path: path, new_name: name } => {
|
||||||
self.layer_mut(path)?.name = Some(name.clone());
|
self.layer_mut(path)?.name = Some(name.clone());
|
||||||
Some(vec![LayerChanged { path: path.clone() }])
|
Some(vec![LayerChanged { path: path.clone() }])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ pub enum Operation {
|
|||||||
path: Vec<LayerId>,
|
path: Vec<LayerId>,
|
||||||
},
|
},
|
||||||
RenameLayer {
|
RenameLayer {
|
||||||
path: Vec<LayerId>,
|
layer_path: Vec<LayerId>,
|
||||||
name: String,
|
new_name: String,
|
||||||
},
|
},
|
||||||
InsertLayer {
|
InsertLayer {
|
||||||
layer: Layer,
|
layer: Layer,
|
||||||
|
|||||||
Reference in New Issue
Block a user