Game Development Community

Disable Click on specified gui

by Nathan Bowhay (ESAL) · 03/24/2009 (6:21 pm) · 6 comments

Add some simple static fields to pass the click (mouse) event on to the child controls or just simply disabling it. This is for TGEA, but can easily if not exactly be ported back to TGE as that is where I originally had it.

An example use for this is if you have a button with a guiTextCtrl and guiBitmapCtrl as the children and you don't want to be able to select the text or have the image be clickable (they would get in the way of the button clicking). This is just one example there are tons more, it has been very useful.

All modifications will be to GuiControl. The line numbers may be a bit off so you will have to bear with me. They should be pretty correct assuming they are the line numbers before the previous changes (as off the original TGEA) file.

To use it just make the changes, recompile and just check/uncheck the checkboxes that will now be in the gui editor under the Clickable group.

guiControl.h
On line 110 or so, after:
public:
...
bool    mIsContainer; ///< if true, then the GuiEditor can drag other controls into this one.

Insert:
//Making click event not happen
   bool mClickable; // added to allow click ignoring
   bool mAffectChildren; // this is for click ignoring, so that all the objects in the group will or will not be affect by its clickable bool

guiControl.cpp
Change line 187 from:
GuiControl::GuiControl() : mAddGroup( NULL ),
...
                           mIsContainer(false)

To:
mIsContainer(false),							                           mClickable(true),
                           mAffectChildren(true)

On line 241 or so, after:
void GuiControl::initPersistFields()
...
   endGroup("GuiControl");

add:
addGroup("Clickable");
   addField("Clickable",         TypeBool,         Offset(mClickable, GuiControl));
   addField("AffectChildren",    TypeBool,         Offset(mAffectChildren, GuiControl));
   endGroup("Clickable");
[\code]

On about line 1141, in GuiControl::findHitControl change:
[code]
      else if (ctrl->mVisible && ctrl->pointInControl(pt))
to
else if (((ctrl->mVisible && ctrl->pointInControl(pt)) && !ctrl->mAffectChildren) || (ctrl->mVisible && ctrl->pointInControl(pt)) && ctrl->mClickable)

shortly after around line 1146 change:
if(hitCtrl->getControlProfile()->mModal)
to
if(hitCtrl != NULL && hitCtrl->getControlProfile()->mModal)

shortly after that around 1150 change:
return this;
to
if(this->mAffectChildren)
	   return this;
   else	if(this->mClickable)
	   return this;
   else
	   return NULL;

And that should be it, sorry for the line numbers being off, but I already had the code edited and I had some other changes as well.

#1
03/25/2009 (7:27 am)
How is this different from this resource?

www.garagegames.com/community/blogs/view/15424
#2
03/25/2009 (10:22 am)
Guess it isn't much different, sorry about that I didn't even see that. I just did this for a work project quite a while ago and finally got around to posting it, when we started porting to TGEA. Didn't look real close at it, but the one difference may be that if you want none of the children to be clicked you can do that in this, but they are pretty much the same.
#3
03/25/2009 (10:28 am)
.. which in turn i've never quite understood, versus the stock feature of giving the control a non-modal profile.
#4
03/25/2009 (10:47 am)
i guess the TDN entry for guiControlProfile is a little misleading on the meaning of the field "modal". it says:
Quote: Modal - bool - Whether the control should make the UI modal (prevent the user from doing anything outside of the control).

in my experience that explanation has zero to do with what this flag actually does. What the modal field in a GuiControlProfile really does is make it so that the control receives mouse events. If true, the control receives mouse events like normal, if false it doesn't. Voila: a control you cannot click on.
#5
03/25/2009 (11:36 am)
@Orion: Personally, I dislike having a bunch of different profiles. But, it doesn't look like setting modal effects the children - just the control it's set on (see code below).

By ignoring the mouse above the modal check, you don't have to muck around with the children.

GuiControl* GuiControl::findHitControl(const Point2I &pt, S32 initialLayer)
{
   iterator i = end(); // find in z order (last to first)
   while (i != begin())
   {
      i--;
      GuiControl *ctrl = static_cast<GuiControl *>(*i);
      if (initialLayer >= 0 && ctrl->mLayer > initialLayer)
      {
         continue;
      }
      else if (ctrl->mVisible && ctrl->pointInControl(pt))
      {
         Point2I ptemp = pt - ctrl->getPosition();
         GuiControl *hitCtrl = ctrl->findHitControl(ptemp);

         if(hitCtrl->getControlProfile()->mModal)
            return hitCtrl;
      }
   }
   return this;
}
#6
03/25/2009 (11:46 am)
good points.
yeah, i'm not a huge fan of the Profile system either,
it gets messy quickly.