Jump to content

recursion help


Rick
 Share

Recommended Posts

Need a little help trying to figure this out. Basically it's GUI programming. This has to do with finding what control the mouse pointer is over. Controls can have children controls which will always be in the bounds of their parents. So if the mouse is over a control, we then have to go inside that controls list of children controls to see if the mouse is over any of those, etc, etc infinitely deep. Hence why I use recursion.

 

In my example I have a form control which has 4 controls on it. Exit button, logon button, username textbox, & password textbox. In the code that I have what ends up happening is the form control gets returned to the calling function. I need the Exit button (since that's where the mouse is over in this example) to be returned. Inside this recursion the Exit button does get returned, but the chain continues and since the form is over the mouse it ultimately gets returned to the calling method. I need some way to retain the last control before a null children list is found so I can return that one up the chain to the calling method.

 

Here is the code in C++, but the idea could be in any language.

Control* GUIManager::FindControlOverMouse(map<string, Control*> controls)
{
map<string, Control*>::iterator iter;

for(iter = controls.begin(); iter != controls.end(); iter++)
{
	if((*iter).second->InBounds(MouseX(), MouseY()))
	{
		map<string, Control*> children;

		children = (*iter).second->GetControls();

		// Go back into this method with this controls list of controls
		Control* ctl = FindControlOverMouse(children);

		return (*iter).second;
	}
}

return 0;
}

Link to comment
Share on other sites

Hi Rick,

 

i wrote a GUI for LE by myself in the past. It does a lot but i stopped the development in the middle of the gui editor because then i realized that i reinvent the wheel again...

But here is my code for getChildAtPoint()

 

I have a widget which is the base for all. And every widget has those 2 functions (and a lot more)

 

1. isPointInside()

2. getChildatPoint()

 

the 2. is the recursive one and calls for every widget 1. this returns true or false if the point is inside

every widget can contain a lot of subwidgets (buttons, editboxes etc) therefore i dig through all childs of the widget.

 

here is the code

// ------------------------------------------------------------------------------------------------
// Name: isPointInside( int iPosX, int iPosY );
// Info: is the point inside this widgetspace?
//
// Return			= (bool)				true / false
//
// iPosX			= (int)					Position Add X
// iPosY			= (int)					Position Add Y
// ------------------------------------------------------------------------------------------------
bool CLEG_WIDGET::isPointInside( uint16 _uiX, uint16 _uiY )
{ return getRect().IntersectPoint( getBorderIntersection(), _uiX, _uiY ); }
// ------------------------------------------------------------------------------------------------


// ------------------------------------------------------------------------------------------------
// Name: getChildAtPoint( uint16 _uiX, uint16 _uiY )
// Info: Get the Childwidget at position _uiX _uiY
//
// Return			= (LPCLEG_WIDGET)		Topmost childwidget at this position
//
// _uiX				= (uint16)				Position X
// _uiY				= (uint16)				Position Y
// ------------------------------------------------------------------------------------------------
LPCLEG_WIDGET CLEG_WIDGET::getChildAtPoint( uint16 _uiX, uint16 _uiY )
{
//Variablen init
mWIItor	itor;																// Iterator
LPCLEG_WIDGET		pChild = NULL;

// Render all sheets
for( itor = m_mapWidgets.begin(); itor != m_mapWidgets.end(); ++itor )
{
	// Pointer
	pChild = (*itor).second;

	// Pointer valid?
	if( pChild == NULL ) continue;

	// Resize ok?
	if( pChild->isPointInside( _uiX, _uiY ) == true ) return pChild;
}

// bye
return NULL;
}
// ------------------------------------------------------------------------------------------------

 

hope this helps

 

cu Oliver

Windows Vista 64 / Win7 64 | 12GB DDR3 1600 | I7 965 | 2 * 280GTX sli | 2 * 300GB Raptor | 2 * 1.5TB

Link to comment
Share on other sites

you dont need a recursion here. (ok i wrote it... but its late here in germany and i have to go to bed :))

 

my way was.

 

you have a sheet which can contain widgets. Those are stored in the a simple STL map. When the user click into the screen (sheet) it asks the widgets if there is a widget which has an intersection in its rect.

If there is an intersection this widgets asks all the childs if any of the childs has an intersection, if so then return it.

 

This worked really well. it was easy and precise.

 

// ------------------------------------------------------------------------------------------------
// Name: getWidget( uint16 _uiX, uint16 _uiY, bool _bfindAll )
// Info: Get the widget at position _uiX _uiY
//
// Return			= (LPCLEG_WIDGET)		Topmost widget at this position
//
// _uiX				= (uint16)				Position X
// _uiY				= (uint16)				Position Y
// _bfindAll		= (bool)				Find all widget, override the find flag (default false)
// ------------------------------------------------------------------------------------------------
LPCLEG_WIDGET CLEG_SHEET::getWidget( uint16 _uiX, uint16 _uiY, bool _bfindAll )
{
// First check if the point is different
if( !_bfindAll && ( m_sPointLastChecked.iX == _uiX ) && ( m_sPointLastChecked.iY == _uiY ) ) return m_pWidgetUnderPoint;

// Set the point
m_sPointLastChecked.iX = (int16)_uiX;
m_sPointLastChecked.iY = (int16)_uiY;

// Variablen init
LPCLEG_WIDGET								pWidget			= NULL;		// Widget
LPCLEG_WIDGET								pReturnWidget	= NULL;		// Widget
list< LPCLEG_WIDGET >::reverse_iterator		itor;						// Iterator

// Is the list empty?
if( m_liWidgets_Active.size() <= 1 ) return pWidget;

// No.. we can search for a widget
itor = m_liWidgets_Active.rbegin();
while( itor != m_liWidgets_Active.rend() )
{
	// Get Widget
	pWidget = *itor;

	// Check if we can find this widget
	if( _bfindAll == false )
		// Check if the widget is not visible or we set the flag that we do not want to find it by this action. Maybe the contextmenue!
		if(( pWidget->getFLAG_Visible() == false ) || ( pWidget->getFLAG_FindByPointInside() == false  ) )
		{
			// Next Element
			++itor;

			// and go on
			continue;
		}

	// Check position
	if( pWidget->isPointInside( _uiX, _uiY ) )
	{
		// This Point is inside, so check if the point is inside of a childwidget
		pReturnWidget = pWidget->getChildAtPoint( _uiX, _uiY );

		// Do we have a child at this point?
		if( pReturnWidget != NULL ) return pReturnWidget;

		// return
		return pWidget;
	}

	// Next Element
	++itor;
}

// bye
return NULL;
}
// ------------------------------------------------------------------------------------------------

 

cu

Oliver

Windows Vista 64 / Win7 64 | 12GB DDR3 1600 | I7 965 | 2 * 280GTX sli | 2 * 300GB Raptor | 2 * 1.5TB

Link to comment
Share on other sites

But what about child's children and their children? That's my issue. Take a panel type control. Its parent is a sheet or form if you will, but it has children in it also. Now imagine embedding panel controls inside panel controls and then a button in that. There is this long chain of parent and children that goes past the first 2. That's the issue that I'm having. With the parent/child design you don't know how far the chain goes. That's why I need recursion.

Link to comment
Share on other sites

Hi Rick,

 

here is the rough layout.

 

You have a widget as a base class this can be a button, a frame element, an editfield or what ever you want.

Every widget can have as many childs it wants to have. think about grouping or windows with subwindows and so on.

 

The widget has a map which stores all the childs of this widget.

When you attach to widget Alpha a window Beta and this cotains a button Charly and you want to check if the mouse is over charly

you first check if the mouse X and Y is inbound the rect of the window Alpha. If this is true then the windowwidget Alpha goes through

the list of its childs and finds 1 window namend Beta and if the mouse is inbout Beta the widget looks up the childs list if

the mouse is in the rectangle of on of his childs like Charly... and so on...

This algo stops when the mouse has the final widget under its pointer from the topmost widget you see... that is what you want.

 

It is stable, fast and precise.

 

Cu

Oliver

Windows Vista 64 / Win7 64 | 12GB DDR3 1600 | I7 965 | 2 * 280GTX sli | 2 * 300GB Raptor | 2 * 1.5TB

Link to comment
Share on other sites

I got my recursion code working. I guess I don't see what you are describing in the code that you posted. I can only assume there is a missing piece that you didn't post. Maybe I'm wrong but it doesn't look like getWidget() transverses a hierarchy of parent/child relationship.

 

I see the below code, but that just seems to say if the current widget is inside, check the child widget to this and return it. If getWidget() isn't called recursively then it seems you would only be getting the first child layer and not any nested children.

// Check position
               if( pWidget->isPointInside( _uiX, _uiY ) )
               {
                       // This Point is inside, so check if the point is inside of a childwidget
                       pReturnWidget = pWidget->getChildAtPoint( _uiX, _uiY );

                       // Do we have a child at this point?
                       if( pReturnWidget != NULL ) return pReturnWidget;

                       // return
                       return pWidget;
               }

 

I guess it depends on what is in m_liWidgets_Active list? Is this every widget?

 

Maybe you do it differently than I do. What I do is create a container widget. I then add widget to that container widget as children. I then only add the container widget to the main gui manager list of widget. The only widgets are not added directly to this main gui manager list because they are indirectly there as children of the container widget.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...