Game Development Community

dev|Pro Game Development Curriculum

New Button: GuiBitmapButtonSimpleCtrl

by Chris Jorgensen · 04/20/2009 (10:16 pm) · 4 comments

I've been meaning to post this for a while. This is a simple button class that requires a single image. It also can have its image changed dynamically. I don't believe such an object exists by default in TGB, so I've added it. Ideally, this class would be in a new file. But for simplicity I appended existing files.

In guiBitmapButtonCtrl.h, go to the end of the file and add this:

//----------------------------------------
// NEW: a simplified button that can have its image changed
// Author: Chris Jorgensen
//----------------------------------------

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

protected:
   StringTableEntry mBitmapName;
   TextureHandle mTextureHandle;
   static bool setBitmapName( void *obj, const char *data );

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

public:
   DECLARE_CONOBJECT(GuiBitmapButtonSimpleCtrl);
   GuiBitmapButtonSimpleCtrl();

   static void initPersistFields();

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

   void setBitmap(const char *name,bool resize = false);

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


In guiBitmapButtonCtrl.cc, go to the end of the file and add this:

//----------------------------------------
// NEW: a simplified button that can have its image changed
// Author: Chris Jorgensen
//----------------------------------------

IMPLEMENT_CONOBJECT(GuiBitmapButtonSimpleCtrl);

//-------------------------------------
GuiBitmapButtonSimpleCtrl::GuiBitmapButtonSimpleCtrl()
{
   mBitmapName = StringTable->insert("");
   mBounds.extent.set(140, 30);
}


//-------------------------------------
void GuiBitmapButtonSimpleCtrl::initPersistFields()
{
   Parent::initPersistFields();
   addProtectedField( "bitmap", TypeFilename, Offset( mBitmapName, GuiBitmapButtonSimpleCtrl ), &setBitmapName, &defaultProtectedGetFn, "" );
}

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


//-------------------------------------
void GuiBitmapButtonSimpleCtrl::onSleep()
{
   mTextureHandle = NULL;
   Parent::onSleep();
}


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

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

//-------------------------------------
void GuiBitmapButtonSimpleCtrl::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) && mTextureHandle)
   {
      TextureObject *texture = (TextureObject *) mTextureHandle;
      mBounds.extent.x = texture->bitmapWidth;
      mBounds.extent.y = texture->bitmapHeight;
   }
}


//-------------------------------------
void GuiBitmapButtonSimpleCtrl::setBitmap(const char *name, bool resize)
{
      mBitmapName = StringTable->insert(name);
   if (*mBitmapName) {
      mTextureHandle = TextureHandle(mBitmapName, BitmapTexture, true);

	  if(resize)
	  {
		  // Resize the control to fit the bitmap
		 TextureObject* texture = (TextureObject *) mTextureHandle;
		 mBounds.extent.x = texture->bitmapWidth;
		 mBounds.extent.y = texture->bitmapHeight;
		 Point2I extent = getParent()->getExtent();
		 parentResized(extent,extent);
	  }
   }
   else
      mTextureHandle = NULL;
   setUpdate();
}


//-------------------------------------
void GuiBitmapButtonSimpleCtrl::onRender(Point2I offset, const RectI& updateRect)
{
   renderButton(mTextureHandle, offset, updateRect);
}

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

void GuiBitmapButtonSimpleCtrl::renderButton(TextureHandle &texture, Point2I &offset, const RectI& updateRect)
{
   if (texture)
   {
      RectI rect(offset, mBounds.extent);
      dglClearBitmapModulation();
      dglDrawBitmapStretch(texture, rect);
      renderChildControls( offset, updateRect);
   }
   else
      Parent::onRender(offset, updateRect);
}

bool GuiBitmapButtonSimpleCtrl::setBitmapName( void *obj, const char *data )
{
   // Prior to this, you couldn't do bitmap.bitmap = "foo.jpg" and have it work.
   // With protected console types you can now call the setBitmap function and
   // make it load the image.
   static_cast<GuiBitmapButtonSimpleCtrl *>( obj )->setBitmap( data );

   // Return false because the setBitmap method will assign 'mBitmapName' to the
   // argument we are specifying in the call.
   return false;
}

That's it! Now you can change your button's image any time by doind a %id.bitmap = "image.png" type call. It also cuts down on button art requirements.

#1
04/21/2009 (8:25 am)
Handy!

How does the button react to mouse-over, mouse-down, etc ?

In the past when i've wanted a button with a single dynamic bitmap i've put the bitmap on a GuiBitmapCtrl, and fitted a mostly-transparent four-state GuiBitmapButtonCtrl over it with generic images to handle mouse-over, click, etc.
#2
04/21/2009 (8:47 am)
It should still have all callbacks like onMouseDown. It actually works super handy. I finally had to cave and add it to my iTGB source. It's just too handy.
#3
04/21/2009 (8:50 am)
gotcha, i guess i mean what does the user see when they mouse-over the button ? ie, does it highlight ?
#4
04/21/2009 (8:59 am)
Correct. No highlight. No _n _h _u _d states. It's basically more like an image that doubles as a button.