[GTK4 C Linux & Windows] hover on / drag graphical elements, is this possible?

I’ve restarted my cross-platform GTK4 C application from scratch. It’s an application that unfolds a volume from its 3d file and draws it flattened as a net of 2d triangles, that’s the easy part that I already made.

Next I want to add interactivity. For the previous version I did that using only a drawingArea that I redraw as needed, adding visible elements to show the user what the current selection is and so on. What do I need to do if I want the user to be able to hover a piece and have it change its border or color to reflect this hover event ? And what do I need to do for the user to be able to drag a piece a move it around the drawingArea ? (make a custom widget ? another drawingArea with only the pieces that shows on top of the big one ?) Or do I need to keep using only one big drawingArea and it’s events ? Depending on the 3d model, the big DrawingArea can contain more than 100 pages (the example shown has 15 pages). Is there somewhere an example of GTK4 C application implementing drawingArea hover and/or drag ? I think I read here that it’s just a matter of event to be able to hover on a drawArea, but I didn’t find anything about dragging, if needed it would be enough for me to be able to drag the bounding box frame of the piece, does this mean that I need to put a box over the drawingArea ?

GTK doesn’t care what you draw on the GtkDrawingArea, that’s the application business. As such, it cannot do picking for you — the application has to do some math and determine which piece is under the cursor.

Basically, you’ll have to listen for motion events on the drawing area. That can be done by adding a GtkEventControllerMotion to the drawing area, or alternatively a GtkEventControllerLegacy, which will catch all kind of events.

Subscribe to the GtkEventControllerMotion::motion signal, that will give you the x and y coordinates of the mouse cursor. Then you have to determine whether the cursor is above the piece or not

Thank you, for the previous version of my application I handled piece picking, movement and rotation using events on the drawingArea, one on left click, another on right click and lots of keyboards pressed events. As I saw the gtkDemo drag example I was hoping that it was possible to implement it using a drawingArea or a custom widget, but I can simply reuse my code and improve it using an event to capture mouse moves even without a button press.

Apparently, it could be helpful for me to use gtk.snapshot for each piece I draw as I can use translate on them to move the whole piece instead of redrawing everything. Browsing the gtk demos, I found that “Simple paintable” is using snapshot, so I’m going to learn from it.

1 Like

For the moment I was able to implement hover on graphical elements and it works fine. Sadly even if my app works, the way I use Cairo makes it hangs from time to time, certainly because of memory management. I tried to use GtkSnapshot but didn’t understand how to use it. It reminds me that before I started using GTK4, I made a console version of my application that only uses cairo to create a pdf file and it was able to create pdfs with hundreds pages without problem, and the first GTK4 GUI version of the app that used a GtkNotebook also was able to create and edit big pdfs, but having only one page shown at a time was not handy for edition. I hope that I will be able to implement a pagination that would allow Cairo memory management to stop hanging the application. But if pagination is mentioned several times on posts about draw area and cairo, there’s no concrete example. I first planned to use one gtkDrawArea per page, that was what I did on first version on the app with a notebook, but here pages are shown altogether. I don’t get how I could handle mouse events in such context. What is frustrating is that what I implemented, hover handling works perfectly.

1 Like

Well, I figured out what was causing Cairo to hang and now my code works fine, but I still haven’t find anything about dragging graphical elements. There is the drag and drop project from Gtk Demos, but I didn’t find it helpful to learn about dragging, it looks more than a technical demo there to show what can be achieved when you know how it works, but without enough comments for those who don’t know how it works, and it uses things like ‘G_GNUC_BEGIN_IGNORE_DEPRECATIONS’ instead of dealing with deprecation. I’m afraid it is a very good example of how GTK works, more a technical demo than something usable by average coders.

Here a short animated gif of what I want to do. Be able to load a 3d model, view it in 3d (one thing that I’m still struggling to do with GTK) and edit it as a 2d pattern by dragging pieces between pages. I made it on html/javascript by reusing my C code and adapting it to js, and it was not long to do using mouse events on svg elements. How can the same (only the 2d part, for the 3d I need to add lighting but it’s not the question asked here) be done with GTK as Cairo doesn’t handle events ? I already did something that works on the previous version but it’s not dragging. Does someone know of a project where the same kind of dragging is implemented ? After this html/javascript I will certainly try do to the same using C++ with QT.

If this is all within one drawing area, then you do not even need to use drop targets and drag sources. All that is needed is a GtkGestureDrag and then you implement the picking and dropping behavior yourself. The drop targets are only if you intend to have dragging from one window to another, or if you want users to be able to drop things from other apps into your app, or the other way around.

My previous version already used GtkGestureDrag but it had pages splitted into a notebook, each having a drawing area and the edition worked by redrawing the current drawing area after each event. Now I’m doing a new version where all the pages are shown into the same window (with scrolling), some of my files have > 100 pages, so that’s why I’m looking for a way to have my pieces drawn into their own snapshot so that the memory usage don’t become too important, but I didn’t find a way to use snapshots with Cairo or even create a custom widget (it’s something I already did but not with GTK that I’m using for the first time for this unfolder project). I doubt that the performance will be acceptable if I keep refreshing all the design after each event, but maybe I’m not understanding the way GTK drawing model works (even if I read the GTK doc chapter about it). What is sad is that Cairo can generate svg elements but doesn’t handle events involving them.

You can use gsk_cairo_node_new and then draw cairo content into the node. Then add it to a new snapshot and use gtk_snapshot_to_paintable to add it to a DragIcon. You can keep a reference to the node and also append it to another snapshot when drawing to the drawing area.

Cairo can only output to SVG as text, it does not include an implementation of SVG DOM or even an SVG renderer. That would be a lot more complicated.

Cairo knows nothing about events: it’s a 2D rendering library.

We’re ok about what Cairo is, indeed I already used Cairo library outside of GTK. What this mean is maybe that there’s something missing here when it comes to svg or more generally vector graphics, and not only events, but also CSS handling, or why not an accessible document model. With html/javascript I was able to do that same thing I’m willing to do here very easily with all those things, and I suspect that with QT it won’t be harder.

The “model” for handling events is GTK. It is also not particularly hard to make a widget that wraps a cairo path and then calls cairo_in_fill to do hit testing, if that is what you want. IIRC Qt does a similar thing. Cairo is closer to using QPainter or HTML <canvas>, if you use those directly you will also have to handle hit testing within whatever content you draw.

Here, I mean targeting graphical elements created by Cairo, there is simply no model for handling events on them. I already have all the logic needed to handle hit testing and I’m happy to know that making a widget doing what I want is not particularly hard, so I will try to do that. What is hard about GTK is not its mechanisms that are the same as others libraries, but that there are not lots of examples project (or even real world projects) to learn from, that the documentation is not very detailed and that the developers seems to forget that there are first time users like me that don’t know all the backstage history of the library and its whole technical ecosystem.

There is a model, you handle events on the drawing area. That is the same as QPainter and HTML <canvas>, etc.

And yes GTK is lacking in documentation and tutorials, it is a volunteer project so there is only limited time to work on that.

On graphical elements there is no event handling, I mean for graphical elements like HTML <line> or <polygon> or for QT, QGraphicsSvgItem that handles events, I still need to learn more about QT but on its examples I found several projects involving graphical elements dragging. I would be happy to give some hand on GTK, my project is already partly on github, but I’m not sure it will be interesting for others.

Sorry I cannot understand how that is related, your example GTK app appears to drawing its own shapes, not SVGs. Drawing SVGs is only useful when you have loaded an external file, i.e. with QT SVG you cannot edit the lines or polygons at all.

Edit: on the web I would also not recommend using SVG DOM for anything besides simple generation or CSS transforms. If you need complex interactivity you must use HTML <canvas> and draw everything again, or at the very least you must rewrite the event handling anyway to handle transforms correctly.

Indeed I’m using vector graphics because the purpose of my application is to generate a 2d pattern that will be used with a cutter, and svg is a vector graphics format, does it make sense now ? You previously said that dragging is only useful between applications but here it is useful to move pieces around and join/disjoin pieces, and the code using dragging techniques is very simple. What you say about SVG DOM is wrong, my html.js application uses it to do exactly what I need it to do, dragging pieces, rotate them, tie and untie, add/remove flaps, I’m using this technique for years and it helps me build lots of cardboard furniture and objects that rely on correctness of the pattern. And what you said about QT SVG is just wrong also, I just read a QT example project which purpose is to dynamically edit svg elements.

Not quite. SVG is a document format for vector graphics. It is meant for writing and reading from files, not necessarily for being the in-memory representation. It works well for SVG embedded in HTML documents because the DOM is already available there, but GTK does not have a DOM so there is not really much reason to use SVG internally at all. Cairo primitives are almost identical to it anyway.

I also have built apps like that, it is only good for simple use cases. It works until you have any transforms on the elements, then you will have problems and there will be a need to implement your own event handling. For example see here: html - How do you convert screen coordinates to document space in a scaled SVG? - Stack Overflow

A GTK application will have to do a very similar thing, there is no way around it.

AFAIK you are talking about something else such as QML shapes, QT SVG is only for reading files.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.