Game Development Community

Changing the z-order of GUI controls at runtime

by Drew Parker · in Torque Game Engine · 03/31/2004 (4:54 am) · 6 replies

Hi all,

How do I change the z-order of GUI controls at runtime with code? The problem I'm having is I have a certain GUI element that takes mouseclicks in the playGui GUI. But, our team is also using another GUI element as a HUD indicator which is created in script like this:

%cView = new GuiCollisionViewer()
{
objectID = %id;
extent = $pref::Video::resolution; //fill the full screen
};

What this does is push an instance of the GuiCollisionViewer guicontrol to the top of our playgui, so then the mouse clicks don't work, and I don't know how to get them captured again. Is there a way I can push the mouse-click GUI control to the front of the z-order with script, or is it possible when dynamically creating a new GUI control to insert it in the middle of the z-order instead of inserting it to the front?

#1
03/31/2004 (5:01 am)
I think you can do %cView.pushToBack(). Bear in mind i've never tried this, and I just woke up, and haven't had my hot cocoa yet. But it can't hurt to try :p
#2
03/31/2004 (5:30 am)
Hahaha :)

Thanks John, I'll try it in a little bit and post my results. Please add a nice dose of RediWhip on your cocoa for me. If you like RediWhip, that is. :)
#3
03/31/2004 (7:07 am)
Ok, I got it to work.

I used Agent Ransack (awesome utility) to do a multi-file search for pushToBack(), and I found it in guiEditCtrl, but not GuiControl. Since the "parent" of my GUI that would be pushing %cView to the back was not of type guiEditCtrl, I figured I'd have to implement it in guiControl. I did notice that in guiEditCtrl they called bringObjectToFront() (in class SimSet) to get their GUI re-ordering to work. Looking at the class tree, I saw that guiEditCtrl is eventually derived from SimSet. GuiControl is also derived from there, so I thought I should be able to use that function in guiControl.

I'll list real quick my code changes. Stuff I added is in bold.

In guiControl.h, I added a function call called pushToBack()

/// Removes a child object from this control.
    /// @param   obj Object to remove from this control
    void removeObject(SimObject *obj);

[b]
	 // Move control to back of z-order --- drew
	 void pushToBack(SimObject *obj);
   [/b] 
    GuiControl *getParent();  ///< Returns the control which owns this one.
    GuiCanvas *getRoot();     ///< Returns the root canvas of this control.

Then in guiControl.cc,

void GuiControl::removeObject(SimObject *object)
{
   AssertFatal(mAwake == static_cast<GuiControl*>(object)->isAwake(), "GuiControl::removeObject: child control wake state is bad");
   if (mAwake)
      static_cast<GuiControl*>(object)->sleep();
    Parent::removeObject(object);
}

[b]
// Push GUI element to back of z-order  - drew
void GuiControl::pushToBack(SimObject *obj)
{
	Con::printf ("c++ GuiControl::pushToBack()");

	// back of GUI z-order is front of set perhaps?
	bringObjectToFront (obj);
}
[/b]
GuiControl *GuiControl::getParent()
{
    SimObject *obj = getGroup();


// .....  jump to bottom of file, where all the ConsoleMethod calls are ......

[b]
// push GUI control to front/back  --- drew
ConsoleMethod( GuiControl, pushToBack, void, 3, 3, "set.pushToBack (obj)")
{
	GuiControl *ctrl;
   if(!Sim::findObject(argv[2], ctrl))
      return;

   object->pushToBack(ctrl);
}
[/b]
ConsoleMethod( GuiControl, setValue, void, 3, 3, "(string value)")
{
   object->setScriptValue(argv[2]);
}

// ......

Then, in script, when dynamically creating a GUI element, you call it like this:

%cView = new GuiCollisionViewer()
{
	objectID = %id;
	extent = $pref::Video::resolution;	//fill the full screen
};	

Canvas.getContent().add(%cView);
	
[b]Canvas.getContent().pushToBack(%cView);[/b]

And that's it. :)
#4
11/08/2005 (4:43 pm)
I don't know if this is in the latest head or not, but i definately think it should be.


[edit]
well i say that, but it doesn't seem to actually work :( wonder what i did wrong.

[edit 2]
Ok i figured it out. I'll elaborate in case anyone else is curiuos.


when doing a push to back, you must do like this

GUI.pushtoback(OBJ);

GUI needs to be the group/parent of the OBJ you wish to push back. So whatever you added the new OBJ to, is what you must call the pushtoback method.
#5
08/14/2006 (7:12 am)
How about if you just create a GuiControl in the main Gui at the place you want the dynamically created Gui's to be inserted, and instead of adding them to the base Gui add them to this placeholder Gui

eg.

+MainGui
---blah
---blah2
---blah3
---blah4
---GuiControlForDynamics
---blah5
---blah6
---blah7
---blah8


Then when you add the dynamic gui's , just do "GuiControlForDynamics.add(obj);".
#6
08/14/2006 (2:33 pm)
Well you can do that i'm sure. it'd depend on exactly what you had in mind.
That may work just fine for some static GUIs...

but what if you have moving GUIs.... it might not.

In what i do, i do alot of dynamically generated/changing menus. So this particular code addition does the job spelendly.