Jump to content

  • Log In with Google      Sign In   
  • Create Account

Custom GUI input events propagation


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
8 replies to this topic

#1 invutil   Crossbones+   -  Reputation: 1926

Like
0Likes
Like

Posted 06 June 2014 - 06:58 PM

My GUI is made up of views/layers. Like, I might have a view for the main menu and one for the credits.

 

Each view has widgets.

 

Now, I've found it necessary to have a "pre" call for any mouse input event and a normal call. For example, I might call prelbuttondown (left mouse button down) on all the views, which propagates to all their widgets.

 

The reason is that if I have a dropdown list selector that covers up a widget (let's say a button) that comes after it, the input event will first get intercepted by the button covered up by the dropdown menu. The widgets input methods are called in reverse order, since the last one will be drawn last and be on top of the other ones.

 

This also applies to drawing. I have a draw() method and a draw2() method that is called after all the draw() methods because even though the dropdown list is drawn before the button, it might have a dropdown menu opened that will cover up other widgets.

 

I was told I should have a variable that keeps track of the active widget. That way I can check the active widget for input event interception first. And I suppose I could call an overdraw() method on the active widget for any drawing that has to be done on top of the other widgets. 

 

But this brings more headache; I only propagate events to views that are open and there's no way to get the view that a widget belongs to, and a widgets can have whole hierarchies of subwidgets. Also, if I have only one active widget with an overdraw() method being called, how do I do label text that appears when the mouse hovers over a button?

 

Is there an easy solution? What is the correct way to do this?



Sponsor:

#2 Servant of the Lord   Crossbones+   -  Reputation: 21195

Like
3Likes
Like

Posted 06 June 2014 - 07:47 PM

Yes, an 'active widget' is important for catching things like keyboard input. (For example, it's common to click on a LineEdit widget and then move the mouse off of it so it's not obscuring the text you are writing). Sometimes focus is split with two separate variables: Keyboard focus and mouse focus.

 

Two thoughts: (coming from a Qt user oriented towards desktop applications)

 

1) Why can't your "view" be a widget? In Qt, they have a widget they call a 'stacked widget', which is (behind the scenes) multiple widgets that are the same physical dimensions that occupy the same location, with only one visible at once. Building off of that, they then use the same widget along with a 'tab bar widget' (a collection of styled buttons) alongside it, to offer 'tabbed widgets'.

 

If you don't want tabs, and want to initiate your own switching of views, you use a stacked widget (with it's parent-child hierarchy of widgets). If you want tabs, you use a tabbed widget.

 

Qt uses lower-level widgets (like buttons, and stacked widgets) to build higher level widgets (like tabbars and tabbed widgets). These are usually has-a, not is-a, relationships, usually by parent-child ownership.

 

Even things like spin boxes, could conceptually be built from other widgets (though they might not be, for optimization purposes):

widget_composition.png

It's likely that those spin-widget buttons aren't separate widgets, but conceptually they are. And they use the same code paths - a behind the scenes DrawButtonAppearance(rect, appearanceFlags)-like function used by the actual user-usable Button, Checkbox, Scrollbar, Tab and Spinbox classes.

 

Same with the TextLabel and DropDownList and ItemList and even the Button's text: a shared behind the scenes shared DrawTextAppearance(rect, appearanceFlags).

 

2) In Qt, dropdown lists are several widgets: the button you click, and then the drop-down part is it's own widget, that has a higher z-order.

 

dropdown.png

 

Qt uses a special widget-flag for these: Qt::Popup. Qt::Popup flags for widgets make the widget above other widgets, and is used for things like file menus and tooltips.

 

One of the benefits of this is that the same widgets can be repurposed for other uses. Today I tossed this together for my editor:

 

custom_dropdown.png

 

Not perfect, but for twenty minutes work it serves its purpose.

 

Qt's widgets are not designed for games, so I'm not recommending you use Qt, but I figure tossing out some ways other APIs handle these problems might give you more options to tackle your own challenges.


Edited by Servant of the Lord, 06 June 2014 - 07:54 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#3 invutil   Crossbones+   -  Reputation: 1926

Like
0Likes
Like

Posted 06 June 2014 - 08:09 PM

Turning the Views into Widgets would simplify things.

 

About the z-order and popping up a new widget: I could push a new list box selector widget at the highest level, eliminating the input and drawing order problem. But if I set its parent Widget to be the dropdown list selector that created it, that would mess up the hierarchy, because the parent Widget doesn't have it as a child. Maybe add a callback Widget pointer to the child? I need some way for the parent widget to know when an item has been selected. 

 

I don't use the z-buffer in my 2D orthographic drawing.



#4 invutil   Crossbones+   -  Reputation: 1926

Like
0Likes
Like

Posted 06 June 2014 - 08:35 PM

What if on an input event the child widget calls the callback (parent) widget and the parent widget deletes the the child widget while its child's function is still on the stack?

 

And the STL list would be modified while it was still being traversed.



#5 Servant of the Lord   Crossbones+   -  Reputation: 21195

Like
0Likes
Like

Posted 06 June 2014 - 08:40 PM

Signals and slots (which are fancy callback functions), or regular callback functions.

 

If the parent widget is creating the popup widget, it should already have a pointer to it in whatever function/logic/script created the popup widget anyway.

 

And nothing is stopping the parent widget from owning it as a child - it's just that (in Qt's implementation) the child has the special widget flag: 'Popup' (this is not a special type of widget, this is a flag available to any widget that changes the behavior).

 

Logic-wise, your program could do something like:

//Process the popups' hierarchies:
for-all-popup-flagged-widgets:
     popupWidget->processEvents() //Including non-popup children widgets.

//Then process the regular hierarchy:
rootWidget->processEvents() //Including non-popup children widgets.

About deleting: Set a 'delete' flag, or push a 'DeleteMe' event. Delete it at the beginning of the next frame, or when the event is processed.

My own non-Qt game logic code uses a 'delete' flag that is processed at the beginning of the next frame. Qt has the base abstract widget type have a 'deleteLater()' function, which probably does something similar.


Edited by Servant of the Lord, 06 June 2014 - 08:40 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#6 invutil   Crossbones+   -  Reputation: 1926

Like
0Likes
Like

Posted 06 June 2014 - 08:50 PM

Another problem:

If I have a bunch of buttons for a list of selected units in an RTS, with a highlight effect when the mouse hovers over them, how do I ensure that only one of them is highlighted. If the mousemove event is intercepted when the mouse goes over a button, it might still be over another button if they are stacked.

The way I do it now is with 'pre' and 'post' event propagation as I said - the premousemove method cannot intercept the mouse event and only sets the button's state to not mouse over, and the (post) mousemove method intercepts the mouse event if mouse is over..

Keeping track of which widget the mouse is over in one variable seems like the solution.


Logic-wise, your program could do something like:

//Process the popups' hierarchies:for-all-popup-flagged-widgets:     popupWidget->processEvents() //Including non-popup children widgets.//Then process the regular hierarchy:rootWidget->processEvents() //Including non-popup children widgets.

So basically have a pre and post event like I have?

Edited by polyfrag, 06 June 2014 - 09:06 PM.


#7 invutil   Crossbones+   -  Reputation: 1926

Like
0Likes
Like

Posted 06 June 2014 - 09:37 PM

Doesn't seem like there's a much better way to do it than what I have. I was going to finish an article about it. Maybe I'll do that soon.

Would be interesting to know how Windows or any other OS does it.

#8 Servant of the Lord   Crossbones+   -  Reputation: 21195

Like
0Likes
Like

Posted 06 June 2014 - 09:37 PM

I do use pre- and post- events for logic and drawing and input, but that's not what I was suggesting above (I use it more for customizing behavior of individual widgets).

 

I'm not sure how Qt handles that specific case, but what I was suggesting is treating popups as their own "root" of their children. Even though they might have parents and might be owned just like other widgets, you can use that popup flag to treat them differently. It can be used so all pop-up widgets are treated (only when drawing, or processing events) as entirely separate hierarchies of widgets.

 

[Edit:] An illustration of what I mean:

 

popup_A.png 

 

popup_B.png

 

Just a thought - that's how I'd begin to explore a solution.


Edited by Servant of the Lord, 06 June 2014 - 09:49 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#9 Endurion   Crossbones+   -  Reputation: 3694

Like
0Likes
Like

Posted 07 June 2014 - 07:08 AM

Popups are nasty things :)

 

Popups come in different flavours, one would be tool tips, others the opened listbox of a combo box.

 

In my GUI system childs are usually truncated to their parent. Popups are basically added as childs of the root component (the root widget in SotLs diagram). Popups are then tied to their source component in a owner/owned relationship.

 

To allow only one child being influenced by a mouse event this is handled by the parent control. The parent control cycles through its childs and chooses the first hit control (and then stops searching). This is done recursively and thus ends up either with nothing or the chosen control.

Esp. for hottips the control itself can define if it is actually clickable (you don't want to focus a tool tip), so it can work as click through.


Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS