Game Development Community

GuiSingleBitmapButtonCtrl

by Orion Elenzil · 06/22/2009 (7:17 pm) · 7 comments

this resource implements a new GuiControl, GuiSingleBitmapButtonCtrl.
this is very similar to a GuiBitmapButtonCtrl, but only takes a single bitmap instead of four.
the four states of the button (normal, highlighted, depressed, inactive) are visually indicated by four different bitmap modulation colors, and / or by four different background fill colors.

motivation:
it's a pain to make four bitmaps for a single button, especially when prototyping,
and often a simple change in color is sufficient to indicate the button's four states.

example 1, source bitmap:
elenzil.com/gg/images/gg1.png
resulting four states:
elenzil.com/gg/images/gg1_nhdi.png

code:
canvas.getContent().add(new GuiSingleBitmapCtrl() {
   extent = "180 120";
   bitmap = "dev/gg1";
});


example 2, source bitmap (the "G" is cut-out):
elenzil.com/gg/images/gg2.png
resulting states ("inactive" state not shown)
elenzil.com/gg/images/gg2_nhd.png
code:
canvas.getContent().add(new GuiSingleBitmapCtrl() {
   extent            = "180 120";
   bitmap            = "dev/gg2";
   modulationcolor_n = "255 255 255 255";
   modulationcolor_h = "255 255 255 255";
   modulationcolor_d = "255 255 255 255";
   backgroundcolor_n = "169 164 169 255";
   backgroundcolor_h = "170 170 170 255";
   backgroundcolor_d = "250 220 80 255";
});



This is based on a TGE 1.3.4 codebase,
but should be relevant to any torque engine using the same GuiControl system and OpenGL.

Some familiarity w/ C++ & Torque is assumed.
I have to admit i just wrote this in the last hour or so, and it's only been minimally tested.

Also note that the "lazyLoad" stuff is optional, if you don't feel like including it.
see this resource for more discussion.



create new file GuiSingleBitmapCtrl.h
//-----------------------------------------------------------------------------
// orion elenzil
// doppelganger
// 20090622
//-----------------------------------------------------------------------------

#ifndef _GUI_SINGLE_BITMAP_BUTTON_CTRL_H_
#define _GUI_SINGLE_BITMAP_BUTTON_CTRL_H_

#include "gui/guiButtonCtrl.h"
#include "dgl/gTexManager.h"

class GuiSingleBitmapButtonCtrl : public GuiButtonCtrl
{
private:
   typedef GuiButtonCtrl Parent;

protected:
   StringTableEntry mBitmapName;
   TextureHandle    mTexture;
   bool             mLazyLoad;
   bool             mNeedLazyLoad;

   void renderButton(TextureHandle &texture, Point2I &offset, const RectI& updateRect);

public:
   ColorI  mModulationColor_Master;       // master modulation
   
   ColorI  mModulationColor_N;            // modulation in the neutral state
   ColorI  mModulationColor_D;            // modulation while the button is down (poor button)
   ColorI  mModulationColor_H;            // modulation while the button is hovered-over
   ColorI  mModulationColor_I;            // modulation while the button is inactive

   ColorI  mBackgroundColor_N;            // Background in the neutral state
   ColorI  mBackgroundColor_D;            // Background while the button is down (poor button)
   ColorI  mBackgroundColor_H;            // Background while the button is hovered-over
   ColorI  mBackgroundColor_I;            // Background while the button is inactive

public:   
   DECLARE_CONOBJECT(GuiSingleBitmapButtonCtrl);
   GuiSingleBitmapButtonCtrl();

   static void initPersistFields();

   //Parent methods
   bool onWake          ();
   void onSleep         ();
   void inspectPostApply();

   StringTableEntry getBitmap();
   void             setBitmap(const char *name);

   void onRender             (Point2I offset, const RectI &updateRect);

   void lazyLoad             ();
};


#endif //_GUI_SINGLE_BITMAP_BUTTON_CTRL_H_


create new file GuiSingleBitmapCtrl.cc
//-----------------------------------------------------------------------------
// orion elenzil
// doppelganger
// 20090622
//-----------------------------------------------------------------------------


#include "console/console.h"
#include "dgl/dgl.h"
#include "console/consoleTypes.h"
#include "platform/platformAudio.h"
#include "gui/guiCanvas.h"
#include "gui/guiSingleBitmapButtonCtrl.h"
#include "gui/guiDefaultControlRender.h"


//-------------------------------------
GuiSingleBitmapButtonCtrl::GuiSingleBitmapButtonCtrl()
{
   mBitmapName                = StringTable->insert("");
   mBounds.extent             = Point2I(140, 30);

   mModulationColor_Master    = ColorI(255, 255, 255, 255);

   mModulationColor_N         = ColorI(200, 200, 200, 255);
   mModulationColor_D         = ColorI(180, 180, 180, 255);
   mModulationColor_H         = ColorI(255, 225, 255, 255);
   mModulationColor_I         = ColorI(200, 200, 200, 170);

   mBackgroundColor_N         = ColorI(200, 200, 200,   0);
   mBackgroundColor_D         = ColorI(180, 180, 180,   0);
   mBackgroundColor_H         = ColorI(255, 225, 255,   0);
   mBackgroundColor_I         = ColorI(200, 200, 200,   0);

   mLazyLoad                  = true ;
   mNeedLazyLoad              = false;
}


//-------------------------------------
void GuiSingleBitmapButtonCtrl::initPersistFields()
{
   Parent::initPersistFields();
   addField("bitmap"                , TypeFilename, Offset(mBitmapName            , GuiSingleBitmapButtonCtrl));
   addField("modulationColor_Master", TypeColorI  , Offset(mModulationColor_Master, GuiSingleBitmapButtonCtrl));
   addField("modulationColor_N"     , TypeColorI  , Offset(mModulationColor_N     , GuiSingleBitmapButtonCtrl));
   addField("modulationColor_D"     , TypeColorI  , Offset(mModulationColor_D     , GuiSingleBitmapButtonCtrl));
   addField("modulationColor_H"     , TypeColorI  , Offset(mModulationColor_H     , GuiSingleBitmapButtonCtrl));
   addField("modulationColor_I"     , TypeColorI  , Offset(mModulationColor_I     , GuiSingleBitmapButtonCtrl));
   addField("backgroundColor_N"     , TypeColorI  , Offset(mBackgroundColor_N     , GuiSingleBitmapButtonCtrl));
   addField("backgroundColor_D"     , TypeColorI  , Offset(mBackgroundColor_D     , GuiSingleBitmapButtonCtrl));
   addField("backgroundColor_H"     , TypeColorI  , Offset(mBackgroundColor_H     , GuiSingleBitmapButtonCtrl));
   addField("backgroundColor_I"     , TypeColorI  , Offset(mBackgroundColor_I     , GuiSingleBitmapButtonCtrl));
   addField("lazyLoad"              , TypeBool    , Offset(mLazyLoad              , GuiSingleBitmapButtonCtrl));
}


//-------------------------------------
bool GuiSingleBitmapButtonCtrl::onWake()
{
   if (! Parent::onWake())
      return false;
   setActive(mActive);
   setBitmap(mBitmapName);
   return true;
}


//-------------------------------------
void GuiSingleBitmapButtonCtrl::onSleep()
{
   mTexture = NULL;
   Parent::onSleep();
}


//-------------------------------------

ConsoleMethod( GuiSingleBitmapButtonCtrl, setBitmap, void, 3, 3, "(filepath name)")
{
   object->setBitmap(argv[2]);
}

//-------------------------------------
void GuiSingleBitmapButtonCtrl::inspectPostApply()
{
   // if the extent is set to (0,0) in the gui editor and appy hit, this control will
   // set it's extent to be exactly the size of the normal bitmap (if present)
   Parent::inspectPostApply();

   if ((mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTexture)
   {
      TextureObject *texture = (TextureObject *) mTexture;
      mBounds.extent.x = texture->bitmapWidth;
      mBounds.extent.y = texture->bitmapHeight;
   }
}

//-------------------------------------
StringTableEntry GuiSingleBitmapButtonCtrl::getBitmap()
{
   return mBitmapName;
}

void GuiSingleBitmapButtonCtrl::setBitmap(const char *name)
{
   mBitmapName   = StringTable->insert(name);
   mNeedLazyLoad = true;

   if (!mLazyLoad)
   {
      lazyLoad();
   }
}

void GuiSingleBitmapButtonCtrl::lazyLoad()
{
   if (!mNeedLazyLoad)
   {
      return;
   }

   mNeedLazyLoad = false;

   if(!isAwake())
      return;

// Con::errorf("%s() - loading %s", __FUNCTION__, mBitmapName ? mBitmapName : "(null)");

   if (*mBitmapName)
   {
      mTexture = TextureHandle(mBitmapName, BitmapTexture, true);
   }
   else
   {
      mBitmapName = NULL;
   }
   setUpdate();
}   


//-------------------------------------
void GuiSingleBitmapButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
{
   lazyLoad();

   enum
   { 
      NORMAL, 
      HILIGHT, 
      DEPRESSED,
      INACTIVE
   } state = NORMAL;

   if (mActive)
   {
      if(mDepressed)
      {
         state = DEPRESSED;
      }
      else if (mMouseOver)
      {
         state = HILIGHT;
      }
      else if (mStateOn)
      {
         state = DEPRESSED;
      }
   }
   else
   {
      state = INACTIVE;
   }

   ColorI modulationColor;
   ColorI backgroundColor;

   switch (state)
   {
      case NORMAL:
         modulationColor = mModulationColor_N;
         backgroundColor = mBackgroundColor_N;
         break;

      case HILIGHT:
         modulationColor = mModulationColor_H;
         backgroundColor = mBackgroundColor_H;
         break;

      case DEPRESSED:
         modulationColor = mModulationColor_D;
         backgroundColor = mBackgroundColor_D;
         break;

      case INACTIVE:
         modulationColor = mModulationColor_I;
         backgroundColor = mBackgroundColor_I;
         break;
   }

   modulationColor *= mModulationColor_Master;        // see ColorI convolution resource - http://www.garagegames.com/community/resources/view/17177
   backgroundColor *= mModulationColor_Master;        // see ColorI convolution resource - http://www.garagegames.com/community/resources/view/17177


   RectI rect(offset, mBounds.extent);

   if (backgroundColor.alpha > 0)
   {
      dglDrawRectFill(rect, backgroundColor);
   }


   if (mTexture && modulationColor.alpha > 0)
   {
      dglSetBitmapModulation(modulationColor);
      dglDrawBitmapStretch  (mTexture, rect);
   }

   renderChildControls( offset, updateRect);
}


be sure to add them to your project file!

GuiCanvas.cc add a #include:
#include "gui/guiSingleBitmapButtonCtrl.h"

and add an IMPLEMENT_CONOBJECT: (anyone know why these are all in Canvas.cc instead of in their respective GuiControlFoo.cc files?)
IMPLEMENT_CONOBJECT(GuiSingleBitmapButtonCtrl);


and shazam!

#1
06/22/2009 (7:38 pm)
Great stuff thanks for sharing.
#2
06/22/2009 (8:41 pm)
Thanks Orion!
#3
06/23/2009 (1:12 am)
Nice resource.

I wrote this resource some time ago explaining a little how TGE uses the color modulation. It uses default TGE functions.

http://www.garagegames.com/community/resources/view/11774

Maybe it help somebody to make an improved control.

Luck!
#4
06/23/2009 (3:37 am)
very coool, thanks a lot, ill try it!.
#5
06/23/2009 (8:26 am)
Cool! This will be handy for sure. Thanks !
#6
07/08/2009 (4:49 pm)
Sadly, I can't get this to work in TGEA 1.8.1. :(
#7
07/08/2009 (10:01 pm)
XD - hmm, bummer. i'm unfamiliar w/ TGEA. for the most part this resource is a subset of GuiBitmapButtonCtrl, so i would suggest looking at GuiBitmapButtonCtrl in TGEA and seeing how the textures are handled.