News | About | Download | Documentation | Development | Links
ClanGUI contains a powerful mechanism to code custom themes, or styles as we call them in ClanGUI. Styles are very flexible, yet very easy to implement. This document will guide you through creation of a custom style.
Each component in ClanGUI is clearly separated into logic and presentation. When creating a new style for a component (for example CL_Button), you create a new class which does the drawing of a component - the logic is still the same between different styles.
A CL_StyleManager is used to attach styles to each component available. So in order to create a new style you need two parts - a stylemanager, and then the style-classes for each component you want a new look for.
The standard GUI theme in ClanGUI very much resembles any desktop-gui used in applications. This doesn't always fit with games.
Some of the components in the default GUI theme supports surfaces, like CL_Button. So, if you only wants some nice-looking buttons in your game which use predrawed pictures, you can still use the default theme. But if you want a custom-looking inputbox or scrollbar, you need to create a custom theme.
Create a new file called stylemanager_cooltheme.h, and insert the following code into it:
#ifndef header_stylemanager_cooltheme
#define header_stylemanager_cooltheme
#include <ClanLib/gui.h>
#include <ClanLib/guistyle.h> // Only include this line for ClanLib 0.7 and higher
class CL_StyleManager_CoolTheme : public CL_StyleManager_Default
{
public:
CL_StyleManager_CoolTheme(CL_ResourceManager *resources);
// Connect component styles to component.
// The 'type' parameter indicates what type the component is.
virtual void connect_styles(const std::string &type, CL_Component *owner);
};
#endif
The new stylemanager (CoolTheme) inherits the CL_StyleManager_Default. This means it will use the default theme for any components you don't define a new theme for. Note that it is not neccessary to inherit from CL_StyleManager_Default - you could also inherit from CL_StyleManager, but if you then try to use a component for which you haven't created a style for, nothing will be drawn for the component.
The connect_styles() is the function which attaches the styles to the various components. Make sure you inherit this function.
Next, create a new file called stylemanager_cooltheme.cpp, and insert the following code into it:
#include "stylemanager_cooltheme.h"
#include "button_cooltheme.h"
CL_StyleManager_CoolTheme::CL_StyleManager_CoolTheme(CL_ResourceManager *resources)
: CL_StyleManager_Default(resources)
{
}
void CL_StyleManager_CoolTheme::connect_styles(const std::string &type, CL_Component *component)
{
if (type == "button")
{
CL_Button *button = (CL_Button *)component;
button->attach_style(new CL_Button_CoolTheme(button, this));
}
else
{
CL_StyleManager_Default::connect_styles(type, component);
}
}
A file called button_cooltheme.h is included here; we'll get back to that in the next section.
The connect_styles() function has two parameters - type and component.
The type parameter contains the name of the component to be styled - examples are label, button, frame, inputbox, scrollbar, radiobutton, listbox, window, etc. For each component you want to put a style on, make a new test for the type, and attach the style using the attach_style() function in the component. Notice how its done through creating a new style class called CL_Button_CoolTheme.
Any components we don't attach, we just pass on to the default stylemanager. You can skip doing this if you have styled all the component you want to use, or don't want to use the default stylemanager at all.
Create a new file called button_cooltheme.h, and insert the following code into it:
#ifndef header_button_cooltheme
#define header_button_cooltheme
#include <ClanLib/gui.h>
#include "stylemanager_cooltheme.h"
class CL_Button_CoolTheme : public CL_ComponentStyle
{
public:
CL_Button_CoolTheme(CL_Button *button, CL_StyleManager_CoolTheme *style);
private:
CL_Slot slot_paint;
void on_paint();
CL_Button *button;
};
#endif
Each component-style inherits from the class CL_ComponentStyle. The CL_Button object you get in the constructor is the logic class for the button. You can query it for states (is_down()) and size etc.
In this simple style, we only prepare to hook into the sig_paint signal - therefore the slot_paint and on_paint() code. Read on for more specifics on this.
Create a new file called button_cooltheme.cpp, and insert the following code into it:
#include <ClanLib/display.h>
#include "button_cooltheme.h"
CL_Button_CoolTheme::CL_Button_CoolTheme(CL_Button *button, CL_StyleManager_CoolTheme *style)
: CL_ComponentStyle(button)
{
this->button = button;
slot_paint = button->sig_paint().connect(this, &CL_Button_CoolTheme::on_paint);
}
void CL_Button_CoolTheme::on_paint()
{
int button_width = button->get_width();
int button_height = button->get_height();
CL_Display::fill_rect(CL_Rect(1, 1, button_width - 1, button_height - 1), CL_Color(70, 120, 255));
if(button->is_down())
CL_Display::draw_rect(CL_Rect(0, 0, button_width, button_height), CL_Color::white);
else
CL_Display::draw_rect(CL_Rect(0, 0, button_width, button_height), CL_Color::black);
}
In the constructor we hook into the sig_paint signal of the CL_Button. This allows us to do custom drawing of the button.
The on_paint() function fetches the size of the button, and draws some simple rects, based on the button state - if its pressed down or not.
We have now created a very simple theme, using only one themed component - a CL_Button. Lets try to test it, and see if it behaves as we expect it to do.
#include <ClanLib/core.h>
#include <ClanLib/gui.h>
#include <ClanLib/gl.h>
#include <ClanLib/application.h>
#include <ClanLib/display.h>
#include "stylemanager_cooltheme.h"
class StyleTest : public CL_ClanApplication
{
public:
int main(int argc, char** argv)
{
try
{
CL_SetupCore::init();
CL_SetupGUI::init();
CL_SetupDisplay::init();
CL_SetupGL::init();
CL_DisplayWindow window("StyleTest", 640, 480);
CL_ResourceManager resources("gui.scr", false);
CL_StyleManager_CoolTheme style(&resources);
CL_GUIManager gui(&style);
CL_Button button(CL_Rect(10, 10, 100, 40), "", &gui);
while (!CL_Keyboard::get_keycode(CL_KEY_ESCAPE))
{
CL_Display::clear(CL_Color::grey);
gui.show();
CL_Display::flip();
CL_System::keep_alive(10);
}
CL_SetupDisplay::deinit();
CL_SetupGUI::deinit();
CL_SetupGL::deinit();
CL_SetupCore::deinit();
}
catch (CL_Error e)
{
std::cout << e.message.c_str() << std::endl;
}
return 0;
}
} app;
Remember to copy the Documentation/Examples/GUIThemeDefault files into your project, so it has some fonts and resources to use. These can be replaced later with your own resources.
Have a look at the NetObjects example on how to expand on this to create a full-blown custom GUI theme.