Wartbed:GUI evaluation

From Dark Omen Wiki

(Difference between revisions)
Jump to: navigation, search
(CEGUI)
(QuickGUI)
Line 23: Line 23:
http://www.ogre3d.org/wiki/index.php/QuickGUI
http://www.ogre3d.org/wiki/index.php/QuickGUI
<br>http://stormsonggames.com/downloads/images/OgreForum/qgui_9_3.jpg
<br>http://stormsonggames.com/downloads/images/OgreForum/qgui_9_3.jpg
-
<br>Made for OGRE, inspired by BetGUI and CEGUI. It seems reasonably complete and is the framework I've gotten furthest with so far.
+
<br>Made for OGRE, inspired by BetGUI and CEGUI.  
-
<pre style="margin:1em; background:black;color:lightgray; size:small;">
+
-
/************************************************************************/
+
-
/* EVALUATION OF QuickGUI                                              */
+
-
/*                                                                      */
+
-
/*                                                                      */
+
-
/************************************************************************/
+
-
#include "../source/wartbed/Wartbed.h"
+
* QuickGUI has somewhat overly complicated initial set-up syntax requirements.
-
#include <QuickGUI.h>
+
* QuickGUI is quite easy to work with and neither terse not verbose
-
 
+
* Widgets are widgets and communicated with through methods, not messages. This is object-oriented but also may entail plenty of casting depending on coding style.  
-
 
+
* The widgets are more limited in automagic functionality than CEGUI (f.i. no 4-state button widget) but are easy to work with programatically on events.
-
#pragma comment(lib, "D:/( C++ )/QuickGUI_9_03/bin/QuickGUI_d.lib")
+
* QuickGUI seems not to support ImageSet-like bitmap abstractions, wherefore all icons must be in unique files?
-
 
+
* There are quirks: events must be methods in a class rather than free functions. The even handler class must be polymorphic (at least one virtual method) dur to internal dynamic_casts under the QuickGUI hood. QuickGUI seems less mature and robustly written than CEGUI.
-
 
+
-
QuickGUI::GUIManager    *g_pGUIManager  = 0;
+
-
QuickGUI::Sheet        *g_pSheet      = 0;
+
-
QuickGUI::Button        *g_pButton      = 0;
+
-
 
+
-
 
+
-
struct FrameListener : wb::FrameListener
+
-
{
+
-
    bool frameStarted(const Ogre::FrameEvent& evt)
+
-
    {
+
-
        using namespace wb::ogre;
+
-
 
+
-
        if (pKeyboard->isKeyDown(OIS::KC_ESCAPE))
+
-
        {
+
-
            Stop();
+
-
            return false;
+
-
        }
+
-
 
+
-
        else
+
-
            wb::FrameListener::frameStarted( evt );
+
-
    }
+
-
};
+
-
 
+
-
 
+
-
struct KeyListener : wb::KeyListener
+
-
{
+
-
    bool keyPressed(const OIS::KeyEvent& e)
+
-
    {
+
-
        g_pGUIManager->injectChar( static_cast<Ogre::UTFString::unicode_char>(e.text) );
+
-
        g_pGUIManager->injectKeyDown( static_cast<QuickGUI::KeyCode>(e.key) );
+
-
        return true;
+
-
    }
+
-
 
+
-
    bool keyReleased(const OIS::KeyEvent& e)
+
-
    {
+
-
        g_pGUIManager->injectKeyUp( static_cast<QuickGUI::KeyCode>(e.key) );
+
-
        return true;
+
-
    }
+
-
};
+
-
 
+
-
 
+
-
struct MouseListener : wb::MouseListener
+
-
{
+
-
    bool mouseMoved( OIS::MouseEvent const &e )
+
-
    {
+
-
        g_pGUIManager->injectMousePosition( e.state.X.abs, e.state.Y.abs );
+
-
 
+
-
        if(e.state.Z.rel != 0)
+
-
            g_pGUIManager->injectMouseWheelChange( e.state.Z.rel );
+
-
 
+
-
        return true;
+
-
    }
+
-
 
+
-
    bool mousePressed( OIS::MouseEvent const &e, OIS::MouseButtonID id)
+
-
    {
+
-
        g_pGUIManager->injectMouseButtonDown( static_cast<QuickGUI::MouseButtonID>(id) );
+
-
        return true;
+
-
    }
+
-
 
+
-
    bool mouseReleased( OIS::MouseEvent const &e, OIS::MouseButtonID id)
+
-
    {
+
-
        g_pGUIManager->injectMouseButtonUp( static_cast<QuickGUI::MouseButtonID>(id) );
+
-
        return true;
+
-
    }
+
-
};
+
-
 
+
-
 
+
-
struct GUIEventHandler
+
-
{
+
-
    GUIEventHandler()
+
-
    {
+
-
        g_pButton->addWidgetEventHandler
+
-
            (
+
-
                QuickGUI::WIDGET_EVENT_MOUSE_BUTTON_UP,  
+
-
                &GUIEventHandler::onClick,
+
-
                this
+
-
            );
+
-
    }
+
-
 
+
-
    // Note that this must be declared virtual because QuickGUI required a
+
-
    // polymorphic class or its dynamic_cast calls will throw
+
-
    //
+
-
    virtual ~GUIEventHandler() {}
+
-
 
+
-
    void onClick( QuickGUI::EventArgs const &args)
+
-
    { 
+
-
        QuickGUI::MouseEventArgs const &mea =
+
-
            static_cast<const QuickGUI::MouseEventArgs &>( args );
+
-
 
+
-
        if (mea.button == QuickGUI::MB_Left)
+
-
        {
+
-
        MessageBeep( MB_OK );
+
-
        }
+
-
 
+
-
        if (mea.button == QuickGUI::MB_Right)
+
-
        {
+
-
        MessageBeep( MB_ICONEXCLAMATION );
+
-
        }
+
-
    }
+
-
};
+
-
 
+
-
 
+
-
//=============================================================================
+
-
// Main function...
+
-
//
+
-
//-----------------------------------------------------------------------------
+
-
 
+
-
    std::string app_name;
+
-
    std::string app_path;
+
-
 
+
-
#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+
-
 
+
-
    //---------------------------------------------------------------------
+
-
    // Windows main signature
+
-
    //---------------------------------------------------------------------
+
-
 
+
-
    #define WIN32_LEAN_AND_MEAN
+
-
    #include "windows.h"
+
-
 
+
-
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
+
-
    {
+
-
        app_name.resize( _MAX_PATH );
+
-
        GetModuleFileNameA( NULL, &app_name[0], _MAX_PATH );
+
-
 
+
-
        STARTUPINFO startupInfo;
+
-
        GetStartupInfo( &startupInfo );
+
-
 
+
-
 
+
-
#else
+
-
 
+
-
    //---------------------------------------------------------------------
+
-
    // POSIX main signature
+
-
    //---------------------------------------------------------------------
+
-
 
+
-
    int main(int argc, char **argv)
+
-
    {
+
-
        app_name = argv[0];
+
-
 
+
-
#endif
+
-
 
+
-
 
+
-
//        utils::tokeniser<char> t( app_name, "//" );
+
-
//        app_path = t.collate( 0, t.size()-3, "/" );
+
-
 
+
-
    //---------------------------------------------------------------------
+
-
    // Common main body
+
-
    //---------------------------------------------------------------------
+
-
 
+
-
        // The entire game is initialised, started and run in the FCom()
+
-
        // function.
+
-
        //
+
-
        try
+
-
        {
+
-
            Wartbed::getInstance( "QuickGUI Test" ).setFrameListener( new FrameListener );
+
-
            Wartbed::getInstance().setKeyListener( new KeyListener );
+
-
            Wartbed::getInstance().setMouseListener( new MouseListener );
+
-
 
+
-
            // Must be done before OGRE's initialiseAllResourceGroups()
+
-
            //
+
-
            QuickGUI::registerScriptReader();
+
-
 
+
-
            // QuickGUI needs at least one font to start, or it will throw
+
-
            // an exception. Also, we need to add a folder containing
+
-
            // QuickGUI .skinTypes (etc) files.
+
-
            //
+
-
            Ogre::ResourceGroupManager::getSingleton().addResourceLocation( "./Fonts", "FileSystem" );
+
-
            Ogre::ResourceGroupManager::getSingleton().addResourceLocation( "./QuickGUI", "FileSystem" );
+
-
            Ogre::ResourceGroupManager::getSingleton().addResourceLocation( "./QuickGUI/qgui.textures.zip", "Zip" );
+
-
 
+
-
            // Instruct Ogre to go through all paths set by addResourceLocation
+
-
            // and add any comptible resources.
+
-
            //
+
-
            Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
+
-
 
+
-
            // Apparently, QuickGUI must be dynamically created. The normal way
+
-
            // of interaction is even through a "getSingletonPtr()" method...
+
-
            //
+
-
            utils::shared_ptr<QuickGUI::Root> pQGUIRoot( new QuickGUI::Root() );
+
-
 
+
-
            // These are the steps that must done to set up and prepare
+
-
            // QuickGUI for use:
+
-
            // * Load the types detected by Ogre's resource initialisation
+
-
            // * Creating a GUI manager object
+
-
            // * Creating a sheet
+
-
            // * Setting the active sheet
+
-
            //
+
-
            QuickGUI::SkinTypeManager::getSingleton().loadTypes();
+
-
            QuickGUI::GUIManagerDesc d;
+
-
            d.sceneManager = wb::ogre::pSceneManager;
+
-
            d.viewport = wb::ogre::pViewport;
+
-
            //d.queueID = Ogre::RENDER_QUEUE_OVERLAY;
+
-
            g_pGUIManager = pQGUIRoot->createGUIManager( d );
+
-
            g_pSheet = QuickGUI::SheetManager::getSingleton().createSheet( QuickGUI::Size(800,600) );
+
-
            g_pGUIManager->setActiveSheet( g_pSheet );
+
-
 
+
-
            // Creating widgets:
+
-
            //
+
-
//            QuickGUI::Sheet* defaultSheet = mGUIManager->getActiveSheet();
+
-
//            QuickGUI::FactoryManager::getSingleton().getDescFactory();
+
-
//            QuickGUI::FactoryManager::getSingleton().getWidgetFactory();
+
-
//            QuickGUI::FactoryManager::getSingleton().getDescFactory()->getInstance("MyButtonDescObject");
+
-
            QuickGUI::ButtonDesc* bd =
+
-
                dynamic_cast<QuickGUI::ButtonDesc*>(
+
-
                    QuickGUI::FactoryManager::getSingleton().
+
-
                        getDescFactory()->
+
-
                            getInstance<QuickGUI::ButtonDesc>("DefaultButtonDesc"));
+
-
 
+
-
            bd->widget_name = "MyButton";
+
-
            bd->textDesc.segments.push_back( QuickGUI::TextSegment("micross.12",Ogre::ColourValue::Red,"Click Me!") );
+
-
            bd->widget_dimensions.size = QuickGUI::Size(100,25);
+
-
            bd->widget_dimensions.position = QuickGUI::Point(50,50);
+
-
            g_pButton = g_pSheet->createButton(bd);
+
-
 
+
-
 
+
-
            // Registering events with a widget. Since the event handlers
+
-
            // use a pointer-to-member-function signature we need to wrap
+
-
            // them in classes, which however could be useful...
+
-
            //
+
-
            GUIEventHandler handler;
+
-
 
+
-
   
+
-
            Wartbed::getInstance().mainLoop();
+
-
        }
+
-
 
+
-
 
+
-
    //---------------------------------------------------------------------
+
-
    // Last-ditch exception handling
+
-
    //---------------------------------------------------------------------
+
-
 
+
-
        catch (Ogre::Exception &e)
+
-
        {
+
-
        #if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+
-
            MessageBoxA( NULL, e.what(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL );
+
-
        #else
+
-
            stderr << "An exception has occurred: " << e.what() << std::endl;
+
-
        #endif
+
-
        }
+
-
 
+
-
 
+
-
        catch (std::exception &e)
+
-
        {
+
-
        #if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+
-
            MessageBoxA( NULL, e.what(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL );
+
-
        #else
+
-
            stderr << "An exception has occurred: " << e.what() << std::endl;
+
-
        #endif
+
-
        }
+
-
 
+
-
 
+
-
        catch (...)
+
-
        {
+
-
        #if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
+
-
            MessageBoxA( NULL, "Unknows exception thrown!", "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL );
+
-
        #else
+
-
            stderr << "An exception has occurred: " << e.what() << std::endl;
+
-
        #endif
+
-
        }
+
-
 
+
-
 
+
-
        return EXIT_SUCCESS;
+
-
    }
+
-
 
+
-
//-----------------------------------------------------------------------------
+
-
//
+
-
// ...end main function
+
-
//=============================================================================
+
-
</pre>
+
===MyGUI===
===MyGUI===

Revision as of 15:59, 12 March 2009

This page contains temporary information. It does not reflect current or future WARTBED state

Contents

Currently evaluated GUI frameworks

GUI systems are relatively complex beasts (which I know having designed a few!) and are good candidates for 3rd party libraries. Requirements are

  • Sufficiently feature-complete (no half-complete or starting frameworks)
  • Stable
  • Maintained
  • OGRE-integrated

Note that the screenshots below are not necessarily representative of the appearance of the frameworks since they all support skinning.

CEGUI

http://www.cegui.org.uk/wiki/index.php/Main_Page
4.jpg
CEGUI is the default GUI framework under OGRE. I had considerable problems getting it to work, though it was reasonably simple once everything was described (a situation of files all over the place without a meaningfuil structure in OGRE - would need some cleaning up). Also, the available support and guides are scarce. It is also rather clumsy to initialise, if perhaps not to work with.

  • It has bindings for Irrlicht and OpenSceneGraph so it might be considered a relatively inter-API-portable framework.
  • CEGUI is very oriented toward defining widgets in XML files. Changing widgets programmatically is done by setting their properties through a messaging system. This message system is clunky and poorly documented.
  • The CEGUI documentation (both Wiki and source-generated API documentation) is insufficient, terse and often unhelpful.
  • CEGUI is by far the most powerful GUI library with the most supported widgets.

QuickGUI

http://www.ogre3d.org/wiki/index.php/QuickGUI
qgui_9_3.jpg
Made for OGRE, inspired by BetGUI and CEGUI.

  • QuickGUI has somewhat overly complicated initial set-up syntax requirements.
  • QuickGUI is quite easy to work with and neither terse not verbose
  • Widgets are widgets and communicated with through methods, not messages. This is object-oriented but also may entail plenty of casting depending on coding style.
  • The widgets are more limited in automagic functionality than CEGUI (f.i. no 4-state button widget) but are easy to work with programatically on events.
  • QuickGUI seems not to support ImageSet-like bitmap abstractions, wherefore all icons must be in unique files?
  • There are quirks: events must be methods in a class rather than free functions. The even handler class must be polymorphic (at least one virtual method) dur to internal dynamic_casts under the QuickGUI hood. QuickGUI seems less mature and robustly written than CEGUI.

MyGUI

http://www.ohloh.net/p/my-gui
1702687_1024x768.png
Last updated in June 2008. MyGUI is a sleek and sufficiently feature-complete framework that is well prepared for integration into OGRE. However, it myst be compiled from source (which is a one-time occurrence, though) and depends in turn on FreeType2, which also must be compiled. This meant initial only hassle, but since the current version seems to be written to a pre-Shoggoth OGRE version I've yet to get it to compile (some invalid signatures and a bunch of unresolved externals).

OpenGUI

http://opengui.rightbracket.com/
Screenshots
OpenGUI seems like a nice GUI library. However, it seems not to be updated anymore (last official optade was in 2007), which might mean severe integration issues with OGRE.

GUIs to be checked and perhaps evalutated

  • BetaGUI
  • Navi - uses the Gecko engine to render HTML and XML into OGRE. Very powerful (supports JavaScript and AJAX, but might be slow and very, very overkill. Also not necessarily easier to design game interfaces in HTML)

Conclusions

CEGUI seems the most well-designed framework. In initial configuration and event bindings QuickGUI feels somewhat messier, and this can be suspected to permeate the entire framework. The function-identical CEGUI code is actually shorter than QuickGUI's (except that it only reacts to the left mouse button). CEGUI binds events to functions rather than methods, which is greatly to its advantage as if simplifies syntax without in practice losing flexibility. QuickGUI's widgets are all dragabble by default. If this is an advantage or not I haven't decided yet.

Personal tools
communication