Skip to main content
gamedev.net
🔒 Locked

GUI - Floating Windows

Started by phb5000 3 replies 550+ views
Original Post
phb5000
phb5000
Anyone have any good suggestions or advice concerning floating windows in a GUI system. Currently, my GUI system consists of controls based on my "GuiControlBase" class which gives all the general information about a control (ex: size, location, parent control, child controls) Now, Im having a bit of a problem with mouse updates. I need a good way of making sure i dont update controls that are overlapped by other controls. Like I said above, my system is a hierarchy. Controls have children and a parent, and a ZOrder as well (0 = topmost). I would like some general info on how to implement this :)
Mushu
Mushu
Well, if you've got a list of controls sorted by z-positions - when you're distributing a mousemove/click event down through the hierarchy you can decide whether or not the event gets "eaten" by that control, thus stopping the propagation.

In my GUI implementation, a mouse event can only be received by one control, basically the topmost control in which the mouse event lies. My list of controls was sorted by z-position, so the first control that was encountered (that the event took place within) was passed the event, and the event was then discarded.

For post-lengthening purposes, this is a source snippet from my GUI crapo -

bool IContainer::processMouseEvent( MouseEvent e ) {	IComponent::processMouseEvent( e );	// the value to return. We'll mark flags during the function.	bool ret = EV_OK;	// translate the event to local space	e.x -= this->getX();	e.y -= this->getY();	// take focus away from everything. har har.	for ( ChildListType::iterator i = _children.begin();		i != _children.end(); ++i ) {			( *i )->setFocus( false );	}	// find the first control within this container to	// pass the event to (the reverse_iterator) is due	// to how the list is ordered - the back represents	// the "front", visably (painter's algorithm), so	// we use it to start with the topmost controls.	for ( ChildListType::reverse_iterator i = _children.rbegin();		i != _children.rend(); i++ ) {		if ( ( *i )->containsPoint( e.x, e.y ) ) {			( *i )->setFocus( true );			if ( ( *i )->processMouseEvent( e ) ) {				ret |= EV_EAT;				break;			}			// check to see if we need to reorder it			// INVALIDATES ITERATOR.			if ( ( *i )->isZOrdered() )				moveToFront( *i );			// only one thing can recieve mouse input			// and also, the vector iterator isn't valid anymore.			break;		}	}	return ret;}


EDIT: And I realize I misread your post. I think what you'll need to implement is a system to flag certain windows as "dirty" - meaning they need to be updated. Checking to find out whether a certain window is obscured is pretty difficult, because it requires that the system be aware of every window in the application. If you've got several layers of windows this can be really tricky.
phb5000
phb5000
Thanks for the advice,

Since my GUI system is going to be manipulating many controls (and many layers) a complete propagation of all the control, testing mouse position against control position will eventually result in very low performance.

Thus, like you mentioned, I have to step by step simplify this process. I think a good way of doing this might be to work from the top of the control hierarchy (the root control) down until we have a match between mouse and control positions.

If I have several child controls in the root, I can simpily first check if the mouse is even in any of the top level controls, before going into the whole hierarchy. If I find a match at a high level the propagation can continue step by step through the whole control hierarchy, discarding all non-involved controls to speed up the process. Eventually I will find the "active" control.

To make sure controls aren't being overlapped the process should check overlapping at every step of the hierarchy.

Using this method the system wont have to check every control against every control, which would eventually be catastrophic :P

(Btw, my system supports mouse events even though a window isnt selected; which makes the whole process a bit harder)

Any thoughts or suggestions?
Mushu
Mushu
Yeah, I agree completely that using the hierarchy would dramatically decrease overhead. In my simplified GUI system there are 2 base class types, a component class and a container class (which is derived from the component class). Further interfaces (ie, windows) are derived from these base classes.

The GUI as a whole is a heirarchy of containers which each are endowed with a list of children. When the top-level container receives an event, it propagates down the tree if its takes place within the bounds of the control (for mouse events, at least), basically as you described.

Overlap is basically handled because the container's lists are already sorted by z-value, since I was using SDL and had to sort the controls to render them properly. In this representation, the first elements checked are already the top-level controls.

The benefit to this is that you can "short circuit" (I don't know the proper term) the unchecked branches of that level of the tree once you find a component/container in which the event falls.

I think we're basically on the same page, but the key element here is the need to either sort the list of components in each container by z-value, or search for the highest z-value in each container.

Blah, sorry about all the rambling - I've got a paper to write that I don't want to write >:(
phb5000
phb5000
Thanks for the advice again :P

I think I'll start writing some code now :) and see what I can come up with.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.