aluntzer / gtknodes

A GTK-based library to create functional flow graphs with the ability to pass arbitrary data between connected elements.
Other
92 stars 10 forks source link

Any way to implement zooming #9

Open ghost opened 3 years ago

ghost commented 3 years ago

Hi,

Sorry, for raising multiple issues. This library is fantastic and has been a pleasure to work with. But recently I have been trying to implement panning and zoom, to make setting and editing large node diagrams easier. I have crudely implemented panning (I just mapped the horizontal and vertical scrollbars to update by the change in mouse movement when the scroll button is pressed), but I have not been able to figure out how to go about implementing zoom in and out with the scroll wheel. The way I see the problem is that I would need to have control over the size of the GtkNodes box, but set_size_request doesn't seem to have any effect. I'm not to sure of how else this could be achieved and was wondering if you had any suggestions.

Thanks for your time, Jack

aluntzer commented 3 years ago

Hi Jack,

for panning, this is the way to go, as it is sufficient to add the node view to a GtkScrolledWindow and then manipulate the viewport. Unfortunately, zooming is an entirely different matter. Calls like set_size_request only concern the height/width allocation of a widget with regard to screen space, but they do not affect its rendering scale at all. In principle, scaling/zooming can be done by just scaling the cairo context/drawing area on which the actual widget graphics are drawn. There is however a catch. This only affects the graphical representation, but does not affect any event filtering actually needed to interact with the GUI. Remember that e.g. a button is simply a rectangle drawn on a background, along with some centered text. The actual responsiveness comes from the knowledge, where the input event (from a mouse cursor) is with regard to that area.

There is no mechanism in GTK3 to easily change the relationship between the on-screen coordinates and the zoomed drawing, especially with fractional (non-integer) scaling. For example, if you had scaled the cairo drawing to half the size, you would also need to change the input pointer's pixel coordinates by a factor of 0.5, so hovering the mouse pointer over a scaled widget (like said button) would still trigger its function. One approach I can think of, would be to add an event filter to the GdkWindow which holds the NodeArea using gdk_window_add_filter() and change the relative coordinates passed from the window manager to GDK and subsequently to GTK for just the NodeArea. This is a low-level operation which can easily break the functionality of GDK/GTK and I'm not even sure how this would affect widgets which are "outside" the viewport of the widget containing the NodeArea. One could also handle all event propagation and drawing for all widgets within the NodeArea in GtkNodes itself, but that would essentially re-implement a major function of GTK, so that doesn't make that much sense.

If you don't mind that interaction/input is disabled while zooming (out) for the purpose of quick navigation, or just to get an overview of the layout, then this is just a matter of scaling the area with temporarily disabled event propagation. This I can probably add to the NodeArea widget.

cheers, Armin