GuiBitmapButtonControl: Setting bitmaps via Profile.
by Kevin Bluck · 08/30/2005 (1:34 am) · 3 comments
So, I was messing with the editors and I discovered that GuiInspector was specifying its 'delete' bitmap button using a hardcoded image file. I thought this was odd, and wondered why a profile wasn't being used instead? I quickly discovered that it was because there weren't really just one bitmap, but actually four decorated with a suffix convention to identify them. The "bitmap name" was really just a root name, and the "real" bitmap names were generated automatically in code. Loading a bitmap from a profile failed to perform this auto-decoration.
I still didn't like the idea of having to specify the bitmap directly in every button control definition, not to mention the hardcoding necessary in the C++ source. So, I took a few minutes to change the GuiBitmapButtonControl such that it could have its bitmap root name.
A quick summary: GuiBitmapButtonControl takes via the setBitmap() method a root filename. Internally, it adds suffixes to this filename for up to four "button state" bitmaps. The suffixes are:
_n: Normal appearance
_h: Hilited appearance
_d: Depressed appearance
_i: Inactive appearance.
So, for example, the GuiInspectors delete button bitmap root name is 'common/ui/inspector_delete', and so it expects to actually find four files in the common/ui folder named inspector_delete_n.png, inspector_delete_h.png, inspector_delete_d.png, and inspector_delete_i.png.
It was simple enough to specify the root name through the profile. But I discovered an annoying warning; the profile tries to load the bitmap itself, and since the root name doesn't actually exist, it would throw a console warning. So, I made it so that the _n "normal" bitmap should be specified in the profile definition, and the root name would be extracted from that.
Note that this was done against 1.4RC1. 1.3 should be substantially similar, but some source files are in different folders and some line numbers may be different.
I replaced the entire setBitmap() method near line 94 in engine/gui/controls/GuiBitmapButtonCtrl.cc with this one:
The general advantage here is that commonplace buttons can have their bitmaps specified using a profile rather than individually. The immediate additional benefit in this case is that I was able to eliminate the hardcoded bitmap path from GuiInspector.cc, replacing it instead with a hardcoded profile name.
At line 583 of guiInspector.cc, this:
becomes this:
Of course, the profile itself must be defined. I added this to example/common/ui/defaultProfiles.cs, right under the existing GuiInspectorTextEditProfile definition:
Bug reports, comments, corrections welcome.
I still didn't like the idea of having to specify the bitmap directly in every button control definition, not to mention the hardcoding necessary in the C++ source. So, I took a few minutes to change the GuiBitmapButtonControl such that it could have its bitmap root name.
A quick summary: GuiBitmapButtonControl takes via the setBitmap() method a root filename. Internally, it adds suffixes to this filename for up to four "button state" bitmaps. The suffixes are:
_n: Normal appearance
_h: Hilited appearance
_d: Depressed appearance
_i: Inactive appearance.
So, for example, the GuiInspectors delete button bitmap root name is 'common/ui/inspector_delete', and so it expects to actually find four files in the common/ui folder named inspector_delete_n.png, inspector_delete_h.png, inspector_delete_d.png, and inspector_delete_i.png.
It was simple enough to specify the root name through the profile. But I discovered an annoying warning; the profile tries to load the bitmap itself, and since the root name doesn't actually exist, it would throw a console warning. So, I made it so that the _n "normal" bitmap should be specified in the profile definition, and the root name would be extracted from that.
Note that this was done against 1.4RC1. 1.3 should be substantially similar, but some source files are in different folders and some line numbers may be different.
I replaced the entire setBitmap() method near line 94 in engine/gui/controls/GuiBitmapButtonCtrl.cc with this one:
//-------------------------------------
void GuiBitmapButtonCtrl::setBitmap(const char *name)
{
// If no bitmap name is supplied, try to get it from the profile.
if( !(name) || !(*name) )
{
if( mProfile )
{
// If the conventional "normal state" bitmap name is supplied, strip the trailing '_n'
// to get the root bitmap name. Otherwise, just use it directly as the root name.
dsize_t nameLen = dStrlen( mProfile->mBitmapName );
if( ( nameLen > 2 ) && ( dStrcmp( mProfile->mBitmapName + nameLen - 2, "_n" ) == 0 ) )
{
dsize_t subStrLen = nameLen - 2;
char* subStr = new char[ subStrLen ];
dStrncpy( subStr, mProfile->mBitmapName, subStrLen );
subStr[ subStrLen ] = 0;
mBitmapName = StringTable->insert(subStr);
delete [] subStr;
}
else
{
mBitmapName = StringTable->insert(mProfile->mBitmapName);
}
}
}
else
{
mBitmapName = StringTable->insert(name);
}
if(!isAwake())
return;
if (mBitmapName && *mBitmapName)
{
char* buffer = new char[dStrlen(mBitmapName) + 3];
char *p;
dStrcpy(buffer, mBitmapName);
p = buffer + dStrlen(buffer);
dStrcpy(p, "_n");
mTextureNormal = TextureHandle(buffer, BitmapTexture, true);
dStrcpy(p, "_h");
mTextureHilight = TextureHandle(buffer, BitmapTexture, true);
if (!mTextureHilight)
mTextureHilight = mTextureNormal;
dStrcpy(p, "_d");
mTextureDepressed = TextureHandle(buffer, BitmapTexture, true);
if (!mTextureDepressed)
mTextureDepressed = mTextureHilight;
dStrcpy(p, "_i");
mTextureInactive = TextureHandle(buffer, BitmapTexture, true);
if (!mTextureInactive)
mTextureInactive = mTextureNormal;
delete [] buffer;
}
else
{
mTextureNormal = NULL;
mTextureHilight = NULL;
mTextureDepressed = NULL;
mTextureInactive = NULL;
}
setUpdate();
}The general advantage here is that commonplace buttons can have their bitmaps specified using a profile rather than individually. The immediate additional benefit in this case is that I was able to eliminate the hardcoded bitmap path from GuiInspector.cc, replacing it instead with a hardcoded profile name.
At line 583 of guiInspector.cc, this:
delButt->setField("profile", "GuiDefaultProfile");
delButt->setField("bitmap", "common/ui/inspector_delete");becomes this:
delButt->setField("profile", "GuiInspectorDeleteButtonProfile");Of course, the profile itself must be defined. I added this to example/common/ui/defaultProfiles.cs, right under the existing GuiInspectorTextEditProfile definition:
if(!isObject(GuiInspectorDeleteButtonProfile)) new GuiControlProfile( GuiInspectorDeleteButtonProfile )
{
bitmap = "./inspector_delete_n";
};Bug reports, comments, corrections welcome.
#2
09/02/2005 (1:54 am)
What Sebastien says is the approach I've taken as well. I don't know about this one, but in any case it's an example on how to change the code :)
#3
Perhaps I'll make up a new class for bitmap buttons that use arrays. Someday.
09/02/2005 (7:39 pm)
I agree that bitmap arrays would be a better way to go. However, I was aiming for minimal impact on the existing implementation of GuiBitmapButtonControl, which uses the suffix decoration model. If one doesn't want to use profiles, then they can still be used the same way as before.Perhaps I'll make up a new class for bitmap buttons that use arrays. Someday.

Torque 3D Owner Sebastien Bourgon
Then you'd only need 1 image for each button. Would make for less actual art assets floating around too.