Add layer node chains, import/export edge connectors, and refactor graph editing to go thru a NodeNetworkInterface (#1794)

* WIP: NodeNetworkInterface

* Organize ModifyInputsContext to use network interface

* Improve ClickTarget and Position state

* Rework ClickTarget state

* Continue fixing NodeGraphMessageHandler

* Restructure network_metadata

* Final(?) NodeNetworkInterface struct

* Final(??) NodeNetworkInterface

* Final(???) NodeNetworkInterface. Separated persistent and transient data

* Final NodeNetworkInterface data structure. Implemented all basic getters

* Continue migrating functionality to network interface

* Migrate all NodeGraphMessage's to use network interface

* Fix all helper functions in NodeGraphMessageHandler

* Move document metadata to network interface, remove various cached fields

* Move all editor only NodeNetwork implementations to NodeNetworkInterface

* Fix all DocumentNodeDefinitions

* Rework and migrate GraphOperationMessages to network interface

* Continue migration to NodeNetworkInterface

* Save point before merging master

* Fix all errors in network_interface

* 850 -> 160 errors

* Fix all errors :D

* Render default document

* Visualize click targets

* merge conflicts

* Cache transient metadata separately, store entire interface in document history

* Start migration to storing selected nodes for each network

* Remove selected nodes from document message handler

* Move outward wires and all nodes bounding box to transient metadata

* Fix connecting/disconnecting nodes

* Layer stack organization for disconnecting/connecting nodes

* Basic chain locking

* Improve chain positioning

* Add copy/pasting

* Move upstream nodes on shift+drag

* merge conflict fixes

* Improve Graph.svelte code quality

* Final improvements to Graph.svelte

* Fix layer panel

* Performance optimizations

* Bug fixes and derived PTZ

* Chain organization improvement and bug fixes

* Bug fixes, remove all warnings

* Automatic file upgrade

* Final code review

* Fix editor tests

* Fix compile errors

* Remove select tool intersection check when panning

* WIP: Import/Exports

* Fix JS issues

* Finish simplified import/export UI

* Import/Export viewport edge UI

* Remove minimum y bound on import/export ports

* Improve performance while panning graph

* cargo fmt

* Fix CI code build

* Format the demo artwork graph with chains

* Code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
Co-authored-by: dennis@kobert.dev <dennis@kobert.dev>
This commit is contained in:
adamgerhant
2024-08-04 06:47:13 -07:00
committed by GitHub
parent ea44d1440a
commit 0dbbabe73e
77 changed files with 11361 additions and 8011 deletions

View File

@@ -21,7 +21,6 @@ use vello::*;
/// Represents a clickable target for the layer
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClickTarget {
subpath: bezier_rs::Subpath<PointId>,
stroke_width: f64,
@@ -38,6 +37,23 @@ impl ClickTarget {
&self.subpath
}
pub fn bounding_box(&self) -> Option<[DVec2; 2]> {
self.bounding_box
}
pub fn bounding_box_with_transform(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
self.bounding_box.map(|[a, b]| [transform.transform_point2(a), transform.transform_point2(b)])
}
pub fn apply_transform(&mut self, affine_transform: DAffine2) {
self.subpath.apply_transform(affine_transform);
self.update_bbox();
}
fn update_bbox(&mut self) {
self.bounding_box = self.subpath.bounding_box();
}
/// Does the click target intersect the rectangle
pub fn intersect_rectangle(&self, document_quad: Quad, layer_transform: DAffine2) -> bool {
// Check if the matrix is not invertible
@@ -85,6 +101,20 @@ impl ClickTarget {
let inflated_quad = Quad::from_box(target_bounds);
self.intersect_rectangle(inflated_quad, layer_transform)
}
/// Does the click target intersect the point (not accounting for stroke size)
pub fn intersect_point_no_stroke(&self, point: DVec2) -> bool {
// Check if the point is within the bounding box
if self
.bounding_box
.is_some_and(|bbox| bbox[0].x <= point.x && point.x <= bbox[1].x && bbox[0].y <= point.y && point.y <= bbox[1].y)
{
// Check if the point is within the shape
self.subpath.closed() && self.subpath.contains_point(point)
} else {
false
}
}
}
/// Mutable state used whilst rendering to an SVG
@@ -284,7 +314,7 @@ impl GraphicElementRendered for GraphicGroup {
let mut new_click_targets = Vec::new();
element.add_click_targets(&mut new_click_targets);
for click_target in new_click_targets.iter_mut() {
click_target.subpath.apply_transform(element.transform())
click_target.apply_transform(element.transform())
}
click_targets.extend(new_click_targets);
}

View File

@@ -186,10 +186,10 @@ impl<T: Hash> MemoHash<T> {
hasher.finish()
}
pub fn inner_mut<'a>(&'a mut self) -> MemoHashGuard<'a, T> {
pub fn inner_mut(&mut self) -> MemoHashGuard<T> {
MemoHashGuard { inner: self }
}
pub fn into_inner<'a>(self) -> T {
pub fn into_inner(self) -> T {
self.value
}
pub fn hash_code(&self) -> u64 {

View File

@@ -485,7 +485,7 @@ use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::hash::Hash;
fn serialize_hashmap<K, V, S>(hashmap: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
pub fn serialize_hashmap<K, V, S>(hashmap: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
where
K: Serialize + Eq + Hash,
V: Serialize,
@@ -498,7 +498,7 @@ where
seq.end()
}
fn deserialize_hashmap<'de, K, V, D>(deserializer: D) -> Result<HashMap<K, V>, D::Error>
pub fn deserialize_hashmap<'de, K, V, D>(deserializer: D) -> Result<HashMap<K, V>, D::Error>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,