Fix Pen tool race condition when drawing handles fast, and stuck overlays (#1283)
* Fix pen tool with async * Fix overlays staying too long * Perhaps fix the transform issue * Fix compile error * Formatting --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
4d1c5fc8bf
commit
abd8e7fab6
|
|
@ -276,6 +276,7 @@ impl<'a> VectorModificationState<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_position(&mut self, point: ManipulatorPointId, position: DVec2) {
|
fn set_position(&mut self, point: ManipulatorPointId, position: DVec2) {
|
||||||
|
assert!(position.is_finite(), "Point position should be finite");
|
||||||
for subpath in self.subpaths.iter_mut() {
|
for subpath in self.subpaths.iter_mut() {
|
||||||
if let Some(manipulator) = subpath.manipulator_mut_from_id(point.group) {
|
if let Some(manipulator) = subpath.manipulator_mut_from_id(point.group) {
|
||||||
match point.manipulator_type {
|
match point.manipulator_type {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ const POINT_STROKE_WEIGHT: f64 = 2.;
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct OverlayRenderer {
|
pub struct OverlayRenderer {
|
||||||
shape_overlay_cache: HashMap<LayerId, Vec<LayerId>>,
|
shape_overlay_cache: HashMap<LayerId, Vec<LayerId>>,
|
||||||
manipulator_group_overlay_cache: HashMap<(LayerId, ManipulatorGroupId), ManipulatorGroupOverlays>,
|
manipulator_group_overlay_cache: HashMap<LayerId, HashMap<ManipulatorGroupId, ManipulatorGroupOverlays>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OverlayRenderer {
|
impl OverlayRenderer {
|
||||||
|
|
@ -68,7 +68,7 @@ impl OverlayRenderer {
|
||||||
|
|
||||||
// Create, place, and style the manipulator overlays
|
// Create, place, and style the manipulator overlays
|
||||||
for manipulator_group in vector_data.manipulator_groups() {
|
for manipulator_group in vector_data.manipulator_groups() {
|
||||||
let manipulator_group_cache = self.manipulator_group_overlay_cache.entry((*layer_id, manipulator_group.id)).or_default();
|
let manipulator_group_cache = self.manipulator_group_overlay_cache.entry(*layer_id).or_default().entry(manipulator_group.id).or_default();
|
||||||
|
|
||||||
// Only view in and out handles if they are not on top of the anchor
|
// Only view in and out handles if they are not on top of the anchor
|
||||||
let [in_handle, out_handle] = {
|
let [in_handle, out_handle] = {
|
||||||
|
|
@ -103,6 +103,19 @@ impl OverlayRenderer {
|
||||||
Self::place_manipulator_group_overlays(manipulator_group, manipulator_group_cache, &transform, responses);
|
Self::place_manipulator_group_overlays(manipulator_group, manipulator_group_cache, &transform, responses);
|
||||||
Self::style_overlays(selected_shape_state, &layer_path, manipulator_group, manipulator_group_cache, responses);
|
Self::style_overlays(selected_shape_state, &layer_path, manipulator_group, manipulator_group_cache, responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(layer_overlays) = self.manipulator_group_overlay_cache.get_mut(layer_id) {
|
||||||
|
if layer_overlays.len() > vector_data.manipulator_groups().count() {
|
||||||
|
layer_overlays.retain(|manipulator, manipulator_group_overlays| {
|
||||||
|
if vector_data.manipulator_groups().any(|current_manipulator| current_manipulator.id == *manipulator) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
Self::remove_manipulator_group_overlays(manipulator_group_overlays, responses);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO Handle removing shapes from cache so we don't memory leak
|
// TODO Handle removing shapes from cache so we don't memory leak
|
||||||
// Eventually will get replaced with am immediate mode renderer for overlays
|
// Eventually will get replaced with am immediate mode renderer for overlays
|
||||||
}
|
}
|
||||||
|
|
@ -120,16 +133,10 @@ impl OverlayRenderer {
|
||||||
self.shape_overlay_cache.remove(layer_id);
|
self.shape_overlay_cache.remove(layer_id);
|
||||||
|
|
||||||
// Remove the ManipulatorGroup overlays
|
// Remove the ManipulatorGroup overlays
|
||||||
if let Ok(layer) = document.layer(&layer_path) {
|
let Some(layer_cache) = self.manipulator_group_overlay_cache.remove(layer_id) else { return };
|
||||||
if let Some(vector_data) = layer.as_vector_data() {
|
|
||||||
for manipulator_group in vector_data.manipulator_groups() {
|
for manipulator_group_overlays in layer_cache.values() {
|
||||||
let id = manipulator_group.id;
|
|
||||||
if let Some(manipulator_group_overlays) = self.manipulator_group_overlay_cache.get(&(*layer_id, id)) {
|
|
||||||
Self::remove_manipulator_group_overlays(manipulator_group_overlays, responses);
|
Self::remove_manipulator_group_overlays(manipulator_group_overlays, responses);
|
||||||
self.manipulator_group_overlay_cache.remove(&(*layer_id, id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,14 +149,19 @@ impl OverlayRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide the manipulator group overlays
|
// Hide the manipulator group overlays
|
||||||
if let Ok(layer) = document.layer(&layer_path) {
|
let Some(manipulator_groups) = self.manipulator_group_overlay_cache.get(layer_id) else { return };
|
||||||
if let Some(vector_data) = layer.as_vector_data() {
|
if visibility {
|
||||||
|
let Ok(layer) = document.layer(&layer_path) else { return };
|
||||||
|
let Some(vector_data) = layer.as_vector_data() else { return };
|
||||||
for manipulator_group in vector_data.manipulator_groups() {
|
for manipulator_group in vector_data.manipulator_groups() {
|
||||||
let id = manipulator_group.id;
|
let id = manipulator_group.id;
|
||||||
if let Some(manipulator_group_overlays) = self.manipulator_group_overlay_cache.get(&(*layer_id, id)) {
|
if let Some(manipulator_group_overlays) = manipulator_groups.get(&id) {
|
||||||
Self::set_manipulator_group_overlay_visibility(manipulator_group_overlays, visibility, responses);
|
Self::set_manipulator_group_overlay_visibility(manipulator_group_overlays, visibility, responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for manipulator_group_overlays in manipulator_groups.values() {
|
||||||
|
Self::set_manipulator_group_overlay_visibility(manipulator_group_overlays, visibility, responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,10 @@ use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
|
use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
|
||||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||||
|
|
||||||
|
use bezier_rs::Subpath;
|
||||||
use document_legacy::LayerId;
|
use document_legacy::LayerId;
|
||||||
|
use graph_craft::document::value::TaggedValue;
|
||||||
|
use graph_craft::document::NodeInput;
|
||||||
use graphene_core::uuid::ManipulatorGroupId;
|
use graphene_core::uuid::ManipulatorGroupId;
|
||||||
use graphene_core::vector::style::{Fill, Stroke};
|
use graphene_core::vector::style::{Fill, Stroke};
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||||
|
|
@ -227,8 +230,8 @@ impl PenToolData {
|
||||||
self.subpath_index = subpath_index;
|
self.subpath_index = subpath_index;
|
||||||
|
|
||||||
// Stop the handles on the first point from mirroring
|
// Stop the handles on the first point from mirroring
|
||||||
let Some(vector_data) = document.document_legacy.layer(layer).ok().and_then(|layer| layer.as_vector_data()) else { return };
|
let Some(subpaths) = get_subpaths(layer, document) else { return };
|
||||||
let manipulator_groups = vector_data.subpaths[subpath_index].manipulator_groups();
|
let manipulator_groups = subpaths[subpath_index].manipulator_groups();
|
||||||
let Some(last_handle) = (if from_start { manipulator_groups.first() } else { manipulator_groups.last() }) else { return };
|
let Some(last_handle) = (if from_start { manipulator_groups.first() } else { manipulator_groups.last() }) else { return };
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
|
|
@ -284,8 +287,7 @@ impl PenToolData {
|
||||||
fn check_break(&mut self, document: &DocumentMessageHandler, transform: DAffine2, shape_overlay: &mut OverlayRenderer, responses: &mut VecDeque<Message>) -> Option<()> {
|
fn check_break(&mut self, document: &DocumentMessageHandler, transform: DAffine2, shape_overlay: &mut OverlayRenderer, responses: &mut VecDeque<Message>) -> Option<()> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer_path = self.path.as_ref()?;
|
let layer_path = self.path.as_ref()?;
|
||||||
let vector_data = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_vector_data())?;
|
let subpath = &get_subpaths(layer_path, document)?[self.subpath_index];
|
||||||
let subpath = &vector_data.subpaths[self.subpath_index];
|
|
||||||
|
|
||||||
// Get the last manipulator group and the one previous to that
|
// Get the last manipulator group and the one previous to that
|
||||||
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
||||||
|
|
@ -336,8 +338,7 @@ impl PenToolData {
|
||||||
fn finish_placing_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, shape_overlay: &mut OverlayRenderer, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
fn finish_placing_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, shape_overlay: &mut OverlayRenderer, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer_path = self.path.as_ref()?;
|
let layer_path = self.path.as_ref()?;
|
||||||
let vector_data = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_vector_data())?;
|
let subpath = &get_subpaths(layer_path, document)?[self.subpath_index];
|
||||||
let subpath = &vector_data.subpaths[self.subpath_index];
|
|
||||||
|
|
||||||
// Get the last manipulator group and the one previous to that
|
// Get the last manipulator group and the one previous to that
|
||||||
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
||||||
|
|
@ -415,8 +416,7 @@ impl PenToolData {
|
||||||
fn drag_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
fn drag_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer_path = self.path.as_ref()?;
|
let layer_path = self.path.as_ref()?;
|
||||||
let vector_data = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_vector_data())?;
|
let subpath = &get_subpaths(layer_path, document)?[self.subpath_index];
|
||||||
let subpath = &vector_data.subpaths[self.subpath_index];
|
|
||||||
|
|
||||||
// Get the last manipulator group
|
// Get the last manipulator group
|
||||||
let manipulator_groups = subpath.manipulator_groups();
|
let manipulator_groups = subpath.manipulator_groups();
|
||||||
|
|
@ -433,6 +433,9 @@ impl PenToolData {
|
||||||
let pos = transform.inverse().transform_point2(mouse);
|
let pos = transform.inverse().transform_point2(mouse);
|
||||||
|
|
||||||
let pos = compute_snapped_angle(&mut self.angle, modifiers.lock_angle, modifiers.snap_angle, pos, last_anchor);
|
let pos = compute_snapped_angle(&mut self.angle, modifiers.lock_angle, modifiers.snap_angle, pos, last_anchor);
|
||||||
|
if !pos.is_finite() {
|
||||||
|
return Some(PenToolFsmState::DraggingHandle);
|
||||||
|
}
|
||||||
|
|
||||||
// Update points on current segment (to show preview of new handle)
|
// Update points on current segment (to show preview of new handle)
|
||||||
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
||||||
|
|
@ -466,8 +469,7 @@ impl PenToolData {
|
||||||
fn place_anchor(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
fn place_anchor(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer_path = self.path.as_ref()?;
|
let layer_path = self.path.as_ref()?;
|
||||||
let vector_data = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_vector_data())?;
|
let subpath = &get_subpaths(layer_path, document)?[self.subpath_index];
|
||||||
let subpath = &vector_data.subpaths[self.subpath_index];
|
|
||||||
|
|
||||||
// Get the last manipulator group and the one previous to that
|
// Get the last manipulator group and the one previous to that
|
||||||
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
||||||
|
|
@ -512,8 +514,7 @@ impl PenToolData {
|
||||||
fn finish_transaction(&mut self, fsm: PenToolFsmState, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Option<DocumentMessage> {
|
fn finish_transaction(&mut self, fsm: PenToolFsmState, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Option<DocumentMessage> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer_path = self.path.as_ref()?;
|
let layer_path = self.path.as_ref()?;
|
||||||
let vector_data = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_vector_data())?;
|
let subpath = &get_subpaths(layer_path, document)?[self.subpath_index];
|
||||||
let subpath = &vector_data.subpaths[self.subpath_index];
|
|
||||||
|
|
||||||
// Abort if only one manipulator group has been placed
|
// Abort if only one manipulator group has been placed
|
||||||
if fsm == PenToolFsmState::PlacingAnchor && subpath.len() < 3 {
|
if fsm == PenToolFsmState::PlacingAnchor && subpath.len() < 3 {
|
||||||
|
|
@ -576,7 +577,20 @@ impl Fsm for PenToolFsmState {
|
||||||
tool_options: &Self::ToolOptions,
|
tool_options: &Self::ToolOptions,
|
||||||
responses: &mut VecDeque<Message>,
|
responses: &mut VecDeque<Message>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let transform = tool_data.path.as_ref().and_then(|path| document.document_legacy.multiply_transforms(path).ok()).unwrap_or_default();
|
let mut transform = tool_data.path.as_ref().and_then(|path| document.document_legacy.multiply_transforms(path).ok()).unwrap_or_default();
|
||||||
|
|
||||||
|
if !transform.inverse().is_finite() {
|
||||||
|
let parent_transform = tool_data
|
||||||
|
.path
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|layer_path| document.document_legacy.multiply_transforms(&layer_path[..layer_path.len() - 1]).ok());
|
||||||
|
|
||||||
|
transform = parent_transform.unwrap_or(DAffine2::IDENTITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !transform.inverse().is_finite() {
|
||||||
|
transform = DAffine2::IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
if let ToolMessage::Pen(event) = event {
|
if let ToolMessage::Pen(event) = event {
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
|
|
@ -753,8 +767,8 @@ fn should_extend(document: &DocumentMessageHandler, pos: DVec2, tolerance: f64)
|
||||||
for layer_path in document.selected_layers() {
|
for layer_path in document.selected_layers() {
|
||||||
let Ok(viewspace) = document.document_legacy.generate_transform_relative_to_viewport(layer_path) else { continue };
|
let Ok(viewspace) = document.document_legacy.generate_transform_relative_to_viewport(layer_path) else { continue };
|
||||||
|
|
||||||
let Some(vector_data) = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_vector_data()) else { continue };
|
let subpaths = get_subpaths(layer_path, document)?;
|
||||||
for (subpath_index, subpath) in vector_data.subpaths.iter().enumerate() {
|
for (subpath_index, subpath) in subpaths.iter().enumerate() {
|
||||||
if subpath.closed() {
|
if subpath.closed() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -774,3 +788,19 @@ fn should_extend(document: &DocumentMessageHandler, pos: DVec2, tolerance: f64)
|
||||||
|
|
||||||
best
|
best
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_subpaths<'a>(layer_path: &[LayerId], document: &'a DocumentMessageHandler) -> Option<&'a Vec<Subpath<ManipulatorGroupId>>> {
|
||||||
|
let layer = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_layer().ok())?;
|
||||||
|
let network = &layer.network;
|
||||||
|
for (node, _node_id) in network.primary_flow() {
|
||||||
|
if node.name == "Path Generator" {
|
||||||
|
let subpaths_input = node.inputs.get(0)?;
|
||||||
|
let NodeInput::Value { tagged_value: TaggedValue::Subpaths(subpaths), .. } = subpaths_input else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Some(subpaths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,13 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||||
|
|
||||||
/// Insert a manipulator group at an index.
|
/// Insert a manipulator group at an index.
|
||||||
pub fn insert_manipulator_group(&mut self, index: usize, group: ManipulatorGroup<ManipulatorGroupId>) {
|
pub fn insert_manipulator_group(&mut self, index: usize, group: ManipulatorGroup<ManipulatorGroupId>) {
|
||||||
|
assert!(group.is_finite(), "Inserting non finite manipulator group");
|
||||||
self.manipulator_groups.insert(index, group)
|
self.manipulator_groups.insert(index, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a manipulator group to the end.
|
/// Push a manipulator group to the end.
|
||||||
pub fn push_manipulator_group(&mut self, group: ManipulatorGroup<ManipulatorGroupId>) {
|
pub fn push_manipulator_group(&mut self, group: ManipulatorGroup<ManipulatorGroupId>) {
|
||||||
|
assert!(group.is_finite(), "Pushing non finite manipulator group");
|
||||||
self.manipulator_groups.push(group)
|
self.manipulator_groups.push(group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,11 @@ impl<ManipulatorGroupId: crate::Identifier> ManipulatorGroup<ManipulatorGroupId>
|
||||||
self.in_handle = self.in_handle.map(|in_handle| affine_transform.transform_point2(in_handle));
|
self.in_handle = self.in_handle.map(|in_handle| affine_transform.transform_point2(in_handle));
|
||||||
self.out_handle = self.out_handle.map(|out_handle| affine_transform.transform_point2(out_handle));
|
self.out_handle = self.out_handle.map(|out_handle| affine_transform.transform_point2(out_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Are all handles at finite positions
|
||||||
|
pub fn is_finite(&self) -> bool {
|
||||||
|
self.anchor.is_finite() && self.in_handle.map_or(true, |handle| handle.is_finite()) && self.out_handle.map_or(true, |handle| handle.is_finite())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue