Game Development Community

dev|Pro Game Development Curriculum

IgnoreMouse property on GuiControl for easier embedding

by Jaimi McEntire · 09/22/2008 (11:44 am) · 4 comments

Have you ever wanted to embed a control inside of a button? I wanted to do just that in TGEA 1.7 - embed a GuiMLTextCtrl inside of a GuiButtonCtrl for my save game system. The problem was that the GuiMLTextCtrl would eat the mouse events so you had to click around it. You could of course click on the embedded control and have it call the same function as the button, but visually this doesn't work because it doesn't look like the button has been pressed.

To fix this, I added a property to GuiControl (and thus to all descendant controls) that allows any control to Ignore the mouse. This will effectively make it so the you can no longer click on that control (or any of the children of that control) - all mouse events are handled by the parent - perfect for my GuiMLTextCtrl buttons!

Note that this effectively locks the control in the GUI editor also, so if you set this property to true, you have to select the control manually in the tree. I like this behavior, so I didn't code in the ability to detect if you were in the editor or not.

On to the changes.

GUICONTROL.H:

in the class GuiControl, right after mIsContainer, add a boolean for our property:

bool    mIsContainer; ///< if true, then the GuiEditor can drag other controls into this one.
    /// IGNORE MOUSE CHANGES
    bool    mIgnoreMouse; // of true, then does not get selected.
    /// IGNORE MOUSE CHANGES

GUICONTROL.CPP:

In the constructor, GuiControl::GuiControl(), initialize mIgnoreMouse to false:

/// IGNORE MOUSE CHANGES
   mIgnoreMouse         = false;
    /// IGNORE MOUSE CHANGES
   mConsoleVariable     = StringTable->insert("");

in the function initPersistFields(), add the property after the canSave property:

addField("canSave",           TypeBool,         Offset(mCanSave, GuiControl));
    /// IGNORE MOUSE CHANGES
   addField("IgnoreMouse",       TypeBool,         Offset(mIgnoreMouse, GuiControl));
    /// IGNORE MOUSE CHANGES

Replace the function GuiControl::findHitControl with this function:

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))
      {
         /// IGNORE MOUSE CHANGES
         if (!ctrl->mIgnoreMouse)
         {
           Point2I ptemp = pt - ctrl->getPosition();
           GuiControl *hitCtrl = ctrl->findHitControl(ptemp);

           if(hitCtrl->getControlProfile()->mModal)
              return hitCtrl;
         }
      }
   }
   return this;
}

Now you're done. By default, everything will behave like it did before. However, if you want to embed an object inside of another (and have the mouse ignore it), just set the IsContainer to true, embed the control, and on the embedded control, set "IgnoreMouse" to 1. Put a bitmap, a label, an MLTextControl, whatever you want inside.

Example:

new GuiButtonCtrl(LoadSlotButton10) {
            canSaveDynamicFields = "0";
            Enabled = "1";
            isContainer = "1";
            HorizSizing = "right";
            VertSizing = "bottom";
            position = "0 477";
            Extent = "243 47";
            MinExtent = "8 2";
            canSave = "1";
            IgnoreMouse = "0";
            Visible = "1";
            hovertime = "1000";
            groupNum = "-1";
            buttonType = "PushButton";
            useMouseEvents = "0";

            new GuiMLTextCtrl(LoadSlotText10) {
               canSaveDynamicFields = "0";
               Enabled = "1";
               isContainer = "0";
               HorizSizing = "right";
               VertSizing = "bottom";
               position = "11 3";
               Extent = "226 14";
               MinExtent = "8 2";
               canSave = "1";
               IgnoreMouse = "1";
               Visible = "1";
               hovertime = "1000";
               lineSpacing = "2";
               allowColorChars = "0";
               maxChars = "-1";
               text = "Test ML";
            };
         };

#1
09/23/2008 (9:33 am)
Great stuff!
#2
09/25/2008 (4:54 pm)
i typically use a "NonModal" GuiProfile to do the same thing,
but it is a bit of a hassle to create a whole new profile just for that.

here's a basic nonmodal profile:
new GuiControlProfile(NonModalProfile : GuiDefaultProfile)
{
   modal = false;
};
#3
10/07/2008 (6:22 am)
I actually ended up using this a lot in code for buttons - to turn mouse interactions on and off for various things.
#4
02/07/2009 (3:47 pm)
hum... I'm was looking for something like this... I've got many problems in a old game! I'll test it later with TGB :D