(Sim::findObject("> Question about "Skinnable GUI Controls" Tutorial | Torque Game Engine | Forums | Community | GarageGames.com

Game Development Community

Question about "Skinnable GUI Controls" Tutorial

by DavidRM · in Torque Game Engine · 07/03/2002 (4:13 pm) · 4 replies

I've been experimenting with the "Skinnable GUI Controls" tutorial posted by Justin "avon Lady" DuJardin and I wanted to ask about a section of the code.

Here's an example:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
  if (def != NULL)
   if(dStrcmp(def->mBitmapName,mProfile->mBitmapName))
   {
        mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
     mProfile->constructBitmapArray();
     mBitmapBounds = mProfile->mBitmapArrayRects.address();
   }

As best I can figure, and I've verified this by stepping through the debugger, the pointers "def" and "mProfile" are identical. "mProfile" is a cached pointer to the control's profile object, and "def" gets the same pointer, but by calling Sim::findObject(). So the string comparison is essentially comparing a string to itself.

Am I reading this correctly? Or is there something I'm missing? For instance, is there a case when Sim::findObject would return a *different* pointer than the one already in mProfile?

In all other respects, the tutorial is great. I just ran into this issue when I was adding Tim Newell's themed skin tutorial on top of it and couldn't get the bitmaps to change at runtime.

Thanks in advance!

-David
Samu Games

#1
07/03/2002 (4:27 pm)
The reason in my tutorial I introduced the mOldSkinBitmap is I ran into the same problem and could not get it to change...both values came out to be equal everytime. This is either a problem or both of us made the same mistake. Avon and another person said they had it working with his version....Im not sure which of us is making the mistake.

-Tim aka Spock
#2
07/03/2002 (6:34 pm)
David, the mProfile->mBitmap is cached and stays unchanged once the torque engine loads the first instance of that certain control. However when i do say...
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
... it retrieves the most current profile according to script, i then compare the most current to the cached version. This works just fine for myself, though tim and yourself seem to be having problems with this. If you are having problems i'd suggest using tim's method, as I do not have any problems and it saves a tiny bit of memory not doing it tim's way, I'll stick to the original way in my tutorial.

Thanks for checking it out, hope you enjoy!
#3
07/04/2002 (8:02 am)
Thanks for the responses, Tim, Justin.

Justin, there must be some other engine change in play for it to work as you describe. Because in every instance I've investigated, the cached "mProfile" pointer was exactly the same as the "def" pointer.

I'm not denying it works for you, of course, thate would be silly. What I *am* wondering, though, is what other changes must have been made for there to be 2 profile objects with the same name attached to the same GUI control.

A minor mystery, but hardly a showstopper.


Tim, I took a similar approach to yours, but instead of putting the new bitmap name check in the actual GUI controls, I put it in the profile object.

In the GUI controls, this code:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
   if(dStrcmp(def->mBitmapName,mProfile->mBitmapName))
   {
   mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
   mProfile->constructBitmapArray();
   mBitmapBounds = mProfile->mBitmapArrayRects.address();
   }

Was replaced by:
mProfile->constructBitmapArray();

The constructBitmapArray() method already included checking to make sure that the bitmap array hadn't alreaady been constructed. So I just extended that a bit:

if(mBitmapArrayRects.size())
      return mBitmapArrayRects.size();

Became:
if((mBitmapArrayRects.size()) && (!needReConstructBitmapArray()))
      return mBitmapArrayRects.size();

   if ((mBitmapArrayRects.size()) || (needReConstructBitmapArray()))
   {
      mBitmapArrayRects.clear();
      mTextureHandle = TextureHandle(mBitmapName, BitmapKeepTexture);
      if (!(bool)mTextureHandle)
         Con::errorf("Failed to load profile bitmap (%s)",mBitmapName);
      mOldBitmapName = mBitmapName;
   }

With needReConstructBitmapArray() as:
bool GuiControlProfile::needReConstructBitmapArray()
{
   return ((mOldBitmapName==NULL) && (mBitmapName!=NULL)) ||
          (mBitmapName!=mOldBitmapName) && (dStrcmp(mBitmapName,mOldBitmapName)!=0);
}

And, just to be complete, this line had to be added to GuiControlProfile::GuiControlProfile(void):
mBitmapName = NULL;
   mOldBitmapName = NULL;

   GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject("GuiDefaultProfile"));
   if (def)
   {
      ...
      mOldBitmapName = mBitmapName;
   }

Finally, GuiInspectorTextEditProfile in common/ui/defaultProfiles.cs needs these lines added:
bitmap = "./torqueTextEdit";
   hasBitmapArray = true;

Without those lines, the text edits in the object inspector of the GUI editor look odd.

Thanks again!

-David
Samu Games

Edits: A few changes to fix problems encountered after the original post.
#4
07/05/2002 (3:07 pm)
Just to mention it...I got bugged by the window control buttons (minimize, maximize, close) being placed "too low" in the title bar of the window. Vertically centered is my own preference. And, thus, the following changes...

First off, it was necessary to change how the control determined the height of the title bar.

In guiWindowCtrl.cc:
bool GuiWindowCtrl::onWake()
{
   ...
    mTitleHeight = buttonHeight + 4;
   ...
}

Became:
bool GuiWindowCtrl::onWake()
{
   ...
   GuiCanvas *root = getRoot();
   GuiControl *firstResponder = root ? root->getFirstResponder() : NULL;
   bool isKey = (!firstResponder || ControlIsChild(firstResponder));
   U32 topBase = isKey ? BorderTopLeftKey : BorderTopLeftNoKey;
   
   mTitleHeight = mBitmapBounds[topBase].extent.y;
   ...
}


Secondly then, I had to change the calculation of the button positions. Calculating it based off the text offset position with the title bar just seems odd to me. So I overrode the mainOff.y value with a calculation based on the (now known) title height.

And so:
void GuiWindowCtrl::PositionButtons(void)
{
   ...
   Point2I mainOff = mProfile->mTextOffset;
   ...
}

Became:
void GuiWindowCtrl::PositionButtons(void)
{
   ...
   Point2I mainOff = mProfile->mTextOffset;
   
   mainOff.y = (mTitleHeight - buttonHeight) / 2;
   ...
}

And *poof* perfectly, vertically centered window control buttons.

-David