-
Notifications
You must be signed in to change notification settings - Fork 138
many-to-many connections support #91
base: main
Are you sure you want to change the base?
Conversation
I felt like #30 and #81 offer an overly complicated solution to the problem of many-to-many connections, so I'm messing around with a different approach. I'd appreciate comments regarding the general design of the feature. Do note that this is purely an experiment to see if this approach can even lead to a workable solution that offers good UX and simple, flexible API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really nice! 🎉 Thanks a lot for this PR :)
Indeed, I've been hesitant to merge previous attempts to this in the past because of how much they deviated from the original design. This looks like a very clean incremental update over what we had, and indeed, users should not have a hard time upgrading. I'd be very much OK with merging something like this.
I feel the ordering of parameters is worth discussing. In this version, you are using a HashSet to store the multiple inputs in a wide port, and this leads to a random ordering of the connections. This leads to the question: Do we care about the ordering of parameters? In your example, an addition operation would not care, since in those cases, as it is commutative. But what happens with operations that are not commutative?
I'm not sure how hard it would be to extend the current design into something that allows users to reorder the connections in a wide port. Essentially, replace that HashSet with a Vec and all the necessary UI interaction bits that make this work. Calculating the insertion point into the list of inputs based on the mouse position when the mouse is released into a connection into a pin doesn't sound that complicated. 🤔 Oh, and now I just realized you're already doing a ver similar logic to handle pin disconnections, so this calculation is already in place!
In case we decide ordered connections in a port are broadening the scope too much for now, input connections should at least be sorted in a deterministic way before iterating them.
Having sat on the issue for a while, these are my thoughts:
|
Implemented ordered inputs, here's the current status: nodes_ordering.webm. Sorry for the invisible cursor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good so far 👍 The new port ordering looks pretty nice!
Once we get the input size and y offset for the wide ports figured out, this will be ready for merging. I left a comment above with a potential solution.
Amazing! 🎉 Thanks a lot for the hard work @kamirr. I'd say with the nice round of recent changes, this being merged would be a good time for a release. But I'm not sure if you're planning on tackling any other tasks, there's really no rush so we can wait. |
I'd like to work on documentation before the next release, I'll get to that right after we get this PR merged. Ps. I was a bit too eager to declare feature-completeness, |
This change enables many-to-manny graphs by extending input ports with a capability to optionally accept multiple connections, via a max_connections parameter. If this parameter is set to anything other than Some(NonZeroU32(1)) the port will be referred to as `wide`. * Adjust Graph::connections to map from InputId to Vec<OutputId> instead of just OutputId. * Adjust UI to render wide ports as segments extending in length proportionally to the number of connections. * Allow creating a new connection by dragging from an extra slot in a wide port. * If a wide port is not full, an in-progress connection will move existing ones out of the way to allow intuitive ordering. Otherwise, the new connection will override the one it's hovering over within the port. * Extend NodeResponse::ConnectEventEnded with an additional field containing the index under which the new connection resides within the input port. * Add Graph::add_wide_input_param for creating wide ports.
Should be ready for review:
The history of my changes is lost due to the rebase with squashes I did, but it can be browsed on the kek/many-to-many2 branch on my fork. |
Thanks for all the amazing work :) I'll review this soon, but I already made a quick look and things are looking good. |
My 2 cents: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html is insertion-sorted :) |
This patch is an attempt at adding many-to-many connection support without overhauling the library and minimal breaking changes to the user.
The core of the idea is to replace
Graph::connections
fromSecondaryMap<InputId, OutputId>
toSecondaryMap<InputId, HashSet<OutputId>>
and roll from that.Ports are parametrized by an argument specifying the maximum non-zero number of connections (not yet enforced), and if that number is greater than 1 a so called wide-port is drawn -- it's characterized by being longer than a typical port and connections made to it are spread out and can be disconnected individually.
Known limitations:
HashSet<_>
isn't an adequate data structure for storing the connected outputs -- we have no control over ordering, let alone the end user.