Handle signal in multiple widgets

Hello everone,
I have a grid filled with buttons and I want to draw a path when the user is entering a drag gesture. The drag gesture will go over multiple buttons. When the user releases the mouse key, I want to activate the button the mouse is currently on and erase the path.

To achieve this I used an overlay to put a drawing area above the grid of buttons. The drag signals are caught by the drawing area to visualize the path. To activate the underlying buttons I measure the width and height of the drawing area. With the x and y coordinates from the drag_update signals I can calculate over which row and column of the grid the mouse is (The cells are homogeneous). With this information I can ask the grid for the child in the calculated cell, downcast it to a button and activate it. This seems rather excessive, error prone and verbose.

Is there a more elegant way to do this? I feel like this would be a common requirement when using an GtkOverlay so I am sure there is a better solution. Possibly by duplicating the signal? I saw the pass_through property of GtkOverlay but I think that’s not what I am looking for. If I understand it correctly instead of true or false I would need both.

Thank you for your help :sunny:

1 Like

I like your mathematical way of doing it. Let me add another method. But please remember, this could be inefficient. xD

  1. Let all buttons have a property called state that is 0 when the mouse is not over them and 1 when when the mouse is over them.
  2. When the drag starts, ask all the buttons to listen to mouse’s movement.
  3. When the mouse hovers over the button, the state of the button will be changed.
  4. After the drag finishes, freeze the state of all buttons. That’s the buttons need not listen to mouse events now.
  5. Now loop over all the buttons and find the button which has state 1.
  6. Activate it.
  7. Reset the state of buttons to zero.

Setting this way could be a headache, but it leaves the pain of calculation via position. And again, this could be an inefficient way. :slight_smile:

1 Like

Hmm, this sounds equally complicated :smile:

I think there is a simpler solution by propagating events and letting the widget figure out itself which button to press. I was thinking to propagate the button_press, button_release and motion_notify events. I will try to explain my goal a bit better:

I have the following tree of widgets:

     |   |--Box
     |       |--Button
     |       |--Button
     |       |--Button
             |   |--Button
             |   |--Button

I want to allow a user to click a button, recognize a long pressed button and I want to notice a swiping motion. A short click is supposed to activate the button when it is released. A long click is supposed to open a popup of the button (that is a problem for another day :wink: ). The swipe is supposed to draw a path on the drawing area and no button is activated.

I can think of two ways my problem could get solved.

First: DrawingArea always on top, propagating Events down to the grid unless swipe gesture is detected
The drawingArea is always on top of the grid and passes all events to the grid. The grid then passes it to the buttons. If a swipe gesture is detected, the propagation stops and starts again after the gesture ended.
I have not been able to get this to work though. I added BUTTON_PRESS_MASK and POINTER_MOTION_MASK on the overlay and tried detecting the gestures on the overlay widget. I also connected to the button_press_event and motion_notify_event. Whenever they are detected I used propagate_event() to propagate the event to the grid. The event does not seem to reach the buttons. I assume this is because if I understand correctly key events bubble up the widget tree so the grid does not propagate the event further down the tree. I don’t know how to change this behavior though.

Second: No propagation of events, show drawingArea only if swipegesture was detected
The other solution I thought of is to hide the drawingArea. That way all events go directly to the grid of buttons and don’t need to be propagated. Only when a swipe gesture is detected, the drawingArea is displayed. Then all further events land on the drawing area. Once the gesture ends, the drawing area is hidden again and events can reach the button grid.
This would be my preferred solution but I also can’t get this one to work. The problem I seem to have is that whenever I click a button the event no longer is propagated up the tree to the overlay where the gesture detection can take place. If I click on an empty place in the grid it all works as expected.

Also I want to activate the buttons when the mouse is released and not when it is pressed. Not sure how to change this behavior either.

I read the documentation multiple times but I feel like I have not fully understand the propagation of events :S
Thank you for taking the time to read my question :otter:

1 Like

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