Game Development Community

GuiBitmapborderBoundsCtrl - An easy to use and simple to make tiled bitmap container

by Jaimi McEntire · 01/29/2009 (11:07 am) · 7 comments

A GuiBitmapBorderBoundsCtrl is a container control that draws itself from a single bitmap. It differs from a GuiBitmapBorder in that it does not need a special BitmapArray, so it is easy to create and modify. In addition, it can draw the sides and interior tiled in addition to stretching, giving it a neater appearance. The corners are not stretched or tiled, so resizing the control still results in correct appearance.

This current version is for TGEA 1.7.1 (A TGEA 1.8 version will follow if no one else gets around to porting, after I've moved up to the new version). The current margins are hardcoded at 25% of the image, all that is needed to adjust these is for me to add a special profile type that would have the margins, and pull the margins from the profile. I will do this when I have time. Here is the layout:

www.aztica.com/images/layout.png
The corners are not stretched or tiled. The tops and bottoms are stretched or tiled only in the horizontal direction, and the sides, only in the vertical direction. The center is stretched or tiled to fill. Wow, that seems complicated. The truth is that it is really simple to create these bitmaps in photoshop with layer styles. The one below took approximately 1 minute to create.

www.aztica.com/images/alumbox.png
Here is a sample of the control in use:

www.aztica.com/images/guibitmapborderboundsexample.jpg
Here are some sample bitmaps, along with the profiles to use them:

Sample bitmaps with profiles

To use this, you will need to have added the following function to GFXDrawUtil: drawBitmapTiledSR

To add the class itself, create a new file named "GuiBitmapBorderBoundsCtrl.cpp" in the engine/gui/controls folder in your project. Add the class as follows to it:

//-----------------------------------------------------------------------------
// Torque Game Engine Advanced
// Copyright (c) 2002 GarageGames.Com
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "gui/core/guiControl.h"
#include "gui/containers/guiContainer.h"
#include "gfx/gfxDevice.h"

/// Renders a skinned border.
class GuiBitmapBorderBoundsCtrl : public GuiContainer
{
   typedef GuiControl Parent;

   int  TopMargin;
   int  BottomMargin;
   int  LeftMargin;
   int  RightMargin;
   bool bTiled;
   StringTableEntry steBitmap;
   GFXTexHandle mTextureObject;
public:
   GuiBitmapBorderBoundsCtrl::GuiBitmapBorderBoundsCtrl()
   {
      mIsContainer = true;
   };
   static void initPersistFields();
   void Setup();
   bool onWake();
   void onSleep();
   void onRender(Point2I offset, const RectI &updateRect);
   DECLARE_CONOBJECT(GuiBitmapBorderBoundsCtrl);
};

IMPLEMENT_CONOBJECT(GuiBitmapBorderBoundsCtrl);


void GuiBitmapBorderBoundsCtrl::Setup()
{
   //get the texture for the close, minimize, and maximize buttons
   mTextureObject = mProfile->mTextureObject;
   if (mTextureObject)
   {
	   TopMargin = mTextureObject.getHeight() /4;
	   BottomMargin = TopMargin;
	   LeftMargin = mTextureObject.getWidth() /4;
	   RightMargin = LeftMargin;
   }
}

bool GuiBitmapBorderBoundsCtrl::onWake()
{
   if (! Parent::onWake())
      return false;

   Setup();
   return true;
}

void GuiBitmapBorderBoundsCtrl::onSleep()
{
   mTextureObject = NULL;
   Parent::onSleep();
}

void GuiBitmapBorderBoundsCtrl::initPersistFields()
{
   Parent::initPersistFields();
   addGroup("GuiBitmapBorderBoundsCtrl");		
   addField("Tiled",   TypeBool,     Offset(bTiled,       GuiBitmapBorderBoundsCtrl));
   endGroup("GuiBitmapBorderBoundsCtrl");		
}

void GuiBitmapBorderBoundsCtrl::onRender(Point2I offset, const RectI &updateRect)
{
   Setup();
   GFX->setClipRect(updateRect);
	if (!mTextureObject)
	{
      renderChildControls( offset, updateRect );
		return;
	}
   // draw the background
   // afterward, draw child controls...

   int BMW = mTextureObject->getWidth();
   int BMH = mTextureObject->getHeight();

   // Draw the top left corner.
   int CenterWidth  = BMW-(LeftMargin+RightMargin);
   int CenterHeight = BMH-(TopMargin+BottomMargin);
   int RightX       = BMW-RightMargin;
   int BottomY      = BMH-BottomMargin;

   // construct these on the fly in case something changes.
   // Top
   RectI sTopLeftRect  (0,0,LeftMargin,TopMargin);
   RectI sTopCenterRect(LeftMargin,0,CenterWidth,TopMargin);
   RectI sTopRightRect (RightX,0,RightMargin,TopMargin);
   // Center
   RectI sLeftCenterRect(0,TopMargin,LeftMargin,CenterHeight);
   RectI sCenterRect(LeftMargin,TopMargin,CenterWidth,CenterHeight);
   RectI sRightCenterRect(RightX,TopMargin,RightMargin,CenterHeight);
   // Bottom
   RectI sBottomLeftRect  (0,BottomY,LeftMargin,BottomMargin);
   RectI sBottomCenterRect(LeftMargin,BottomY,CenterWidth,BottomMargin);
   RectI sBottomRightRect (RightX,BottomY,RightMargin,BottomMargin);


   int DestCenterWidth = getWidth()-(LeftMargin+RightMargin);
   int DestCenterHeight = getHeight() - (TopMargin+BottomMargin);
   RectI dTopCenterRect(offset.x+LeftMargin,offset.y,DestCenterWidth,TopMargin);
   RectI dLeftCenterRect(offset.x,offset.y+TopMargin,LeftMargin,DestCenterHeight);
   RectI dCenter(offset.x+LeftMargin,offset.y+TopMargin,DestCenterWidth,DestCenterHeight);
   RectI dRightCenterRect(offset.x+LeftMargin+DestCenterWidth,offset.y+TopMargin,RightMargin,DestCenterHeight);
   RectI dBottomCenterRect(offset.x+LeftMargin,offset.y+TopMargin+DestCenterHeight,DestCenterWidth,BottomMargin);


   // Draw the container

   GFX->getDrawUtil()->clearBitmapModulation();
   // draw the corners
   GFXDrawUtil *Draw = GFX->getDrawUtil();
   // TL
   Draw->drawBitmapSR(mTextureObject, offset, sTopLeftRect);
   // TR
   Draw->drawBitmapSR(mTextureObject, Point2I(offset.x + (getWidth()-LeftMargin), offset.y),sTopRightRect);
   // BL
   Draw->drawBitmapSR(mTextureObject, Point2I(offset.x, offset.y +(getHeight()-BottomMargin)),sBottomLeftRect);
   // BR
   Draw->drawBitmapSR(mTextureObject, Point2I(offset.x + (getWidth()-LeftMargin), 
   offset.y +(getHeight()-BottomMargin)),sBottomRightRect);

   // draw the center sections.
   if (bTiled)
   {
	   Draw->drawBitmapTiledSR(mTextureObject,dTopCenterRect,sTopCenterRect);
	   Draw->drawBitmapTiledSR(mTextureObject,dLeftCenterRect,sLeftCenterRect);
	   Draw->drawBitmapTiledSR(mTextureObject,dCenter,sCenterRect);
	   Draw->drawBitmapTiledSR(mTextureObject,dRightCenterRect,sRightCenterRect);
	   Draw->drawBitmapTiledSR(mTextureObject,dBottomCenterRect,sBottomCenterRect);
   }
   else
   {
	   Draw->drawBitmapStretchSR(mTextureObject,dTopCenterRect,sTopCenterRect);
	   Draw->drawBitmapStretchSR(mTextureObject,dLeftCenterRect,sLeftCenterRect);
	   Draw->drawBitmapStretchSR(mTextureObject,dCenter,sCenterRect);
	   Draw->drawBitmapStretchSR(mTextureObject,dRightCenterRect,sRightCenterRect);
	   Draw->drawBitmapStretchSR(mTextureObject,dBottomCenterRect,sBottomCenterRect);
   }

   renderChildControls( offset, updateRect );
}

#1
01/29/2009 (11:18 am)
Nice useful GUI improvement. This is one of those things I had planned on doing, just never got around to it. No more solid color or stretched borders -- thanks Jaimi!
#2
01/29/2009 (1:55 pm)
nice resource!
#3
01/29/2009 (9:54 pm)
Wow, thats really neat! Thanks for posting. ;)
#4
02/04/2009 (2:53 am)
IN -> "GuiBitmapBorderBoundsCtrl.cpp" in the engine/gui/controls folder

everything works fine except i got 5 errors, and i wonder if someone can help with this! My ide tell me this...

line 137 trought 141

GFXDrawUtil::drawBitmapTiledSR : Function does not take 3 arguments

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

what i am missing?
thx!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
fixed! apprently tippo errors...when copying missing codes

->in gfxDrawUtil.h, when adding void drawBitmapTiledSR, in the end
be sure to add this as below
const GFXBitmapFlip in_flip = GFXBitmapFlip_None );

otherwise, you'll get errors like from my above post!
thank you for this wonderful resource!
it compile perfectly now!

#5
02/13/2009 (6:59 am)
@Hyborian:
Thanks - I double checked the code, and what I found out is that the new "markuplite" code block truncates text if the line is too long! I have updated the code above (and in the tile resource) and manually wrapped the lines so this no longer happens. Sorry for the trouble!
#6
04/14/2009 (11:52 pm)
Noob here: Anybody have this working with 1.8.1? I have lots of ": is not a member of 'GFXDevice'" errors on compiling that I have no clue on how to fix.

I think this is the best looking scaleable window solution I've seen and would love to get it working.
#7
05/12/2009 (9:11 pm)
@Rob - I'm in the process of upgrading to 1.8.1, and should have this ported soon.