Nelarius / imnodes

A small, dependency-free node editor for dear imgui
MIT License
1.97k stars 241 forks source link

Add grid snapping, ctrl-select, primary grid coloration #100

Closed Web-eWorks closed 2 years ago

Web-eWorks commented 3 years ago

Updated version of #72 since I apparently cannot push to that PR anymore. Oh well, I needed the motivation to get this going! :smile: Closes #98.

This PR implements snap-to-grid behavior while dragging nodes. Grid snapping uses a simple nearest-point algorithm that works for negative coordinates. Since the last pull request, I made it fancier, so it now snaps the node you started dragging while you're dragging. It's off by default, and totally configurable based on the grid square width and the style flags.

Primary line drawing is very simple, just colors the origin lines a lighter (or darker) shade. Could likely be extended to draw every n lines instead, but that's outside of the scope of this PR. It's off by default but controllable with style flags and colors for those who like the UE4 grid drawing and aligning their nodes with the graph origin.

Ctrl-select is another simple feature; when holding down the Ctrl key (configurable to use a different modifier), left clicking on an unselected node will add it to the current selection instead of clearing the selection. Left-clicking a selected node will remove it from the current selection.

Nodes now get created at (0,0) instead of (100,100) to guarantee they start aligned to the grid - the viewport pan is modified to produce almost-identical behavior to that of before this change. I've also reduced the grid size to default at 24 instead of 32; the snap increment was simply too large at 32 pixels.

Web-eWorks commented 3 years ago

As a note for the future, I think it's probably worth promoting the grid-space -> screen-space conversion utilities to class or namespace scope in imnodes_internal.h so they're available in the entire implementation file. There are a few lines in there where I copied the related math because the conversion utilities were defined significantly later in the file and I didn't want to do such a major refactoring.

Nelarius commented 2 years ago

I'll take it!

Reviewing the code I can't help but wonder if we could implement this feature without the need for the explicit call to SnapNodeToGrid. I think the feature should work just by enabling the grid snapping flag. But it might require quite a bit of tweaking of the internal code structure.

Web-eWorks commented 2 years ago

I'll take it!

Reviewing the code I can't help but wonder if we could implement this feature without the need for the explicit call to SnapNodeToGrid. I think the feature should work just by enabling the grid snapping flag. But it might require quite a bit of tweaking of the internal code structure.

Thanks! Glad to finally get this landed!

SnapNodeToGrid is separate API for two reasons: user code can position nodes arbitrarily, which means that they either have to reimplement snap code or have some way to manually re-snap nodes if they want; and UE4 (the reference application for grid snapping behavior :smile:) has a "straighten connections" action which moves nodes slightly off-grid to maintain visual clarity in node connections, so I wanted automatic grid snapping when creating and positioning nodes through API to be entirely opt-in for maximum control on the application's part.