Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
// Rust Analyzer config
"rust-analyzer.experimental.procAttrMacros": true,
"rust-analyzer.cargo.target": "wasm32-unknown-unknown",
"rust-analyzer.checkOnSave.command": "clippy",
// ESLint config
"eslint.format.enable": true,
"eslint.workingDirectories": [
Expand Down
8 changes: 6 additions & 2 deletions editor/src/communication/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateLayer),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::DisplayFolderTreeStructure),
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateOpenDocumentsList),
MessageDiscriminant::Tool(ToolMessageDiscriminant::SelectedLayersChanged),
MessageDiscriminant::Tool(ToolMessageDiscriminant::DocumentIsDirty),
];

impl Dispatcher {
Expand Down Expand Up @@ -338,16 +338,20 @@ mod test {
assert_eq!(&layers_after_copy[5], ellipse_before_copy);
}
#[test]
#[ignore] // TODO: Re-enable test, see issue #444 (https://github.com/GraphiteEditor/Graphite/pull/444)
/// - create rect, shape and ellipse
/// - select ellipse and rect
/// - move them down and back up again
fn move_selection() {
init_logger();
let mut editor = create_editor_with_three_layers();

let sorted_layers = editor.dispatcher.documents_message_handler.active_document().all_layers_sorted();
println!("Sorted layers: {:?}", sorted_layers);

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

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

editor.handle_message(DocumentMessage::ReorderSelectedLayers(1));
let (all, non_selected, selected) = verify_order(&mut editor.dispatcher.documents_message_handler.active_document_mut());
Expand Down
137 changes: 72 additions & 65 deletions editor/src/document/document_file.rs

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions editor/src/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ impl DocumentsMessageHandler {
.document_ids
.iter()
.filter_map(|id| {
self.documents.get(&id).map(|doc| FrontendDocumentDetails {
is_saved: doc.is_saved(),
self.documents.get(id).map(|document| FrontendDocumentDetails {
is_saved: document.is_saved(),
id: *id,
name: doc.name.clone(),
name: document.name.clone(),
})
})
.collect::<Vec<_>>();
Expand Down
18 changes: 9 additions & 9 deletions editor/src/document/layer_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl LayerData {
}

pub fn layer_panel_entry(layer_data: &LayerData, transform: DAffine2, layer: &Layer, path: Vec<LayerId>) -> LayerPanelEntry {
let layer_type: LayerType = (&layer.data).into();
let layer_type: LayerDataTypeDiscriminant = (&layer.data).into();
let name = layer.name.clone().unwrap_or_else(|| format!("Unnamed {}", layer_type));
let arr = layer.data.bounding_box(transform).unwrap_or([DVec2::ZERO, DVec2::ZERO]);
let arr = arr.iter().map(|x| (*x).into()).collect::<Vec<(f64, f64)>>();
Expand Down Expand Up @@ -103,35 +103,35 @@ pub struct LayerPanelEntry {
pub visible: bool,
pub blend_mode: BlendMode,
pub opacity: f64,
pub layer_type: LayerType,
pub layer_type: LayerDataTypeDiscriminant,
pub layer_data: LayerData,
pub path: Vec<LayerId>,
pub thumbnail: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum LayerType {
pub enum LayerDataTypeDiscriminant {
Folder,
Shape,
}

impl fmt::Display for LayerType {
impl fmt::Display for LayerDataTypeDiscriminant {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
LayerType::Folder => "Folder",
LayerType::Shape => "Shape",
LayerDataTypeDiscriminant::Folder => "Folder",
LayerDataTypeDiscriminant::Shape => "Shape",
};

formatter.write_str(name)
}
}

impl From<&LayerDataType> for LayerType {
impl From<&LayerDataType> for LayerDataTypeDiscriminant {
fn from(data: &LayerDataType) -> Self {
use LayerDataType::*;
match data {
Folder(_) => LayerType::Folder,
Shape(_) => LayerType::Shape,
Folder(_) => LayerDataTypeDiscriminant::Folder,
Shape(_) => LayerDataTypeDiscriminant::Shape,
}
}
}
3 changes: 3 additions & 0 deletions editor/src/document/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod document_file;
mod document_message_handler;
pub mod layer_panel;
mod movement_handler;
mod overlay_message_handler;
mod transform_layer_handler;
mod vectorize_layerdata;

Expand All @@ -15,4 +16,6 @@ pub use document_message_handler::{Clipboard, DocumentsMessage, DocumentsMessage
#[doc(inline)]
pub use movement_handler::{MovementMessage, MovementMessageDiscriminant};
#[doc(inline)]
pub use overlay_message_handler::{OverlayMessage, OverlayMessageDiscriminant};
#[doc(inline)]
pub use transform_layer_handler::{TransformLayerMessage, TransformLayerMessageDiscriminant};
99 changes: 50 additions & 49 deletions editor/src/document/movement_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl MovementMessageHandler {

impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreprocessor)> for MovementMessageHandler {
fn process_action(&mut self, message: MovementMessage, data: (&mut LayerData, &Document, &InputPreprocessor), responses: &mut VecDeque<Message>) {
let (layerdata, document, ipp) = data;
let (layer_data, document, ipp) = data;
use MovementMessage::*;
match message {
TranslateCanvasBegin => {
Expand All @@ -89,7 +89,8 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
self.mouse_pos = ipp.mouse.position;
}
TransformCanvasEnd => {
layerdata.rotation = self.snapped_angle(layerdata);
layer_data.rotation = self.snapped_angle(layer_data);
responses.push_back(ToolMessage::DocumentIsDirty.into());
self.snap_rotate = false;
self.translating = false;
self.rotating = false;
Expand All @@ -100,9 +101,9 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
let delta = ipp.mouse.position - self.mouse_pos;
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);

layerdata.translation += transformed_delta;
responses.push_back(ToolMessage::SelectedLayersChanged.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
layer_data.translation += transformed_delta;
responses.push_back(ToolMessage::DocumentIsDirty.into());
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
if self.rotating {
let half_viewport = ipp.viewport_bounds.size() / 2.;
Expand All @@ -114,51 +115,51 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces

let snapping = self.snapping;

layerdata.rotation += rotation;
layer_data.rotation += rotation;
responses.push_back(ToolMessage::DocumentIsDirty.into());
self.snap_rotate = snapping;
responses.push_back(ToolMessage::SelectedLayersChanged.into());
responses.push_back(
FrontendMessage::SetCanvasRotation {
new_radians: self.snapped_angle(layerdata),
new_radians: self.snapped_angle(layer_data),
}
.into(),
);
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
if self.zooming {
let difference = self.mouse_pos.y as f64 - ipp.mouse.position.y as f64;
let amount = 1. + difference * VIEWPORT_ZOOM_MOUSE_RATE;

let new = (layerdata.scale * amount).clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
layerdata.scale = new;
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
responses.push_back(ToolMessage::SelectedLayersChanged.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
let new = (layer_data.scale * amount).clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
layer_data.scale = new;
responses.push_back(ToolMessage::DocumentIsDirty.into());
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into());
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
self.mouse_pos = ipp.mouse.position;
}
SetCanvasZoom(new) => {
layerdata.scale = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
responses.push_back(ToolMessage::SelectedLayersChanged.into());
layer_data.scale = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
responses.push_back(ToolMessage::DocumentIsDirty.into());
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into());
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
IncreaseCanvasZoom => {
// TODO: Eliminate redundant code by making this call SetCanvasZoom
layerdata.scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > layerdata.scale).unwrap_or(&layerdata.scale);
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
responses.push_back(ToolMessage::SelectedLayersChanged.into());
layer_data.scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > layer_data.scale).unwrap_or(&layer_data.scale);
responses.push_back(ToolMessage::DocumentIsDirty.into());
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into());
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
DecreaseCanvasZoom => {
// TODO: Eliminate redundant code by making this call SetCanvasZoom
layerdata.scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < layerdata.scale).unwrap_or(&layerdata.scale);
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
responses.push_back(ToolMessage::SelectedLayersChanged.into());
layer_data.scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < layer_data.scale).unwrap_or(&layer_data.scale);
responses.push_back(ToolMessage::DocumentIsDirty.into());
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into());
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
WheelCanvasZoom => {
// TODO: Eliminate redundant code by making this call SetCanvasZoom
Expand All @@ -175,29 +176,29 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
let delta = delta_size * (DVec2::splat(0.5) - mouse_fraction);

let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
let new = (layerdata.scale * zoom_factor).clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
layerdata.scale = new;
layerdata.translation += transformed_delta;
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
responses.push_back(ToolMessage::SelectedLayersChanged.into());
let new = (layer_data.scale * zoom_factor).clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX);
layer_data.scale = new;
layer_data.translation += transformed_delta;
responses.push_back(ToolMessage::DocumentIsDirty.into());
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into());
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
WheelCanvasTranslate { use_y_as_x } => {
let delta = match use_y_as_x {
false => -ipp.mouse.scroll_delta.as_dvec2(),
true => (-ipp.mouse.scroll_delta.y as f64, 0.).into(),
} * VIEWPORT_SCROLL_RATE;
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
layerdata.translation += transformed_delta;
responses.push_back(ToolMessage::SelectedLayersChanged.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
layer_data.translation += transformed_delta;
responses.push_back(ToolMessage::DocumentIsDirty.into());
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
SetCanvasRotation(new) => {
layerdata.rotation = new;
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
layer_data.rotation = new;
responses.push_back(ToolMessage::DocumentIsDirty.into());
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
responses.push_back(FrontendMessage::SetCanvasRotation { new_radians: new }.into());
responses.push_back(ToolMessage::SelectedLayersChanged.into());
}
ZoomCanvasToFitAll => {
if let Some([pos1, pos2]) = document.visible_layers_bounding_box() {
Expand All @@ -211,27 +212,27 @@ impl MessageHandler<MovementMessage, (&mut LayerData, &Document, &InputPreproces
let size = 1. / size;
let new_scale = size.min_element();

layerdata.translation += center;
layerdata.scale *= new_scale;
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layerdata.scale }.into());
responses.push_back(ToolMessage::SelectedLayersChanged.into());
layer_data.translation += center;
layer_data.scale *= new_scale;
responses.push_back(ToolMessage::DocumentIsDirty.into());
responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into());
responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
}
TranslateCanvas(delta) => {
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);

layerdata.translation += transformed_delta;
responses.push_back(ToolMessage::SelectedLayersChanged.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
layer_data.translation += transformed_delta;
responses.push_back(ToolMessage::DocumentIsDirty.into());
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
TranslateCanvasByViewportFraction(delta) => {
let transformed_delta = document.root.transform.inverse().transform_vector2(delta * ipp.viewport_bounds.size());

layerdata.translation += transformed_delta;
responses.push_back(ToolMessage::SelectedLayersChanged.into());
self.create_document_transform_from_layerdata(layerdata, &ipp.viewport_bounds, responses);
layer_data.translation += transformed_delta;
responses.push_back(ToolMessage::DocumentIsDirty.into());
self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses);
}
}
}
Expand Down
58 changes: 58 additions & 0 deletions editor/src/document/overlay_message_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
pub use crate::document::layer_panel::*;
use crate::document::{DocumentMessage, LayerData};
use crate::input::InputPreprocessor;
use crate::message_prelude::*;
use graphene::document::Document;
use graphene::Operation as DocumentOperation;

use graphene::document::Document as GrapheneDocument;
use graphene::layers::style::ViewMode;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};

#[impl_message(Message, DocumentMessage, Overlay)]
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum OverlayMessage {
DispatchOperation(Box<DocumentOperation>),
ClearAllOverlays,
}

impl From<DocumentOperation> for OverlayMessage {
fn from(operation: DocumentOperation) -> OverlayMessage {
Self::DispatchOperation(Box::new(operation))
}
}

#[derive(Debug, Clone, Default)]
pub struct OverlayMessageHandler {
pub overlays_graphene_document: GrapheneDocument,
overlay_path_mapping: HashMap<Vec<LayerId>, Vec<LayerId>>,
}

impl MessageHandler<OverlayMessage, (&mut LayerData, &Document, &InputPreprocessor)> for OverlayMessageHandler {
fn process_action(&mut self, message: OverlayMessage, data: (&mut LayerData, &Document, &InputPreprocessor), responses: &mut VecDeque<Message>) {
let (layerdata, document, ipp) = data;
use OverlayMessage::*;
match message {
DispatchOperation(operation) => match self.overlays_graphene_document.handle_operation(&operation) {
Ok(_) => (),
Err(e) => log::error!("OverlayError: {:?}", e),
},
ClearAllOverlays => todo!(),
}

// Render overlays
responses.push_back(
FrontendMessage::UpdateOverlays {
svg: self.overlays_graphene_document.render_root(ViewMode::Normal),
}
.into(),
);
}

fn actions(&self) -> ActionList {
actions!(OverlayMessageDiscriminant;
ClearAllOverlays
)
}
}
Loading