Refactor internal shape and reduce reliance on Kurbo (#617)

* Dissolve Points from path

* Add handling for removing the first anchor

* Add function to turn handles into bez_paths

* Created overlay manager, wip

* WIP Refactor of VectorShape / Overlays / ShapeEditor

* WIP stripping vector shape, anchor, point.

* WIP Removed kurbo deps from vector shape, anchor, point

* WIP Further work to make vector shapes / anchors / points more standalone.

* WIP more pruning

* WIP Progress on overlay_renderer

* WIP more overlay_renderer work

* WIP more pruning, cleared warnings

* WIP decided ShapeRenderer wasn't an accurate name, ShapeAdapter now. Error squashing continues.

* WIP squashed more errors, now need to decide if anchors should have unique IDs

* WIP Errors squashed, now to actually make it work.

* WIP Moved vector structs to graphene, beginning to remove bezpath from shape_layer

* Refactoring: disentangle kurbo from apply_affine

* Refactor internal shape and remove reliance on Kurbo (PR #617) - Disentangle Kurbo (#619)

* Refactoring: disentangle kurbo from apply_affine

* Broke boolean operations, refactor in state which compiles

* "fixed" boolean operation refactor related errors

* fixed apply_affine, which would not have applied any type of affine

* Small Cleanup, readability

* Fix issue with overlay styles no longer showing selection state.

* Resolved error with point option

* WIP, figuring out how to have one source of truth for VectorShape. Trying to avoid cloning.

* WIP work on single source of truth vectorshapes

* More steps toward single source of truth VectorShape

* Continued wip on making VectorShapes mutably accessible without cloning

* Wip using paths to reference vectorshapes instead, need to restructure ShapeEditor

* Decided to allow temporary copies of vectorshapes.

* Removed HashSet for selected shape indices

* Added @TrueDoctor's id_storage.rs with some heavy modification. Added it to VectorShape. Isn't yet used for folders.

* Integrated UniqueElements<T> with VectorShape to store VectorAnchors

* Improved storage_id.rs perf and cleaned up it's interface

* Iterator Implementations and fixes (#637)

* Refactoring: disentangle kurbo from apply_affine

* Broke boolean operations, refactor in state which compiles

* "fixed" boolean operation refactor related errors

* fixed apply_affine, which would not have applied any type of affine

* implemented transforms for VectorAnchors
implemented Not for VectorControlPointType

* started adding Vector Shape implementations of shape prototypes

* added several useful implemtations to UniqueElements

* added another implemnation for UniqueElements to make working with iterators easier, fixed vector-shape errors

* package-lock.json

* clean up rebase, added back Layer paths

* added deref implementation for VectorShape

* unnecesary variable

* simplify code by removing levels of indirection

* fixed errors

* merge cleanup

* removed package-lock.json

* Removed .selected from VectorShape, it isn't needed as layers are selected not shapes specifically.

* Removed transform and layer_path from VectorShape

* Auto-saving tentitively working. Work toward Overlay transform issues.

* Overlays properly hiding and caching. Not clearing cache yet and some tool switching issues remain, but progress.

* Putting layers in folders changes their unique ID. This is problematic. Assumed this was not the case.

* Removed need for closed bool, changed VectorShape to a tuple struct.

* WIP Switched to layer paths as opposed to VectorShapes. Next up add messages for changing VectorShapes.

* Added initial messages to edit VectorShape points.

* DeleteSelectedPoints messages implemented, selection isn't working currently though.

* Selection messages arriving in document, but transform is wrong.

* Selection, Deselection working, delete working for first point.

* Working towards moving points again

* Removed extra vec from UniqueElements, attempting to squash ordering bug. Still appears to occur though.

* Delete more stable, clean up, renamed to HandleIn, HandleOut

* Further vec_unique cleanup

* Further cleanup

* Removed Deref / DerefMut from VectorShape

* Document version++, will likely revert before merge into master

* Seleting / deleting handles tentitively working again.

* Version number bump, fixed tests.

* Fixed comment in VecUnique

* Improved VecUnique descriptor comment

* Renamed VecUnique to IdBackedVec to further clarify usage.

* Resolved formatting.

* WIP Fixing dragging points

* Fixed an instance where an OverlayMessage could be sent to the main document incorrectly.

* Deleting all of a shapes points now gracefully deletes the layer instead of crashing.

* Fixed handle configurations that would panic on deletion

* Single anchor dragging restored with multi-dragging next plus handles

* sides.into()

* Handle and Multi-point dragging working

* WIP Handle symmetry working again

* Handle mirroring functional again.

* Cleaned up warnings

* Fixed overlay outline not matching shape

* Git branch fix of compatibility with new master

* Fixed closed shape bug, replaced kurbo ellipse

* Removed unused func, updated comments

* Deleting points can undo, multiple shape selection deletes now working

* Removed AddOverlay* operations

* Partial fix for select drift, added helpers

* Don't snap against dragging points

* Properly cleanup path outline with multiple shapes

* Clear all points in other selected shapes

* Actually don't snap against dragging points

* Fix path tool & add snap angle and break handle

* Fix handle being set to NaN causing render issues

* Fix cached overlays not showing line -> curve

* Add operations for modifying paths

* Remove kurbo from pen tool

* Do not snap against handles when anchor selected

* Fix overlays not being cleaned up on path tool

* Fix handle position after dragging

* Use `Anchor` for text & no kurbo in operations

* Replace kurbo to_svg function

* Ngon no longer center scales by default, still some weird behaviour when holding alt

* Cleanup overlays

* Fix render and bounding box doctests

* Fix fun to_svg error

* Fix compile error

* Some code review

* Remove legacy `SelectPoint` on doubleclick

* Remove font from test document

* Fix the pen tool selection changed

* Reorder imports

Co-authored-by: Dennis <dennis@kobert.dev>
Co-authored-by: Caleb Dennis <caleb.dennis429@gmail.com>
Co-authored-by: caleb <56044292+caleb-ad@users.noreply.github.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
Co-authored-by: 0hypercube <0hypercube@gmail.com>
Co-authored-by: 0HyperCube <78500760+0HyperCube@users.noreply.github.com>
This commit is contained in:
Oliver Davies
2022-07-05 15:02:18 -07:00
committed by Keavon Chambers
parent 3c2fff4465
commit 58675eb64d
48 changed files with 2461 additions and 1807 deletions

View File

@@ -53,7 +53,9 @@ pub enum DocumentMessage {
layer_path: Vec<LayerId>,
},
DeleteSelectedLayers,
DeleteSelectedVectorPoints,
DeselectAllLayers,
DeselectAllVectorPoints,
DirtyRenderDocument,
DirtyRenderDocumentInOutlineView,
DocumentHistoryBackward,
@@ -81,6 +83,11 @@ pub enum DocumentMessage {
insert_index: isize,
reverse_index: bool,
},
MoveSelectedVectorPoints {
layer_path: Vec<LayerId>,
delta: (f64, f64),
absolute_position: (f64, f64),
},
NudgeSelectedLayers {
delta_x: f64,
delta_y: f64,
@@ -144,6 +151,11 @@ pub enum DocumentMessage {
ToggleLayerVisibility {
layer_path: Vec<LayerId>,
},
ToggleSelectedHandleMirroring {
layer_path: Vec<LayerId>,
toggle_distance: bool,
toggle_angle: bool,
},
Undo,
UngroupLayers {
folder_path: Vec<LayerId>,

View File

@@ -14,7 +14,6 @@ use crate::layout::widgets::{
SeparatorDirection, SeparatorType, Widget, WidgetCallback, WidgetHolder, WidgetLayout,
};
use crate::message_prelude::*;
use crate::viewport_tools::vector_editor::vector_shape::VectorShape;
use crate::EditorError;
use graphene::color::Color;
@@ -24,6 +23,7 @@ use graphene::layers::folder_layer::FolderLayer;
use graphene::layers::layer_info::{LayerDataType, LayerDataTypeDiscriminant};
use graphene::layers::style::{Fill, RenderData, ViewMode};
use graphene::layers::text_layer::{Font, FontCache};
use graphene::layers::vector::vector_shape::VectorShape;
use graphene::{DocumentError, DocumentResponse, LayerId, Operation as DocumentOperation};
use glam::{DAffine2, DVec2};
@@ -158,28 +158,6 @@ impl DocumentMessageHandler {
self.artboard_message_handler.artboards_graphene_document.bounding_box_and_transform(path, font_cache).unwrap_or(None)
}
/// Create a new vector shape representation with the underlying kurbo data, VectorManipulatorShape
pub fn selected_visible_layers_vector_shapes(&self, responses: &mut VecDeque<Message>, font_cache: &FontCache) -> Vec<VectorShape> {
let shapes = self.selected_layers().filter_map(|path_to_shape| {
let viewport_transform = self.graphene_document.generate_transform_relative_to_viewport(path_to_shape).ok()?;
let layer = self.graphene_document.layer(path_to_shape);
match &layer {
Ok(layer) if layer.visible => {}
_ => return None,
};
// TODO: Create VectorManipulatorShape when creating a kurbo shape as a stopgap, rather than on each new selection
match &layer.ok()?.data {
LayerDataType::Shape(shape) => Some(VectorShape::new(path_to_shape.to_vec(), viewport_transform, &shape.path, shape.closed, responses)),
LayerDataType::Text(text) => Some(VectorShape::new(path_to_shape.to_vec(), viewport_transform, &text.to_bez_path_nonmut(font_cache), true, responses)),
_ => None,
}
});
shapes.collect::<Vec<VectorShape>>()
}
pub fn selected_layers(&self) -> impl Iterator<Item = &[LayerId]> {
self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then(|| path.as_slice()))
}
@@ -223,6 +201,22 @@ impl DocumentMessageHandler {
})
}
/// Returns a copy of all the currently selected VectorShapes.
pub fn selected_vector_shapes(&self) -> Vec<VectorShape> {
self.selected_visible_layers()
.flat_map(|layer| self.graphene_document.layer(layer))
.flat_map(|layer| layer.as_vector_shape_copy())
.collect::<Vec<VectorShape>>()
}
/// Returns references to all the currently selected VectorShapes.
pub fn selected_vector_shapes_ref(&self) -> Vec<&VectorShape> {
self.selected_visible_layers()
.flat_map(|layer| self.graphene_document.layer(layer))
.flat_map(|layer| layer.as_vector_shape())
.collect::<Vec<&VectorShape>>()
}
/// Returns the bounding boxes for all visible layers and artboards, optionally excluding any paths.
pub fn bounding_boxes<'a>(&'a self, ignore_document: Option<&'a Vec<Vec<LayerId>>>, ignore_artboard: Option<LayerId>, font_cache: &'a FontCache) -> impl Iterator<Item = [DVec2; 2]> + 'a {
self.visible_layers()
@@ -998,14 +992,28 @@ impl MessageHandler<DocumentMessage, (&InputPreprocessorMessageHandler, &FontCac
responses.push_front(BroadcastSignal::SelectionChanged.into());
responses.push_back(BroadcastSignal::DocumentIsDirty.into());
}
DeleteSelectedVectorPoints => {
responses.push_back(StartTransaction.into());
responses.push_front(
DocumentOperation::DeleteSelectedVectorPoints {
layer_paths: self.selected_layers_without_children().iter().map(|path| path.to_vec()).collect(),
}
.into(),
);
}
DeselectAllLayers => {
responses.push_front(SetSelectedLayers { replacement_selected_layers: vec![] }.into());
self.layer_range_selection_reference.clear();
}
DeselectAllVectorPoints => {
for layer_path in self.selected_layers_without_children() {
responses.push_back(DocumentOperation::DeselectAllVectorPoints { layer_path: layer_path.to_vec() }.into());
}
}
DirtyRenderDocument => {
// Mark all non-overlay caches as dirty
GrapheneDocument::mark_children_as_dirty(&mut self.graphene_document.root);
responses.push_back(DocumentMessage::RenderDocument.into());
}
DirtyRenderDocumentInOutlineView => {
@@ -1163,6 +1171,12 @@ impl MessageHandler<DocumentMessage, (&InputPreprocessorMessageHandler, &FontCac
.into(),
);
}
MoveSelectedVectorPoints { layer_path, delta, absolute_position } => {
self.backup(responses);
if let Ok(_layer) = self.graphene_document.layer(&layer_path) {
responses.push_back(DocumentOperation::MoveSelectedVectorPoints { layer_path, delta, absolute_position }.into());
}
}
NudgeSelectedLayers { delta_x, delta_y } => {
self.backup(responses);
for path in self.selected_layers().map(|path| path.to_vec()) {
@@ -1462,6 +1476,20 @@ impl MessageHandler<DocumentMessage, (&InputPreprocessorMessageHandler, &FontCac
responses.push_back(DocumentOperation::ToggleLayerVisibility { path: layer_path }.into());
responses.push_back(BroadcastSignal::DocumentIsDirty.into());
}
ToggleSelectedHandleMirroring {
layer_path,
toggle_distance,
toggle_angle,
} => {
responses.push_back(
DocumentOperation::SetSelectedHandleMirroring {
layer_path,
toggle_distance,
toggle_angle,
}
.into(),
);
}
Undo => {
responses.push_back(BroadcastSignal::ToolAbort.into());
responses.push_back(DocumentHistoryBackward.into());

View File

@@ -1,11 +1,12 @@
use super::clipboards::{CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
use super::{DocumentMessageHandler, MenuBarMessageHandler};
use crate::consts::{DEFAULT_DOCUMENT_NAME, GRAPHITE_DOCUMENT_VERSION};
use crate::dialog;
use crate::frontend::utility_types::FrontendDocumentDetails;
use crate::input::InputPreprocessorMessageHandler;
use crate::layout::layout_message::LayoutTarget;
use crate::layout::widgets::PropertyHolder;
use crate::{dialog, message_prelude::*};
use crate::message_prelude::*;
use graphene::layers::layer_info::LayerDataTypeDiscriminant;
use graphene::layers::text_layer::{Font, FontCache};