mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 03:18:06 +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:
@@ -14,14 +14,23 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum DocumentMessage {
|
||||
AbortTransaction,
|
||||
AddSelectedLayers(Vec<Vec<LayerId>>),
|
||||
AlignSelectedLayers(AlignAxis, AlignAggregate),
|
||||
AddSelectedLayers {
|
||||
additional_layers: Vec<Vec<LayerId>>,
|
||||
},
|
||||
AlignSelectedLayers {
|
||||
axis: AlignAxis,
|
||||
aggregate: AlignAggregate,
|
||||
},
|
||||
#[child]
|
||||
Artboard(ArtboardMessage),
|
||||
CommitTransaction,
|
||||
CreateEmptyFolder(Vec<LayerId>),
|
||||
CreateEmptyFolder {
|
||||
container_path: Vec<LayerId>,
|
||||
},
|
||||
DebugPrintDocument,
|
||||
DeleteLayer(Vec<LayerId>),
|
||||
DeleteLayer {
|
||||
layer_path: Vec<LayerId>,
|
||||
},
|
||||
DeleteSelectedLayers,
|
||||
DeselectAllLayers,
|
||||
DirtyRenderDocument,
|
||||
@@ -32,41 +41,78 @@ pub enum DocumentMessage {
|
||||
DocumentStructureChanged,
|
||||
DuplicateSelectedLayers,
|
||||
ExportDocument,
|
||||
FlipSelectedLayers(FlipAxis),
|
||||
FolderChanged(Vec<LayerId>),
|
||||
FlipSelectedLayers {
|
||||
flip_axis: FlipAxis,
|
||||
},
|
||||
FolderChanged {
|
||||
affected_folder_path: Vec<LayerId>,
|
||||
},
|
||||
GroupSelectedLayers,
|
||||
LayerChanged(Vec<LayerId>),
|
||||
LayerChanged {
|
||||
affected_layer_path: Vec<LayerId>,
|
||||
},
|
||||
#[child]
|
||||
Movement(MovementMessage),
|
||||
MoveSelectedLayersTo {
|
||||
path: Vec<LayerId>,
|
||||
folder_path: Vec<LayerId>,
|
||||
insert_index: isize,
|
||||
},
|
||||
NudgeSelectedLayers(f64, f64),
|
||||
NudgeSelectedLayers {
|
||||
delta_x: f64,
|
||||
delta_y: f64,
|
||||
},
|
||||
#[child]
|
||||
Overlays(OverlaysMessage),
|
||||
Redo,
|
||||
RenameLayer(Vec<LayerId>, String),
|
||||
RenameLayer {
|
||||
layer_path: Vec<LayerId>,
|
||||
new_name: String,
|
||||
},
|
||||
RenderDocument,
|
||||
ReorderSelectedLayers(i32), // relative_position,
|
||||
ReorderSelectedLayers {
|
||||
relative_index_offset: isize,
|
||||
},
|
||||
RollbackTransaction,
|
||||
SaveDocument,
|
||||
SelectAllLayers,
|
||||
SelectionChanged,
|
||||
SelectLayer(Vec<LayerId>, bool, bool),
|
||||
SetBlendModeForSelectedLayers(BlendMode),
|
||||
SetLayerExpansion(Vec<LayerId>, bool),
|
||||
SetOpacityForSelectedLayers(f64),
|
||||
SetSelectedLayers(Vec<Vec<LayerId>>),
|
||||
SetSnapping(bool),
|
||||
SetViewMode(ViewMode),
|
||||
SelectLayer {
|
||||
layer_path: Vec<LayerId>,
|
||||
ctrl: bool,
|
||||
shift: bool,
|
||||
},
|
||||
SetBlendModeForSelectedLayers {
|
||||
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,
|
||||
ToggleLayerExpansion(Vec<LayerId>),
|
||||
ToggleLayerVisibility(Vec<LayerId>),
|
||||
ToggleLayerExpansion {
|
||||
layer_path: Vec<LayerId>,
|
||||
},
|
||||
ToggleLayerVisibility {
|
||||
layer_path: Vec<LayerId>,
|
||||
},
|
||||
#[child]
|
||||
TransformLayers(TransformLayerMessage),
|
||||
Undo,
|
||||
UngroupLayers(Vec<LayerId>),
|
||||
UngroupLayers {
|
||||
folder_path: Vec<LayerId>,
|
||||
},
|
||||
UngroupSelectedLayers,
|
||||
UpdateLayerMetadata {
|
||||
layer_path: Vec<LayerId>,
|
||||
|
||||
@@ -340,7 +340,7 @@ impl DocumentMessageHandler {
|
||||
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
||||
self.document_redo_history.push((document, layer_metadata));
|
||||
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(())
|
||||
}
|
||||
@@ -358,7 +358,7 @@ impl DocumentMessageHandler {
|
||||
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
||||
self.document_undo_history.push((document, layer_metadata));
|
||||
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(())
|
||||
}
|
||||
@@ -446,15 +446,15 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
self.undo(responses).unwrap_or_else(|e| log::warn!("{}", e));
|
||||
responses.extend([RenderDocument.into(), DocumentStructureChanged.into()]);
|
||||
}
|
||||
AddSelectedLayers(paths) => {
|
||||
for path in paths {
|
||||
responses.extend(self.select_layer(&path));
|
||||
AddSelectedLayers { additional_layers } => {
|
||||
for layer_path in additional_layers {
|
||||
responses.extend(self.select_layer(&layer_path));
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
AlignSelectedLayers(axis, aggregate) => {
|
||||
AlignSelectedLayers { axis, aggregate } => {
|
||||
self.backup(responses);
|
||||
let (paths, boxes): (Vec<_>, Vec<_>) = self
|
||||
.selected_layers()
|
||||
@@ -499,16 +499,22 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
);
|
||||
}
|
||||
CommitTransaction => (),
|
||||
CreateEmptyFolder(mut path) => {
|
||||
CreateEmptyFolder { mut container_path } => {
|
||||
let id = generate_uuid();
|
||||
path.push(id);
|
||||
responses.push_back(DocumentOperation::CreateFolder { path: path.clone() }.into());
|
||||
responses.push_back(DocumentMessage::SetLayerExpansion(path, true).into());
|
||||
container_path.push(id);
|
||||
responses.push_back(DocumentOperation::CreateFolder { path: container_path.clone() }.into());
|
||||
responses.push_back(
|
||||
DocumentMessage::SetLayerExpansion {
|
||||
layer_path: container_path,
|
||||
set_expanded: true,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
DebugPrintDocument => {
|
||||
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 => {
|
||||
self.backup(responses);
|
||||
|
||||
@@ -519,7 +525,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
responses.push_front(ToolMessage::DocumentIsDirty.into());
|
||||
}
|
||||
DeselectAllLayers => {
|
||||
responses.push_front(SetSelectedLayers(vec![]).into());
|
||||
responses.push_front(SetSelectedLayers { replacement_selected_layers: vec![] }.into());
|
||||
self.layer_range_selection_reference.clear();
|
||||
}
|
||||
DirtyRenderDocument => {
|
||||
@@ -537,20 +543,25 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
Ok(Some(document_responses)) => {
|
||||
for response in document_responses {
|
||||
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 } => {
|
||||
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 } => {
|
||||
if self.layer_metadata.contains_key(path) {
|
||||
log::warn!("CreatedLayer overrides existing layer metadata.");
|
||||
}
|
||||
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();
|
||||
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()),
|
||||
};
|
||||
@@ -596,9 +607,9 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
FlipSelectedLayers(axis) => {
|
||||
FlipSelectedLayers { flip_axis } => {
|
||||
self.backup(responses);
|
||||
let scale = match axis {
|
||||
let scale = match flip_axis {
|
||||
FlipAxis::X => 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());
|
||||
}
|
||||
}
|
||||
FolderChanged(path) => {
|
||||
FolderChanged { affected_folder_path } => {
|
||||
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 => {
|
||||
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());
|
||||
|
||||
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(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(
|
||||
PortfolioMessage::PasteIntoFolder {
|
||||
clipboard: Clipboard::System,
|
||||
path: new_folder_path.clone(),
|
||||
folder_path: new_folder_path.clone(),
|
||||
insert_index: -1,
|
||||
}
|
||||
.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) => {
|
||||
if let Ok(layer_entry) = self.layer_panel_entry(path) {
|
||||
LayerChanged { affected_layer_path } => {
|
||||
if let Ok(layer_entry) = self.layer_panel_entry(affected_layer_path) {
|
||||
responses.push_back(FrontendMessage::UpdateDocumentLayer { data: layer_entry }.into());
|
||||
}
|
||||
}
|
||||
Movement(message) => self.movement_handler.process_action(message, (&self.graphene_document, ipp), responses),
|
||||
MoveSelectedLayersTo { path, insert_index } => {
|
||||
let layers = self.selected_layers().collect::<Vec<_>>();
|
||||
MoveSelectedLayersTo { folder_path, insert_index } => {
|
||||
let selected_layers = self.selected_layers().collect::<Vec<_>>();
|
||||
|
||||
// Trying to insert into self.
|
||||
if layers.iter().any(|layer| path.starts_with(layer)) {
|
||||
// Prevent trying to insert into self
|
||||
if selected_layers.iter().any(|layer| folder_path.starts_with(layer)) {
|
||||
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(
|
||||
PortfolioMessage::PasteIntoFolder {
|
||||
clipboard: Clipboard::System,
|
||||
path,
|
||||
folder_path,
|
||||
insert_index,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
NudgeSelectedLayers(x, y) => {
|
||||
NudgeSelectedLayers { delta_x, delta_y } => {
|
||||
self.backup(responses);
|
||||
for path in self.selected_layers().map(|path| path.to_vec()) {
|
||||
let operation = DocumentOperation::TransformLayerInViewport {
|
||||
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());
|
||||
}
|
||||
@@ -695,9 +714,9 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
responses.push_back(DocumentHistoryForward.into());
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.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 => {
|
||||
responses.push_back(
|
||||
FrontendMessage::UpdateDocumentArtwork {
|
||||
@@ -743,32 +762,55 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
ReorderSelectedLayers(relative_position) => {
|
||||
ReorderSelectedLayers { relative_index_offset } => {
|
||||
self.backup(responses);
|
||||
|
||||
let all_layer_paths = self.all_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.last(),
|
||||
_ => unreachable!(),
|
||||
} {
|
||||
let all_layer_paths: Vec<_> = all_layer_paths
|
||||
_ => panic!("ReorderSelectedLayers must be given a non-zero value"),
|
||||
};
|
||||
|
||||
if let Some(pivot_layer) = first_or_last_selected_layer {
|
||||
let sibling_layer_paths: Vec<_> = all_layer_paths
|
||||
.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();
|
||||
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
|
||||
let insert_index = if relative_position < 0 { layer_index } else { layer_index + 1 };
|
||||
// TODO: Break this out into a reusable function: `fn layer_index_in_containing_folder(layer_path) -> usize`
|
||||
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 => {
|
||||
let all_layer_paths = self.all_layers();
|
||||
responses.push_front(SetSelectedLayers(all_layer_paths.map(|path| path.to_vec()).collect()).into());
|
||||
let all = self.all_layers().map(|path| path.to_vec()).collect();
|
||||
responses.push_front(SetSelectedLayers { replacement_selected_layers: all }.into());
|
||||
}
|
||||
SelectionChanged => {
|
||||
// TODO: Hoist this duplicated code into wider system
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||
}
|
||||
SelectLayer(selected, ctrl, shift) => {
|
||||
SelectLayer { layer_path, ctrl, shift } => {
|
||||
let mut paths = vec![];
|
||||
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
|
||||
self.layer_metadata
|
||||
.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, _)| {
|
||||
paths.push(layer_path.clone());
|
||||
});
|
||||
} else {
|
||||
if 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;
|
||||
responses.push_back(LayerChanged(selected.clone()).into());
|
||||
responses.push_back(
|
||||
LayerChanged {
|
||||
affected_layer_path: layer_path.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||
} else {
|
||||
paths.push(selected.clone());
|
||||
paths.push(layer_path.clone());
|
||||
}
|
||||
|
||||
// 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
|
||||
if !paths.is_empty() {
|
||||
// Add or set our selected layers
|
||||
if ctrl {
|
||||
responses.push_front(AddSelectedLayers(paths).into());
|
||||
responses.push_front(AddSelectedLayers { additional_layers: paths }.into());
|
||||
} 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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
SetLayerExpansion(path, is_expanded) => {
|
||||
self.layer_metadata_mut(&path).expanded = is_expanded;
|
||||
SetLayerExpansion { layer_path, set_expanded } => {
|
||||
self.layer_metadata_mut(&layer_path).expanded = set_expanded;
|
||||
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);
|
||||
let opacity = opacity.clamp(0., 1.);
|
||||
|
||||
@@ -861,30 +908,31 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
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);
|
||||
selected.for_each(|(path, layer_metadata)| {
|
||||
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) => {
|
||||
self.snapping_enabled = new_status;
|
||||
SetSnapping { snap } => {
|
||||
self.snapping_enabled = snap;
|
||||
}
|
||||
SetViewMode(mode) => {
|
||||
self.view_mode = mode;
|
||||
SetViewMode { view_mode } => {
|
||||
self.view_mode = view_mode;
|
||||
responses.push_front(DocumentMessage::DirtyRenderDocument.into());
|
||||
}
|
||||
StartTransaction => self.backup(responses),
|
||||
ToggleLayerExpansion(path) => {
|
||||
self.layer_metadata_mut(&path).expanded ^= true;
|
||||
ToggleLayerExpansion { layer_path } => {
|
||||
self.layer_metadata_mut(&layer_path).expanded ^= true;
|
||||
responses.push_back(DocumentStructureChanged.into());
|
||||
responses.push_back(LayerChanged(path).into())
|
||||
responses.push_back(LayerChanged { affected_layer_path: layer_path }.into())
|
||||
}
|
||||
ToggleLayerVisibility(path) => {
|
||||
responses.push_back(DocumentOperation::ToggleLayerVisibility { path }.into());
|
||||
ToggleLayerVisibility { layer_path } => {
|
||||
responses.push_back(DocumentOperation::ToggleLayerVisibility { path: layer_path }.into());
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||
}
|
||||
TransformLayers(message) => self
|
||||
@@ -895,24 +943,26 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
|
||||
responses.push_back(DocumentHistoryBackward.into());
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.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
|
||||
let to_select = self.graphene_document.folder_children_paths(&folder_path);
|
||||
let select = self.graphene_document.folder_children_paths(&folder_path);
|
||||
|
||||
let message_buffer = [
|
||||
// Select them
|
||||
DocumentMessage::SetSelectedLayers { replacement_selected_layers: select }.into(),
|
||||
// Copy them
|
||||
DocumentMessage::SetSelectedLayers(to_select).into(),
|
||||
PortfolioMessage::Copy(Clipboard::System).into(),
|
||||
PortfolioMessage::Copy { clipboard: Clipboard::System }.into(),
|
||||
// Paste them into the folder above
|
||||
PortfolioMessage::PasteIntoFolder {
|
||||
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,
|
||||
}
|
||||
.into(),
|
||||
// Delete parent folder
|
||||
DocumentMessage::DeleteLayer(folder_path).into(),
|
||||
// Delete the parent folder
|
||||
DocumentMessage::DeleteLayer { layer_path: folder_path }.into(),
|
||||
];
|
||||
|
||||
// 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());
|
||||
let folder_paths = self.graphene_document.sorted_folders_by_depth(self.selected_layers());
|
||||
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());
|
||||
}
|
||||
UpdateLayerMetadata { layer_path: path, layer_metadata } => {
|
||||
self.layer_metadata.insert(path, layer_metadata);
|
||||
UpdateLayerMetadata { layer_path, layer_metadata } => {
|
||||
self.layer_metadata.insert(layer_path, layer_metadata);
|
||||
}
|
||||
ZoomCanvasToFitAll => {
|
||||
if let Some(bounds) = self.document_bounds() {
|
||||
|
||||
@@ -26,12 +26,20 @@ pub enum MovementMessage {
|
||||
zoom_from_viewport: Option<DVec2>,
|
||||
},
|
||||
RotateCanvasBegin,
|
||||
SetCanvasRotation(f64),
|
||||
SetCanvasZoom(f64),
|
||||
SetCanvasRotation {
|
||||
angle_radians: f64,
|
||||
},
|
||||
SetCanvasZoom {
|
||||
zoom_factor: f64,
|
||||
},
|
||||
TransformCanvasEnd,
|
||||
TranslateCanvas(DVec2),
|
||||
TranslateCanvas {
|
||||
delta: DVec2,
|
||||
},
|
||||
TranslateCanvasBegin,
|
||||
TranslateCanvasByViewportFraction(DVec2),
|
||||
TranslateCanvasByViewportFraction {
|
||||
delta: DVec2,
|
||||
},
|
||||
WheelCanvasTranslate {
|
||||
use_y_as_x: bool,
|
||||
},
|
||||
|
||||
@@ -106,7 +106,7 @@ impl MovementMessageHandler {
|
||||
let mouse_fraction = mouse / viewport_bounds;
|
||||
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 {
|
||||
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 {
|
||||
bounds: [bounds_corner_a, bounds_corner_b],
|
||||
@@ -158,7 +158,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
if center_on_mouse {
|
||||
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 {
|
||||
snap_angle,
|
||||
@@ -169,7 +169,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
if self.panning {
|
||||
let delta = ipp.mouse.position - self.mouse_position;
|
||||
|
||||
responses.push_back(TranslateCanvas(delta).into());
|
||||
responses.push_back(TranslateCanvas { delta }.into());
|
||||
}
|
||||
|
||||
if self.tilting {
|
||||
@@ -190,7 +190,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
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 {
|
||||
@@ -210,10 +210,10 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
if let Some(mouse) = zoom_from_viewport {
|
||||
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));
|
||||
} else {
|
||||
responses.push_back(SetCanvasZoom(self.zoom).into());
|
||||
responses.push_back(SetCanvasZoom { zoom_factor: self.zoom }.into());
|
||||
}
|
||||
}
|
||||
self.mouse_position = ipp.mouse.position;
|
||||
@@ -222,14 +222,14 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
self.tilting = true;
|
||||
self.mouse_position = ipp.mouse.position;
|
||||
}
|
||||
SetCanvasRotation(new_radians) => {
|
||||
self.tilt = new_radians;
|
||||
SetCanvasRotation { angle_radians } => {
|
||||
self.tilt = angle_radians;
|
||||
self.create_document_transform(&ipp.viewport_bounds, responses);
|
||||
responses.push_back(ToolMessage::DocumentIsDirty.into());
|
||||
responses.push_back(FrontendMessage::UpdateCanvasRotation { angle_radians: self.snapped_angle() }.into());
|
||||
}
|
||||
SetCanvasZoom(new) => {
|
||||
self.zoom = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
|
||||
SetCanvasZoom { zoom_factor } => {
|
||||
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(ToolMessage::DocumentIsDirty.into());
|
||||
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
|
||||
@@ -246,7 +246,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
self.tilting = false;
|
||||
self.zooming = false;
|
||||
}
|
||||
TranslateCanvas(delta) => {
|
||||
TranslateCanvas { delta } => {
|
||||
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
|
||||
|
||||
self.pan += transformed_delta;
|
||||
@@ -257,7 +257,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
self.panning = true;
|
||||
self.mouse_position = ipp.mouse.position;
|
||||
}
|
||||
TranslateCanvasByViewportFraction(delta) => {
|
||||
TranslateCanvasByViewportFraction { delta } => {
|
||||
let transformed_delta = document.root.transform.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
|
||||
|
||||
self.pan += transformed_delta;
|
||||
@@ -269,7 +269,7 @@ impl MessageHandler<MovementMessage, (&Document, &InputPreprocessorMessageHandle
|
||||
false => -ipp.mouse.scroll_delta.as_dvec2(),
|
||||
true => (-ipp.mouse.scroll_delta.y as f64, 0.).into(),
|
||||
} * VIEWPORT_SCROLL_RATE;
|
||||
responses.push_back(TranslateCanvas(delta).into());
|
||||
responses.push_back(TranslateCanvas { delta }.into());
|
||||
}
|
||||
WheelCanvasZoom => {
|
||||
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(SetCanvasZoom(self.zoom * zoom_factor).into());
|
||||
responses.push_back(SetCanvasZoom { zoom_factor: self.zoom * zoom_factor }.into());
|
||||
}
|
||||
ZoomCanvasBegin => {
|
||||
self.zooming = true;
|
||||
|
||||
@@ -10,14 +10,24 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum PortfolioMessage {
|
||||
AutoSaveActiveDocument,
|
||||
AutoSaveDocument(u64),
|
||||
AutoSaveDocument {
|
||||
document_id: u64,
|
||||
},
|
||||
CloseActiveDocumentWithConfirmation,
|
||||
CloseAllDocuments,
|
||||
CloseAllDocumentsWithConfirmation,
|
||||
CloseDocument(u64),
|
||||
CloseDocumentWithConfirmation(u64),
|
||||
Copy(Clipboard),
|
||||
Cut(Clipboard),
|
||||
CloseDocument {
|
||||
document_id: u64,
|
||||
},
|
||||
CloseDocumentWithConfirmation {
|
||||
document_id: u64,
|
||||
},
|
||||
Copy {
|
||||
clipboard: Clipboard,
|
||||
},
|
||||
Cut {
|
||||
clipboard: Clipboard,
|
||||
},
|
||||
#[child]
|
||||
Document(DocumentMessage),
|
||||
NewDocument,
|
||||
@@ -25,19 +35,23 @@ pub enum PortfolioMessage {
|
||||
OpenDocument,
|
||||
OpenDocumentFile(String, String),
|
||||
OpenDocumentFileWithId {
|
||||
document: String,
|
||||
document_name: String,
|
||||
document_id: u64,
|
||||
document_name: String,
|
||||
document_is_saved: bool,
|
||||
document_serialized_content: String,
|
||||
},
|
||||
Paste {
|
||||
clipboard: Clipboard,
|
||||
},
|
||||
Paste(Clipboard),
|
||||
PasteIntoFolder {
|
||||
clipboard: Clipboard,
|
||||
path: Vec<LayerId>,
|
||||
folder_path: Vec<LayerId>,
|
||||
insert_index: isize,
|
||||
},
|
||||
PrevDocument,
|
||||
RequestAboutGraphiteDialog,
|
||||
SelectDocument(u64),
|
||||
SelectDocument {
|
||||
document_id: u64,
|
||||
},
|
||||
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>) {
|
||||
// Special case when loading a document on an empty page
|
||||
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
|
||||
.document_ids
|
||||
@@ -92,7 +92,7 @@ impl PortfolioMessageHandler {
|
||||
|
||||
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.
|
||||
@@ -129,15 +129,15 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
||||
use PortfolioMessage::*;
|
||||
#[remain::sorted]
|
||||
match message {
|
||||
AutoSaveActiveDocument => responses.push_back(PortfolioMessage::AutoSaveDocument(self.active_document_id).into()),
|
||||
AutoSaveDocument(id) => {
|
||||
let document = self.documents.get(&id).unwrap();
|
||||
AutoSaveActiveDocument => responses.push_back(PortfolioMessage::AutoSaveDocument { document_id: self.active_document_id }.into()),
|
||||
AutoSaveDocument { document_id } => {
|
||||
let document = self.documents.get(&document_id).unwrap();
|
||||
responses.push_back(
|
||||
FrontendMessage::TriggerIndexedDbWriteDocument {
|
||||
document: document.serialize_document(),
|
||||
details: FrontendDocumentDetails {
|
||||
is_saved: document.is_saved(),
|
||||
id,
|
||||
id: document_id,
|
||||
name: document.name.clone(),
|
||||
},
|
||||
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
|
||||
@@ -146,7 +146,7 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
||||
)
|
||||
}
|
||||
CloseActiveDocumentWithConfirmation => {
|
||||
responses.push_back(PortfolioMessage::CloseDocumentWithConfirmation(self.active_document_id).into());
|
||||
responses.push_back(PortfolioMessage::CloseDocumentWithConfirmation { document_id: self.active_document_id }.into());
|
||||
}
|
||||
CloseAllDocuments => {
|
||||
// Empty the list of internal document data
|
||||
@@ -159,9 +159,9 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
||||
CloseAllDocumentsWithConfirmation => {
|
||||
responses.push_back(FrontendMessage::DisplayConfirmationToCloseAllDocuments.into());
|
||||
}
|
||||
CloseDocument(id) => {
|
||||
let document_index = self.document_index(id);
|
||||
self.documents.remove(&id);
|
||||
CloseDocument { document_id } => {
|
||||
let document_index = self.document_index(document_id);
|
||||
self.documents.remove(&document_id);
|
||||
self.document_ids.remove(document_index);
|
||||
|
||||
// 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.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
|
||||
self.active_document_id
|
||||
} 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::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(DocumentMessage::DocumentStructureChanged.into());
|
||||
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) => {
|
||||
let target_document = self.documents.get(&id).unwrap();
|
||||
CloseDocumentWithConfirmation { document_id } => {
|
||||
let target_document = self.documents.get(&document_id).unwrap();
|
||||
if target_document.is_saved() {
|
||||
responses.push_back(PortfolioMessage::CloseDocument(id).into());
|
||||
responses.push_back(PortfolioMessage::CloseDocument { document_id }.into());
|
||||
} else {
|
||||
responses.push_back(FrontendMessage::DisplayConfirmationToCloseDocument { document_id: id }.into());
|
||||
responses.push_back(FrontendMessage::DisplayConfirmationToCloseDocument { document_id }.into());
|
||||
// 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`
|
||||
let active_document = self.documents.get(&self.active_document_id).unwrap();
|
||||
|
||||
@@ -230,8 +230,8 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
||||
}
|
||||
}
|
||||
}
|
||||
Cut(clipboard) => {
|
||||
responses.push_back(Copy(clipboard).into());
|
||||
Cut { clipboard } => {
|
||||
responses.push_back(Copy { clipboard }.into());
|
||||
responses.push_back(DeleteSelectedLayers.into());
|
||||
}
|
||||
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 next_index = (current_index + 1) % self.document_ids.len();
|
||||
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 => {
|
||||
responses.push_back(FrontendMessage::TriggerFileUpload.into());
|
||||
}
|
||||
OpenDocumentFile(document_name, document) => {
|
||||
OpenDocumentFile(document_name, document_serialized_content) => {
|
||||
responses.push_back(
|
||||
PortfolioMessage::OpenDocumentFileWithId {
|
||||
document,
|
||||
document_name,
|
||||
document_id: generate_uuid(),
|
||||
document_name,
|
||||
document_is_saved: true,
|
||||
document_serialized_content,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
OpenDocumentFileWithId {
|
||||
document_name,
|
||||
document_id,
|
||||
document,
|
||||
document_name,
|
||||
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 {
|
||||
Ok(mut document) => {
|
||||
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 shallowest_common_folder = document
|
||||
.graphene_document
|
||||
@@ -294,14 +294,18 @@ impl MessageHandler<PortfolioMessage, &InputPreprocessorMessageHandler> for Port
|
||||
responses.push_back(
|
||||
PasteIntoFolder {
|
||||
clipboard,
|
||||
path: shallowest_common_folder.to_vec(),
|
||||
folder_path: shallowest_common_folder.to_vec(),
|
||||
insert_index: -1,
|
||||
}
|
||||
.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<_>| {
|
||||
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 prev_index = (current_index + len - 1) % len;
|
||||
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 => {
|
||||
responses.push_back(FrontendMessage::DisplayDialogAboutGraphite.into());
|
||||
}
|
||||
SelectDocument(id) => {
|
||||
SelectDocument { document_id } => {
|
||||
let active_document = self.active_document();
|
||||
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;
|
||||
responses.push_back(FrontendMessage::UpdateActiveDocument { document_id: id }.into());
|
||||
self.active_document_id = document_id;
|
||||
responses.push_back(FrontendMessage::UpdateActiveDocument { document_id }.into());
|
||||
responses.push_back(RenderDocument.into());
|
||||
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,6 @@ pub enum TransformLayerMessage {
|
||||
MouseMove { slow_key: Key, snap_key: Key },
|
||||
TypeBackspace,
|
||||
TypeDecimalPoint,
|
||||
TypeDigit { digit: u8 },
|
||||
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),
|
||||
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),
|
||||
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,
|
||||
CancelTransformOperation,
|
||||
ApplyTransformOperation,
|
||||
TypeNumber,
|
||||
TypeDigit,
|
||||
TypeBackspace,
|
||||
TypeDecimalPoint,
|
||||
TypeNegate,
|
||||
|
||||
Reference in New Issue
Block a user