Theme Manager v1.0
by Tim Newell · 06/08/2002 (8:14 am) · 12 comments
Download Code File
Theme Manager v1.0
This tutorial uses the Skinnable GUI Controls in TGE tutorial posted by Justin "avon Lady" Dujardin. This tutorial adds the ability to create themes easily and to switch them in realtime inside torque via the Graphics Tab in the Optionsdlg Pane.
Screenshots:


First thing you need to do is to apply Justin Dujardin's tutorial to your game. (this tutorial assumes you applied the GuiControl C++ edit too that he mentioned was optional) Then you need to apply the following C++ changes:
Note: I only make changes to most of the same files he made changes too.
engine/gui/guiControl.h
around line 105 (which is in the protected section of the guicontrol class) add:
engine/gui/guiButtonCtrl.cc
in GuiButtonCtrl::GuiButtonCtrl() add:
in the onRender Function you should find something like this:
you need to replace it with:
-------------------------------------------------------------------------------------------------
engine/gui/guiCheckBoxCtrl.cc
in GuiCheckBoxCtrl::GuiCheckBoxCtrl() add:
in the onRender Function you should find something like this:
you need to replace it with:
-----------------------------------------------------------------------------------------------
engine/gui/guiPopUpCtrl.cc
in GuiPopUpCtrl::GuiPopUpCtrl() add:
in the onRender Function you should find something like this:
you need to replace it with:
----------------------------------------------------------------------------------------------
engine/gui/guiRadioCtrl.cc
in GuiRadioCtrl::GuiRadioCtrl() add:
----------------------------------------------------------------------------------------------
engine/gui/guiScrollCtrl.cc
in GuiScrollCtrl::GuiScrollCtrl() add:
in the onRender Function you need to add the following code:
between:
----------------------------------------------------------------------------------------------
engine/gui/guiSliderCtrl.cc
in GuiSliderCtrl::GuiSliderCtrl() add:
in the onRender Function you should find something like this:
you need to replace it with:
-----------------------------------------------------------------------------------------------
engine/gui/guiTextEditCtrl.cc
in GuiTextEditCtrl::GuiTextEditCtrl() add:
in the onRender Function you should find something like this:
you need to replace it with:
------------------------------------------------------------------------------------------------
engine/gui/guiWindowCtrl.cc
in GuiWindowCtrl::GuiWindowCtrl() add:
in the onRender Function you should find something like this:
you need to replace it with:
------------------------------------------------------------------------------------------------
Now that those C++ changes are out of the way, lets add the manager to the script and setup a couple of themes. (2 themes are provided in the accompany zip...default is the windowsXP theme that was in [avon]'s tutorial and the other theme labeled rpg is an ugly recoloring of the XP theme to show that themes do work. Im not an artist so don't expect pretty things :))
First thing you need to do is open the Gui editor and add a Textctrl to the Optionsdlg's GraphicsPane labeled "Theme:" and add a Menu (guipopupmenuctrl) and name it OptGrahicsThemeMenu. Save your work and exit torque. (it should look similar to the other 3 menus on that pane - Display Driver, Resolution, and Bit Depth)
Now open fps/client/scripts/optionsDlg.cs
Scroll to the very end of the file and add:
Now scroll up to function optionsDlg::applyGraphics( %this ) and add:
After %newFullScreen = OptGraphicsFullscreenToggle.getValue();
Now scroll on up to function OptGraphicsDriverMenu::onSelect( %this, %id, %text ) and Add to the end of it:
---------------------------------------------------------------------------------------------------
Now all that is left is to install the themes from the zip file
Create the dir example/common/ui/themes and unzip the rpg and default folders into there.
To create a new theme you can simply copy the default folder, rename it to something else and make sure you rename all the images and the .th file.
ImportantNote: You must name the .th file in the format [themename]Theme.th. ex: rpgTheme.th
thats it...launch torque and go to the options pane, select rpg and click apply.
-Tim aka Spock
Theme Manager v1.0
This tutorial uses the Skinnable GUI Controls in TGE tutorial posted by Justin "avon Lady" Dujardin. This tutorial adds the ability to create themes easily and to switch them in realtime inside torque via the Graphics Tab in the Optionsdlg Pane.
Screenshots:


First thing you need to do is to apply Justin Dujardin's tutorial to your game. (this tutorial assumes you applied the GuiControl C++ edit too that he mentioned was optional) Then you need to apply the following C++ changes:
Note: I only make changes to most of the same files he made changes too.
engine/gui/guiControl.h
around line 105 (which is in the protected section of the guicontrol class) add:
//Added for skinnable GUI char mOldSkinBitmap[80]; //might want to adjust this to something like 255 if you think filenames are going to be really long.
engine/gui/guiButtonCtrl.cc
in GuiButtonCtrl::GuiButtonCtrl() add:
dStrcpy(mOldSkinBitmap, "");
in the onRender Function you should find something like this:
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();
}you need to replace it with:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
if(dStrcmp(def->mBitmapName,mOldSkinBitmap))
{
mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
mProfile->constructBitmapArray();
mBitmapBounds = mProfile->mBitmapArrayRects.address();
dStrcpy(mOldSkinBitmap,mProfile->mBitmapName);
}-------------------------------------------------------------------------------------------------
engine/gui/guiCheckBoxCtrl.cc
in GuiCheckBoxCtrl::GuiCheckBoxCtrl() add:
dStrcpy(mOldSkinBitmap, "");
in the onRender Function you should find something like this:
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();
}you need to replace it with:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
if(dStrcmp(def->mBitmapName,mOldSkinBitmap))
{
mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
mProfile->constructBitmapArray();
mBitmapBounds = mProfile->mBitmapArrayRects.address();
dStrcpy(mOldSkinBitmap,mProfile->mBitmapName);
}-----------------------------------------------------------------------------------------------
engine/gui/guiPopUpCtrl.cc
in GuiPopUpCtrl::GuiPopUpCtrl() add:
dStrcpy(mOldSkinBitmap, "");
in the onRender Function you should find something like this:
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();
}you need to replace it with:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
if(dStrcmp(def->mBitmapName,mOldSkinBitmap))
{
mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
mProfile->constructBitmapArray();
mBitmapBounds = mProfile->mBitmapArrayRects.address();
dStrcpy(mOldSkinBitmap,mProfile->mBitmapName);
}----------------------------------------------------------------------------------------------
engine/gui/guiRadioCtrl.cc
in GuiRadioCtrl::GuiRadioCtrl() add:
dStrcpy(mOldSkinBitmap, "");
----------------------------------------------------------------------------------------------
engine/gui/guiScrollCtrl.cc
in GuiScrollCtrl::GuiScrollCtrl() add:
dStrcpy(mOldSkinBitmap, "");
in the onRender Function you need to add the following code:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
if(dStrcmp(def->mBitmapName,mOldSkinBitmap))
{
mTextureHandle = NULL;
mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
mTextureHandle = mProfile->mTextureHandle;
mTextureHandle.setFilterNearest();
mProfile->constructBitmapArray();
mBitmapBounds = mProfile->mBitmapArrayRects.address();
dStrcpy(mOldSkinBitmap,mProfile->mBitmapName);
} between:
RectI r(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
//insert above code here
if (mProfile->mOpaque)
dglDrawRectFill(r, mProfile->mFillColor);----------------------------------------------------------------------------------------------
engine/gui/guiSliderCtrl.cc
in GuiSliderCtrl::GuiSliderCtrl() add:
dStrcpy(mOldSkinBitmap, "");
in the onRender Function you should find something like this:
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();
}you need to replace it with:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
if(dStrcmp(def->mBitmapName,mOldSkinBitmap))
{
mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
mProfile->constructBitmapArray();
mBitmapBounds = mProfile->mBitmapArrayRects.address();
dStrcpy(mOldSkinBitmap,mProfile->mBitmapName);
}-----------------------------------------------------------------------------------------------
engine/gui/guiTextEditCtrl.cc
in GuiTextEditCtrl::GuiTextEditCtrl() add:
dStrcpy(mOldSkinBitmap, "");
in the onRender Function you should find something like this:
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();
}you need to replace it with:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
if(dStrcmp(def->mBitmapName,mOldSkinBitmap))
{
mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
mProfile->constructBitmapArray();
mBitmapBounds = mProfile->mBitmapArrayRects.address();
dStrcpy(mOldSkinBitmap,mProfile->mBitmapName);
}------------------------------------------------------------------------------------------------
engine/gui/guiWindowCtrl.cc
in GuiWindowCtrl::GuiWindowCtrl() add:
dStrcpy(mOldSkinBitmap, "");
in the onRender Function you should find something like this:
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();
}you need to replace it with:
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject(mProfile->getName()));
if (def != NULL)
if(dStrcmp(def->mBitmapName,mOldSkinBitmap))
{
mProfile->flushBitmapInfo(); //they're different, which means the skin was changed, so update.
mProfile->constructBitmapArray();
mBitmapBounds = mProfile->mBitmapArrayRects.address();
dStrcpy(mOldSkinBitmap,mProfile->mBitmapName);
}------------------------------------------------------------------------------------------------
Now that those C++ changes are out of the way, lets add the manager to the script and setup a couple of themes. (2 themes are provided in the accompany zip...default is the windowsXP theme that was in [avon]'s tutorial and the other theme labeled rpg is an ugly recoloring of the XP theme to show that themes do work. Im not an artist so don't expect pretty things :))
First thing you need to do is open the Gui editor and add a Textctrl to the Optionsdlg's GraphicsPane labeled "Theme:" and add a Menu (guipopupmenuctrl) and name it OptGrahicsThemeMenu. Save your work and exit torque. (it should look similar to the other 3 menus on that pane - Display Driver, Resolution, and Bit Depth)
Now open fps/client/scripts/optionsDlg.cs
Scroll to the very end of the file and add:
//Added Themes Menu stuff
/////////////////////////////////////////////////////////////////////////////
function fillThemeList() {
OptGraphicsThemeMenu.clear();
%i = 0;
for(%file = findFirstFile("common/ui/themes/*.th");
%file !$= ""; %file = findNextFile("common/ui/themes/*.th")) {
%strip = getSubStr(%file, 17, strlen( %file ));
OptGraphicsThemeMenu.add(getSubStr(%strip,0,strstr(%strip,"/")), %i++);
}
}
$CurTheme = "default";Now scroll up to function optionsDlg::applyGraphics( %this ) and add:
%newTheme = OptGraphicsThemeMenu.getText();
if (%newTheme !$= "") {
exec("common/ui/themes/" @ %newTheme @ "/" @ %newTheme @ "Theme.th");
$CurTheme = %newTheme;
}After %newFullScreen = OptGraphicsFullscreenToggle.getValue();
Now scroll on up to function OptGraphicsDriverMenu::onSelect( %this, %id, %text ) and Add to the end of it:
//theme switching/////////////////////////////////
fillThemeList();
%selId = OptGraphicsThemeMenu.findText( $CurTheme );
if ( %selId == -1 )
%selId = 0;
OptGraphicsThemeMenu.setSelected( %selId );---------------------------------------------------------------------------------------------------
Now all that is left is to install the themes from the zip file
Create the dir example/common/ui/themes and unzip the rpg and default folders into there.
To create a new theme you can simply copy the default folder, rename it to something else and make sure you rename all the images and the .th file.
ImportantNote: You must name the .th file in the format [themename]Theme.th. ex: rpgTheme.th
thats it...launch torque and go to the options pane, select rpg and click apply.
-Tim aka Spock
#2
06/08/2002 (12:36 am)
As a Note has anyone else gotten the mProfile->mBitmapName to work as avon suggsted above...I couldnt get it to work is why I used the mOldSkinBitmap....perhaps there is something missing and if no one else can get it to work that might be the case cause looking at the code I thought his way should work but in practice it didn't.
#3
06/20/2002 (2:42 pm)
Tim, I added your script code only, not the C++ changes. It works perfectly. I didn't need the mOldSkinBitmap stuff. Many thanks to you and Justin.
#4
06/20/2002 (3:50 pm)
hrmm..Interesting. Did it do realtime switching? I would thing that without the C++ code it wouldn't work quite right. Did you mean none if the C++ code or just my C++ changes? If you got it to work with just Justin's C++ code then it worked for you also and I wonder why it didn't work for me. Maybe Ill have to take another look at it.
#5
06/20/2002 (11:24 pm)
Tim, I added Justins C++ code and your script code.
#6
06/21/2002 (12:45 am)
alright...I'll have to check that...unless he fixed it you might want to check the scroll control as he didnt have it completed in his tutorial.
#7
The only problem left, is the popupMenuControl, i.e. it changes its skin, but in a somehow "undefined" manner.
06/21/2002 (12:00 pm)
Tim, you're right. I modified the scroll control and window control a little bit. I compare def->mBitmapName against mTextureHandle.getName() (I didn't delete the mTextureHandle from the window control like avon's tut). The only problem left, is the popupMenuControl, i.e. it changes its skin, but in a somehow "undefined" manner.
#8
A similar change needs to be made to load the last theme on startup.
That way it automagically gets saved between sessions by the preference management tool.
(Edits are because I originally typed prefs instead of pref and did not reference the need to apply the theme on startup).
Additional note: Because it is a "good idea" to automatically restore the user's preferred theme, it would also be a "good idea" to make a themes.cs, and put all the functionality there. That way, you only have one implementation to change if you ever need to expand on the processing when a theme is loaded or unloaded.
Good tutorial - very useful
06/22/2002 (12:43 pm)
I would suggest also that instead of just $CurTheme, you probably really want $pref::Client::UI::CurTheme, even though it is a bit longer.A similar change needs to be made to load the last theme on startup.
That way it automagically gets saved between sessions by the preference management tool.
(Edits are because I originally typed prefs instead of pref and did not reference the need to apply the theme on startup).
Additional note: Because it is a "good idea" to automatically restore the user's preferred theme, it would also be a "good idea" to make a themes.cs, and put all the functionality there. That way, you only have one implementation to change if you ever need to expand on the processing when a theme is loaded or unloaded.
Good tutorial - very useful
#9
10/07/2002 (1:40 am)
flushBitmapInfo() is removed from GuiControlProfile??
#10
nice tut! Works like a charm.
I only got caught up on one thing.
There was a small type where you mentioned
to add menu and name it "OptGrahicsThemeMenu".
Otherwise, it works great. Thank you so much
and this helps advance the idea I working on.
Not so much allowing people to pick their own themes, but changing the themes based on their player selection.
Thanks,
Ben "bato" Ward
11/17/2002 (1:12 am)
Tim, nice tut! Works like a charm.
I only got caught up on one thing.
There was a small type where you mentioned
to add menu and name it "OptGrahicsThemeMenu".
Otherwise, it works great. Thank you so much
and this helps advance the idea I working on.
Not so much allowing people to pick their own themes, but changing the themes based on their player selection.
Thanks,
Ben "bato" Ward
#11
11/21/2003 (7:32 pm)
How about updating for 1.2 support?
#12
FYI.
05/24/2005 (7:39 pm)
Both this and the Skinnable GUI Controls resources are currently incompatible with the latest 1.3 release.FYI.

Associate Justin DuJardin
Default Studio Name
The way you went about changing skins is commendable. The only difference i've noticed between the one I use and the one you've presented is that mine applies the skin, not according to when you hit apply, but changes when you select a different skin.
Goodjob none-the-less. :)