Closed briancairl closed 3 years ago
Apologies about the videos not showing the mouse cursor. I was having some issues with my usual screen capture program.
Thanks for the great write-up @briancairl ! 👍
Reframing the minimap as just another view of the editor context and using the interaction with the minimap to drive the main editor view seems like a good way to think about this feature.
Regarding your questions
IsItemHovered
pattern to render a tooltip when hovered. But that can't be used with the currently proposed interface. What do you have in mind for custom tooltips, besides the node name?Some additional thoughts There are pros and cons to having this feature as an integrated library feature.
Some of the things you mentioned are definitely pros. Imnodes could easily do the heavy lifting, since it already has everything it needs to render a minimap. Imnodes could also use the actual node geometry, i.e. the rectangle shape, to render the node proxies, something which can't be done (or would be really inconvenient to do) from user code.
Having a MiniMap
function as a part of the Imnodes header is also a drawback -- Imnodes can only render a minimap after EndNodeEditor
has been called. Only at that point do we actually have all the information we need: the nodes, link positions, as well as which node is actually hovered or selected. So this would somewhat restrict where the user can place a minimap, as they can't render it in the same window before the node editor canvas (without repositioning the internal cursor, etc.). If the minimap was created by the user, based on the user-data, they could render it anywhere they want. But they pros might outweigh the cons in this case.
What do you think about showing multiple links between nodes? I think currently they are rendered as a single bezier curve, but I suppose we could actually show them as distinct curves. What that help orienting the user in the minimap, or would it introduce too much clutter, I wonder? 🤔
Finally, a heads-up. Don't get too attached to the current internals of the library. I'm going to try to spend the next few days doing some much-needed clean-up and refactoring, and the changes are probably all going to cause massive conflicts with any other work 😅 The first pr is up: https://github.com/Nelarius/imnodes/pull/95 There's a few internal complexities that I would like to try resolve entirely, having to do with the object pool, and the pervasive use of indices to refer to the internal objects.
@Nelarius To address one of these points, since its been on my mind:
Having a MiniMap function as a part of the Imnodes header is also a drawback -- Imnodes can only render a minimap after EndNodeEditor has been called. Only at that point do we actually have all the information we need: the nodes, link positions, as well as which node is actually hovered or selected
This came to mind when I sat down to look over this the other day, though I didn't think about it so carefully when I made my prototype implementation :sweat_smile: . I think this is true if the user is given the ability to place the mini-map in any window/context. Even so, it can be done if the last draw info for nodes/links/etc. is available when the mini-map is drawn. I'm not a huge fan of depending on old draw info from the last frame, but its a way that this could be done.
Conversely, drawing the mini-map as an editor overlay (like a heads-up display) could avoid the dependence on old draw data altogether. BeginNodeEditor
could have an extra flag to enable the mini-map overlay, and EndNodeEditor
could draw the mini-map, if enabled.
imnodes::BeginNodeEditor(ImNodesNodeEditor_EnableMiniMap);
// draw nodes and links
imnodes::EndNodeEditor(); // <-- mini-map overlay computations/interaction handling/drawing done here
This, of course, make Begin/EndNodeEditor
more complex, which you might not want. It also introduces a new problem around the sizing and positioning of the mini map. I'm not sure that mini-map sizing is something that needs to be exposed to the user, or can be auto-magically sized given the size of the editor context. As for positioning, I think this is a simpler matter. the ImNodesNodeEditor_EnableMiniMap
could be more specific to allow the used to place the mini-map in different corners of the editor:
enum {
ImNodesNodeEditor_EnableMiniMapTopLeft,
ImNodesNodeEditor_EnableMiniMapBottomLeft,
// etc.
}
There are also other pay-for-use draw backs like the amount of editor real estate the mini-map takes up as an overlay. There's a bunch of fiddling to do around relative sizing and opacity when focused/not to make the mini-map as innocuous as possible when not being used for navigation.
As for the other points, I'll give these some more thought when I put my head to it after you've completed your internal cleanups -- I was just about to start work on this again, so thanks for letting me know before the merge conflicts! :smile:
Let me know what you think about the mini-map as a HUD.
Rendering the minimap as an overlay seems a neat way of solving the EndNodeEditor dependency problem. Seems like a better user experience than relying on the previous frame's data 🤔 Although, like you mentioned, it probably will require a bit of fiddling to make the user experience nice.
A quick note about complexity. If we can keep the interface simple and orthogonal to the rest of the interface in imnodes.h
than I don't think the actual implementation size matters (unintended complexity is a different matter! 😄 ). The proposed interface, a single Minimap
function, does a lot of work for the user 🙂 It doesn't interact in any way with the rest of the functions in the header (except for, perhaps, some additional customizability), so in this way I think it is quite an ideal interface.
Which brings me to the refactoring. I've merged all the bigger structural changes I'll do for the time being. It's mostly formatting changes which went in. imnodes.cpp
contains unintended complexity, and I've started rewriting some of the internals from scratch: https://github.com/Nelarius/imnodes/commits/internal-refactor It's going to take quite a while, though -- thus, no need to wait for me on this if you have the drive to tinker with this now. Merge conflicts are something which can be figured out, should it come to it 🙂
@Nelarius Here's a first pass https://github.com/Nelarius/imnodes/pull/99
Among other things, the default colors probably need some tuning :sweat_smile:
Closing, since feature was added with https://github.com/Nelarius/imnodes/pull/99.
Some background
Something that seems useful for large graphs is a way of quickly navigating to nodes in some sort of "zoomed out" context. I searched through some old repo issues to find that this has been brought up in the past, but isn't practically achievable with ImGui in its current state.
One alternative to zooming in the editor panel that I wanted to try was a navigable mini-map of the node editor context panel.
Prototype design
I've made a prototype version of this based on some basic design details:
https://user-images.githubusercontent.com/1093236/112758246-26998000-8fa2-11eb-9945-27a1a73b48c7.mp4
https://user-images.githubusercontent.com/1093236/112758257-3618c900-8fa2-11eb-8e0b-cdfd7576d7da.mp4
https://user-images.githubusercontent.com/1093236/112758959-bb51ad00-8fa5-11eb-931e-7ae67045145e.mp4
Implementation
I've added some code for the current prototype here using the existing
imnodes
implementation andImGui
functions. Some details are left a bit vague, namely, the containers storing node/link IDs and how I'm mapping from link-to-node IDs. Previously, I was using a function I added to theimnodes
library in my local fork to get nodes IDs from links IDs without having to do any external structures to hold on to the link-to-node mapping, specifically.However, I propose that this functionality could be made into an complimentary library feature, since all the necessary information for rendering it is available in the
imnodes
internals.I imagine it as a widget which:
can be drawn as separate contents which is drawn in another window/group, like I've shown in the prototype
can be drawn as an entity that is overlaying the node editor context
Questions
DrawMiniMap
feature useful/reasonable as I've describe it?DrawMiniMap