[SOLVED] Custom widgets? Example or docs?

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. 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. :)