Letschki
03-01-2010 22:05:20
Hello and happy new year!
Can anyone point me to an example of how to create a custom widget?
The problem i want to solve is to add features to existing QuickGUI classes. For example i want to create widgets with built in scripting support that are tightly integrated within my application. My first thought was to simply derive from the QuickGUI widget i want to 'enhance', but as i understand I cannot simply create a widget object, for example:
QuickGUI::Button * btnTest = new QuickGUI::Button("Name");
QuickGUI::Button * btnDerived = new QuickGUI::ButtonTest("Test"); // derived from QuickGUI::Button
Instead i have to use the createButton() method of the sheet or panel class. But to use this mechanism to create my own widget objects i have to build them as custom widgets, or?
I see the advantages of the latter approach, but perhaps i am completly on the wrong track
I am using QuickGUI 9.10 with Ogre 1.6.
Thanks in advance!!!
kungfoomasta
04-01-2010 19:31:47
I haven't made a tutorial on this, so its not fully tested, but I think it should be possible. For example the Panel widget has the following API:
Widget* createCustomWidget(const Ogre::String& className, WidgetDesc* d);
Prior to calling this API, you should:
- Register your new Widget Desc with the DescFactory
- Register your new Widget with the WidgetFactory
- Register your Widget's skin with the SkinDefinitionManager
- Define some skin types for this Widget. For example in a .skinTypes file.
Then you should be able to create your custom widget like this:
MyWidgetDesc* myDesc = QuickGUI::DescManager::getSingleton().createDesc("MyWidgetDesc","test");
// fill in myDesc properties
MyWidget* myWidget = dynamic_cast<MyWidget*>(somePanel->createCustomWidget("MyWidget",myDesc));
Being able to write "new Button(...)" would be nice, but a big change to the current design.
Letschki
04-01-2010 20:27:55
Thanks for the information!
I will try to implement it in the described way and report any success
/ failure
here.
Letschki
04-01-2010 22:35:23
Good news... thanks to your info i was able to implement a 'subclassed' button
Thanks!!!
Here is what i have done (basically what you advised):
1. Created a new class derived from QuickGUI::ButtonDesc (added own implementation of getClass() and getWidgetClass())
2. Created a new class derived from QuickGUI::Button (added own implementation of getClass())
3. Registered the new desc type, the new widget type and the new skin definition (Important: must be called before SkinTypeManager::loadTypes())
4. Added a new section to the .skinTypes file
5. Created the new button
[/list:u]
I think this sums it up. I have not tested this extensively, but my first tests seem promising
Here is the startup code to initialize the custom widget:
// Register the custom widgets (must be called before SkinTypeManager::loadTypes);
GfxGUI_Button::registerAsCustomWidget();
Button creation:
GfxGUI_ButtonDesc * buttonDesc = QuickGUI::DescManager::getSingleton().createDesc<GfxGUI_ButtonDesc>(WIDGET_DESC_NAME, "test_id");
buttonDesc->resetToDefault();
buttonDesc->widget_name = "MyNewButton";
buttonDesc->widget_dimensions.size = QuickGUI::Size(100, 25);
buttonDesc->widget_dimensions.position = QuickGUI::Point(50, 100);
GfxGUI_Button * myNewButton = dynamic_cast<GfxGUI_Button *>(m_sheetGameState->createCustomWidget(WIDGET_CLASS_NAME, buttonDesc));
myNewButton->setText("Subclassed");
Header file of the new button class:
#ifndef __GFXGUI_BUTTON__
#define __GFXGUI_BUTTON__
#define WIDGET_CLASS_NAME "NewButton"
#define WIDGET_DESC_NAME "NewButtonDesc"
class GfxGUI_ButtonDesc : public QuickGUI::ButtonDesc {
public:
GfxGUI_ButtonDesc();
~GfxGUI_ButtonDesc(void);
Ogre::String getClass();
Ogre::String getWidgetClass();
};
class GfxGUI_Button : public QuickGUI::Button {
public:
GfxGUI_Button(const Ogre::String& name);
~GfxGUI_Button(void);
Ogre::String getClass();
static void registerAsCustomWidget();
};
#endif // __GFXGUI_BUTTON__
CPP-File:
#include "Precompile.h"
#include "GfxGUI_Button.h"
// *** Class: GfxGUI_ButtonDesc
GfxGUI_ButtonDesc::GfxGUI_ButtonDesc() : QuickGUI::ButtonDesc() {
}
GfxGUI_ButtonDesc::~GfxGUI_ButtonDesc(void) {
}
Ogre::String GfxGUI_ButtonDesc::getClass() {
return WIDGET_DESC_NAME;
}
Ogre::String GfxGUI_ButtonDesc::getWidgetClass() {
return WIDGET_CLASS_NAME;
}
// *** Class: GfxGUI_Button
GfxGUI_Button::GfxGUI_Button(const Ogre::String& name) : QuickGUI::Button(name) {
}
GfxGUI_Button::~GfxGUI_Button(void) {
}
Ogre::String GfxGUI_Button::getClass() {
return WIDGET_CLASS_NAME;
}
void GfxGUI_Button::registerAsCustomWidget() {
// Register the new widget type
QuickGUI::WidgetFactory* widgetFactory = QuickGUI::FactoryManager::getSingletonPtr()->getWidgetFactory();
widgetFactory->registerClass<GfxGUI_Button>(WIDGET_CLASS_NAME);
// Register the new description type
QuickGUI::DescFactory* descFactory = QuickGUI::FactoryManager::getSingletonPtr()->getDescFactory();
descFactory->registerClass<GfxGUI_ButtonDesc>(WIDGET_DESC_NAME);
// Register the widget's skin with the SkinDefinitionManager
QuickGUI::SkinDefinition* skinDefinition = OGRE_NEW_T(QuickGUI::SkinDefinition, Ogre::MEMCATEGORY_GENERAL)(WIDGET_CLASS_NAME);
skinDefinition->defineSkinElement(DEFAULT);
skinDefinition->defineSkinElement(OVER);
skinDefinition->defineSkinElement(DOWN);
skinDefinition->definitionComplete();
QuickGUI::SkinDefinitionManager::getSingleton().registerSkinDefinition(WIDGET_CLASS_NAME, skinDefinition);
}
.skinTypes file additions (copied from "Button"):
NewButton default
{
SkinElement default
{
Border_Bottom 2
Border_Left 2
Border_Right 2
Border_Top 2
Texture qgui.button.png
TileBackground false
TileBorders true
}
SkinElement down
{
Border_Bottom 2
Border_Left 2
Border_Right 2
Border_Top 2
Texture qgui.button.down.png
TileBackground false
TileBorders true
}
SkinElement over
{
Border_Bottom 2
Border_Left 2
Border_Right 2
Border_Top 2
Texture qgui.button.over.png
TileBackground false
TileBorders true
}
}
kungfoomasta
04-01-2010 23:28:46
Awesome! I like how you registered everything in one place, maybe I should have done that for each widget also. Not that it matters too much, as long as they all get called at some point.