2003-11-03 17:22:45 +01:00
/*
CGUI
by Gustav Larsson
gee @ pyro . nu
*/
2004-06-03 20:38:14 +02:00
# include "precompiled.h"
2004-06-15 23:08:05 +02:00
2004-09-19 13:38:54 +02:00
# include <string>
2005-06-28 06:06:25 +02:00
2004-09-19 13:38:54 +02:00
# include <stdarg.h>
2005-08-12 19:06:53 +02:00
# include "lib/res/graphics/unifont.h"
2004-09-19 13:38:54 +02:00
2003-11-03 17:22:45 +01:00
# include "GUI.h"
2004-05-29 06:06:50 +02:00
// Types - when including them into the engine.
# include "CButton.h"
2004-09-02 05:02:32 +02:00
# include "CImage.h"
2004-05-29 06:06:50 +02:00
# include "CText.h"
# include "CCheckBox.h"
# include "CRadioButton.h"
2004-10-14 12:09:26 +02:00
# include "CInput.h"
2005-04-07 11:13:10 +02:00
# include "CList.h"
2005-04-24 01:20:50 +02:00
# include "CDropDown.h"
2004-10-14 04:32:26 +02:00
# include "CProgressBar.h"
2004-12-21 14:37:24 +01:00
# include "CTooltip.h"
2004-10-08 03:10:14 +02:00
# include "MiniMap.h"
2004-05-29 06:06:50 +02:00
2005-08-15 01:50:37 +02:00
# include "ps/XML/Xeromyces.h"
2004-08-28 00:08:30 +02:00
# include "ps/Font.h"
2003-11-24 03:18:41 +01:00
2004-12-05 22:56:09 +01:00
# include "Pyrogenesis.h"
2003-11-24 03:18:41 +01:00
# include "input.h"
2004-05-29 06:06:50 +02:00
# include "OverlayText.h"
// TODO Gee: Whatever include CRect/CPos/CSize
# include "Overlay.h"
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
# include "scripting/ScriptingHost.h"
2004-07-22 18:18:12 +02:00
# include "Hotkey.h"
2004-07-08 17:23:47 +02:00
2003-11-03 17:22:45 +01:00
// namespaces used
using namespace std ;
2004-07-08 17:23:47 +02:00
# include "ps/CLogger.h"
2004-08-15 22:57:31 +02:00
# define LOG_CATEGORY "gui"
2004-07-08 17:23:47 +02:00
// Class for global JavaScript object
JSClass GUIClass = {
" GUIClass " , 0 ,
JS_PropertyStub , JS_PropertyStub , JS_PropertyStub , JS_PropertyStub ,
JS_EnumerateStub , JS_ResolveStub , JS_ConvertStub , JS_FinalizeStub ,
} ;
2004-10-14 12:09:26 +02:00
// Globals used.
2004-06-03 03:43:33 +02:00
extern int g_xres , g_yres ;
2004-10-14 12:09:26 +02:00
extern bool keys [ SDLK_LAST ] ;
2003-11-03 17:22:45 +01:00
2003-11-22 16:07:22 +01:00
//-------------------------------------------------------------------
// called from main loop when (input) events are received.
// event is passed to other handlers if false is returned.
// trampoline: we don't want to make the implementation (in CGUI) static
//-------------------------------------------------------------------
2004-06-24 16:06:24 +02:00
int gui_handler ( const SDL_Event * ev )
2003-11-05 00:41:42 +01:00
{
2003-11-05 23:34:38 +01:00
return g_GUI . HandleEvent ( ev ) ;
2003-11-05 00:41:42 +01:00
}
2004-06-24 16:06:24 +02:00
int CGUI : : HandleEvent ( const SDL_Event * ev )
2003-11-03 17:22:45 +01:00
{
2004-10-14 12:09:26 +02:00
int ret = EV_PASS ;
2004-10-31 21:29:09 +01:00
if ( ev - > type = = SDL_GUIHOTKEYPRESS )
2004-07-22 18:18:12 +02:00
{
2004-10-31 21:29:09 +01:00
const CStr & objectName = * ( CStr * ) ev - > user . code ;
IGUIObject * object = FindObjectByName ( objectName ) ;
if ( ! object )
{
LOG ( ERROR , LOG_CATEGORY , " Cannot find hotkeyed object '%s' " , objectName . c_str ( ) ) ;
}
else
{
object - > HandleMessage ( SGUIMessage ( GUIM_PRESSED ) ) ;
object - > ScriptEvent ( " press " ) ;
}
2004-07-22 18:18:12 +02:00
}
2004-10-31 21:29:09 +01:00
else if ( ev - > type = = SDL_MOUSEMOTION )
2003-12-27 07:26:03 +01:00
{
2004-09-03 07:48:47 +02:00
// Yes the mouse position is stored as float to avoid
// constant conversations when operating in a
// float-based environment.
m_MousePos = CPos ( ( float ) ev - > motion . x , ( float ) ev - > motion . y ) ;
2003-11-03 17:22:45 +01:00
2003-12-27 07:26:03 +01:00
GUI < SGUIMessage > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST , m_BaseObject ,
& IGUIObject : : HandleMessage ,
SGUIMessage ( GUIM_MOUSE_MOTION ) ) ;
}
2004-07-08 17:23:47 +02:00
// Update m_MouseButtons. (BUTTONUP is handled later.)
2004-10-31 21:29:09 +01:00
else if ( ev - > type = = SDL_MOUSEBUTTONDOWN )
2003-12-27 07:26:03 +01:00
{
2004-07-08 17:23:47 +02:00
// (0,1,2) = (LMB,RMB,MMB)
if ( ev - > button . button < 3 )
m_MouseButtons | = ( 1 < < ev - > button . button ) ;
2003-12-27 07:26:03 +01:00
}
2003-11-03 17:22:45 +01:00
// JW: (pre|post)process omitted; what're they for? why would we need any special button_released handling?
// Only one object can be hovered
2003-11-24 03:18:41 +01:00
IGUIObject * pNearest = NULL ;
2003-11-03 17:22:45 +01:00
2004-10-14 12:09:26 +02:00
// TODO Gee: (2004-09-08) Big TODO, don't do the below if the SDL_Event is something like a keypress!
2003-11-25 03:47:12 +01:00
try
2003-11-03 17:22:45 +01:00
{
2004-05-29 06:06:50 +02:00
// TODO Gee: Optimizations needed!
// these two recursive function are quite overhead heavy.
2003-11-25 03:47:12 +01:00
// pNearest will after this point at the hovered object, possibly NULL
2003-12-27 07:26:03 +01:00
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST , m_BaseObject ,
2003-11-25 03:47:12 +01:00
& IGUIObject : : ChooseMouseOverAndClosest ,
pNearest ) ;
2004-07-11 18:22:35 +02:00
2005-07-24 00:27:55 +02:00
// Is placed in the UpdateMouseOver function
//if (ev->type == SDL_MOUSEMOTION && pNearest)
// pNearest->ScriptEvent("mousemove");
2004-07-11 18:22:35 +02:00
2003-11-25 03:47:12 +01:00
// Now we'll call UpdateMouseOver on *all* objects,
// we'll input the one hovered, and they will each
// update their own data and send messages accordingly
2004-07-22 18:18:12 +02:00
2003-12-27 07:26:03 +01:00
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST , m_BaseObject ,
2003-11-25 03:47:12 +01:00
& IGUIObject : : UpdateMouseOver ,
pNearest ) ;
2004-06-24 16:06:24 +02:00
if ( ev - > type = = SDL_MOUSEBUTTONDOWN )
2003-11-25 03:47:12 +01:00
{
2004-06-24 16:06:24 +02:00
switch ( ev - > button . button )
2003-11-25 03:47:12 +01:00
{
2004-05-29 06:06:50 +02:00
case SDL_BUTTON_LEFT :
if ( pNearest )
2003-12-27 07:26:03 +01:00
{
2004-10-14 12:09:26 +02:00
if ( pNearest ! = m_FocusedObject )
{
// Update focused object
if ( m_FocusedObject )
m_FocusedObject - > HandleMessage ( SGUIMessage ( GUIM_LOST_FOCUS ) ) ;
m_FocusedObject = pNearest ;
m_FocusedObject - > HandleMessage ( SGUIMessage ( GUIM_GOT_FOCUS ) ) ;
}
2004-05-29 06:06:50 +02:00
pNearest - > HandleMessage ( SGUIMessage ( GUIM_MOUSE_PRESS_LEFT ) ) ;
2004-07-11 18:22:35 +02:00
pNearest - > ScriptEvent ( " mouseleftpress " ) ;
2004-10-14 12:09:26 +02:00
// Block event, so things on the map (behind the GUI) won't be pressed
2004-10-17 12:55:57 +02:00
ret = EV_HANDLED ;
2004-05-29 06:06:50 +02:00
}
2005-04-24 01:20:50 +02:00
else if ( m_FocusedObject )
{
m_FocusedObject - > HandleMessage ( SGUIMessage ( GUIM_LOST_FOCUS ) ) ;
//if (m_FocusedObject-> TODO SelfishFocus?
m_FocusedObject = 0 ;
}
2004-07-11 18:22:35 +02:00
break ;
2004-05-29 06:06:50 +02:00
2005-07-24 00:27:55 +02:00
// TODO Gee (!!!): This is weird, I've tested this, and mousewheelup is
// what I would call mousewheeldown!
2004-06-02 17:22:19 +02:00
case SDL_BUTTON_WHEELDOWN : // wheel down
2004-05-29 06:06:50 +02:00
if ( pNearest )
{
pNearest - > HandleMessage ( SGUIMessage ( GUIM_MOUSE_WHEEL_DOWN ) ) ;
2004-07-11 18:22:35 +02:00
pNearest - > ScriptEvent ( " mousewheeldown " ) ;
2004-10-17 12:55:57 +02:00
ret = EV_HANDLED ;
2003-12-27 07:26:03 +01:00
}
2004-05-29 06:06:50 +02:00
break ;
2004-06-02 17:22:19 +02:00
case SDL_BUTTON_WHEELUP : // wheel up
2004-05-29 06:06:50 +02:00
if ( pNearest )
2003-12-27 07:26:03 +01:00
{
2004-05-29 06:06:50 +02:00
pNearest - > HandleMessage ( SGUIMessage ( GUIM_MOUSE_WHEEL_UP ) ) ;
2005-07-24 00:27:55 +02:00
pNearest - > ScriptEvent ( " mousewheelup " ) ;
2004-10-17 12:55:57 +02:00
ret = EV_HANDLED ;
2003-12-27 07:26:03 +01:00
}
2004-05-29 06:06:50 +02:00
break ;
default :
break ;
}
}
else
2004-06-24 16:06:24 +02:00
if ( ev - > type = = SDL_MOUSEBUTTONUP )
2004-05-29 06:06:50 +02:00
{
2004-12-21 14:37:24 +01:00
switch ( ev - > button . button )
2004-05-29 06:06:50 +02:00
{
2004-12-21 14:37:24 +01:00
case SDL_BUTTON_LEFT :
2003-12-27 07:26:03 +01:00
if ( pNearest )
2004-07-11 18:22:35 +02:00
{
2004-05-29 06:06:50 +02:00
pNearest - > HandleMessage ( SGUIMessage ( GUIM_MOUSE_RELEASE_LEFT ) ) ;
2004-07-11 18:22:35 +02:00
pNearest - > ScriptEvent ( " mouseleftrelease " ) ;
2004-10-14 12:09:26 +02:00
ret = EV_HANDLED ;
2004-07-11 18:22:35 +02:00
}
2004-12-21 14:37:24 +01:00
break ;
2003-12-27 07:26:03 +01:00
}
2004-05-29 06:06:50 +02:00
// Reset all states on all visible objects
GUI < > : : RecurseObject ( GUIRR_HIDDEN , m_BaseObject ,
& IGUIObject : : ResetStates ) ;
// It will have reset the mouse over of the current hovered, so we'll
// have to restore that
if ( pNearest )
pNearest - > m_MouseHovering = true ;
2003-11-25 03:47:12 +01:00
}
}
catch ( PS_RESULT e )
{
2005-08-09 18:02:15 +02:00
UNUSED2 ( e ) ;
2004-08-10 18:04:21 +02:00
debug_warn ( " CGUI::HandleEvent error " ) ;
2003-12-27 07:26:03 +01:00
// TODO Gee: Handle
2003-11-25 03:47:12 +01:00
}
2003-11-03 17:22:45 +01:00
// JW: what's the difference between mPress and mDown? what's the code below responsible for?
2004-06-11 04:14:18 +02:00
/*
// Generally if just mouse is clicked
2003-11-03 17:22:45 +01:00
if ( m_pInput - > mDown ( NEMM_BUTTON1 ) & & pNearest )
{
pNearest - > HandleMessage ( GUIM_MOUSE_DOWN_LEFT ) ;
}
*/
2004-07-08 17:23:47 +02:00
// BUTTONUP's effect on m_MouseButtons is handled after
// everything else, so that e.g. 'press' handlers (activated
// on button up) see which mouse button had been pressed.
if ( ev - > type = = SDL_MOUSEBUTTONUP )
{
// (0,1,2) = (LMB,RMB,MMB)
if ( ev - > button . button < 3 )
m_MouseButtons & = ~ ( 1 < < ev - > button . button ) ;
}
2004-10-14 12:09:26 +02:00
// Handle keys for input boxes
2005-01-22 19:46:03 +01:00
if ( GetFocusedObject ( ) )
2004-10-14 12:09:26 +02:00
{
2005-01-22 19:46:03 +01:00
if (
( ev - > type = = SDL_KEYDOWN & &
ev - > key . keysym . sym ! = SDLK_ESCAPE & &
! keys [ SDLK_LCTRL ] & & ! keys [ SDLK_RCTRL ] & &
! keys [ SDLK_LALT ] & & ! keys [ SDLK_RALT ] )
| | ev - > type = = SDL_HOTKEYDOWN
)
2004-10-14 12:09:26 +02:00
{
ret = GetFocusedObject ( ) - > ManuallyHandleEvent ( ev ) ;
}
// else will return EV_PASS because we never used the button.
}
return ret ;
2003-11-03 17:22:45 +01:00
}
2004-07-24 21:09:12 +02:00
void CGUI : : TickObjects ( )
{
CStr action = " tick " ;
GUI < CStr > : : RecurseObject ( 0 , m_BaseObject ,
& IGUIObject : : ScriptEvent , action ) ;
2004-12-21 14:37:24 +01:00
// Also update tooltips:
// TODO: Efficiency
IGUIObject * pNearest = NULL ;
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST , m_BaseObject ,
& IGUIObject : : ChooseMouseOverAndClosest ,
pNearest ) ;
m_Tooltip . Update ( pNearest , m_MousePos , this ) ;
2004-07-24 21:09:12 +02:00
}
2005-01-01 18:30:55 +01:00
void CGUI : : SendEventToAll ( CStr EventName )
{
GUI < CStr > : : RecurseObject ( 0 , m_BaseObject ,
& IGUIObject : : ScriptEvent , EventName ) ;
}
2003-11-03 17:22:45 +01:00
//-------------------------------------------------------------------
// Constructor / Destructor
//-------------------------------------------------------------------
2004-10-14 12:09:26 +02:00
CGUI : : CGUI ( ) : m_InternalNameNumber ( 0 ) , m_MouseButtons ( 0 ) , m_FocusedObject ( NULL )
2003-11-03 17:22:45 +01:00
{
2003-11-06 12:54:46 +01:00
m_BaseObject = new CGUIDummyObject ;
2003-11-03 17:22:45 +01:00
m_BaseObject - > SetGUI ( this ) ;
2004-07-08 17:23:47 +02:00
// Construct the parent object for all GUI JavaScript things
2004-09-04 16:40:06 +02:00
m_ScriptObject = JS_NewObject ( g_ScriptingHost . getContext ( ) , & GUIClass , NULL , NULL ) ;
2005-06-28 06:06:25 +02:00
debug_assert ( m_ScriptObject ! = NULL ) ; // How should it handle errors?
2004-07-08 17:23:47 +02:00
JS_AddRoot ( g_ScriptingHost . getContext ( ) , & m_ScriptObject ) ;
2003-11-03 17:22:45 +01:00
// This will make this invisible, not add
//m_BaseObject->SetName(BASE_OBJECT_NAME);
}
CGUI : : ~ CGUI ( )
{
if ( m_BaseObject )
delete m_BaseObject ;
2004-07-08 17:23:47 +02:00
if ( m_ScriptObject )
// Let it be garbage-collected
JS_RemoveRoot ( g_ScriptingHost . getContext ( ) , & m_ScriptObject ) ;
2003-11-03 17:22:45 +01:00
}
2003-11-22 16:07:22 +01:00
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
2004-06-18 16:07:06 +02:00
IGUIObject * CGUI : : ConstructObject ( const CStr & str )
2003-11-03 17:22:45 +01:00
{
if ( m_ObjectTypes . count ( str ) > 0 )
return ( * m_ObjectTypes [ str ] ) ( ) ;
else
2003-11-24 03:18:41 +01:00
{
2004-09-02 05:02:32 +02:00
// Error reporting will be handled with the NULL return.
2003-11-03 17:22:45 +01:00
return NULL ;
2003-11-24 03:18:41 +01:00
}
2003-11-03 17:22:45 +01:00
}
2003-11-24 03:18:41 +01:00
void CGUI : : Initialize ( )
2003-11-03 17:22:45 +01:00
{
// Add base types!
2003-11-24 03:18:41 +01:00
// You can also add types outside the GUI to extend the flexibility of the GUI.
2004-12-05 22:56:09 +01:00
// Pyrogenesis though will have all the object types inserted from here.
2004-05-29 06:06:50 +02:00
AddObjectType ( " empty " , & CGUIDummyObject : : ConstructObject ) ;
AddObjectType ( " button " , & CButton : : ConstructObject ) ;
2004-09-02 05:02:32 +02:00
AddObjectType ( " image " , & CImage : : ConstructObject ) ;
2004-05-29 06:06:50 +02:00
AddObjectType ( " text " , & CText : : ConstructObject ) ;
AddObjectType ( " checkbox " , & CCheckBox : : ConstructObject ) ;
AddObjectType ( " radiobutton " , & CRadioButton : : ConstructObject ) ;
2004-10-14 04:32:26 +02:00
AddObjectType ( " progressbar " , & CProgressBar : : ConstructObject ) ;
2004-10-08 03:10:14 +02:00
AddObjectType ( " minimap " , & CMiniMap : : ConstructObject ) ;
2004-10-14 12:09:26 +02:00
AddObjectType ( " input " , & CInput : : ConstructObject ) ;
2005-07-20 07:27:32 +02:00
// The following line was commented out, I don't know if that's me or not, or
// for what reason, but I'm gonna uncomment, if anything breaks, just let me
// know, or if it wasn't I that commented it out, do let me know why.
// -- Gee 20-07-2005
AddObjectType ( " list " , & CList : : ConstructObject ) ;
//
2005-04-24 01:20:50 +02:00
AddObjectType ( " dropdown " , & CDropDown : : ConstructObject ) ;
2003-11-03 17:22:45 +01:00
}
void CGUI : : Process ( )
{
2004-06-11 04:14:18 +02:00
/*
2003-11-03 17:22:45 +01:00
2003-12-27 07:26:03 +01:00
// TODO Gee: check if m_pInput is valid, otherwise return
2005-06-28 06:06:25 +02:00
/// debug_assert(m_pInput);
2003-11-03 17:22:45 +01:00
// Pre-process all objects
try
{
2003-11-24 03:18:41 +01:00
GUI < EGUIMessage > : : RecurseObject ( 0 , m_BaseObject , & IGUIObject : : HandleMessage , GUIM_PREPROCESS ) ;
2003-11-03 17:22:45 +01:00
}
catch ( PS_RESULT e )
{
return ;
}
// Check mouse over
try
{
// Only one object can be hovered
// check which one it is, if any !
2003-11-24 03:18:41 +01:00
IGUIObject * pNearest = NULL ;
2003-11-03 17:22:45 +01:00
2003-11-24 03:18:41 +01:00
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN , m_BaseObject , & IGUIObject : : ChooseMouseOverAndClosest , pNearest ) ;
2003-11-03 17:22:45 +01:00
// Now we'll call UpdateMouseOver on *all* objects,
// we'll input the one hovered, and they will each
// update their own data and send messages accordingly
2003-11-24 03:18:41 +01:00
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN , m_BaseObject , & IGUIObject : : UpdateMouseOver , pNearest ) ;
2003-11-03 17:22:45 +01:00
// If pressed
if ( m_pInput - > mPress ( NEMM_BUTTON1 ) & & pNearest )
{
pNearest - > HandleMessage ( GUIM_MOUSE_PRESS_LEFT ) ;
}
else
// If released
if ( m_pInput - > mRelease ( NEMM_BUTTON1 ) & & pNearest )
{
pNearest - > HandleMessage ( GUIM_MOUSE_RELEASE_LEFT ) ;
}
// Generally if just mouse is clicked
if ( m_pInput - > mDown ( NEMM_BUTTON1 ) & & pNearest )
{
pNearest - > HandleMessage ( GUIM_MOUSE_DOWN_LEFT ) ;
}
}
catch ( PS_RESULT e )
{
return ;
}
// Post-process all objects
try
{
2003-11-24 03:18:41 +01:00
GUI < EGUIMessage > : : RecurseObject ( 0 , m_BaseObject , & IGUIObject : : HandleMessage , GUIM_POSTPROCESS ) ;
2003-11-03 17:22:45 +01:00
}
catch ( PS_RESULT e )
{
return ;
}
*/
}
void CGUI : : Draw ( )
{
2004-07-08 17:23:47 +02:00
// Clear the depth buffer, so the GUI is
// drawn on top of everything else
glClear ( GL_DEPTH_BUFFER_BIT ) ;
2003-11-24 03:18:41 +01:00
glPushMatrix ( ) ;
2005-02-05 08:25:16 +01:00
guiLoadIdentity ( ) ;
2003-11-24 03:18:41 +01:00
2003-11-03 17:22:45 +01:00
try
{
2003-11-24 03:18:41 +01:00
// Recurse IGUIObject::Draw() with restriction: hidden
// meaning all hidden objects won't call Draw (nor will it recurse its children)
GUI < > : : RecurseObject ( GUIRR_HIDDEN , m_BaseObject , & IGUIObject : : Draw ) ;
2003-11-03 17:22:45 +01:00
}
catch ( PS_RESULT e )
{
2005-08-09 18:02:15 +02:00
UNUSED2 ( e ) ;
2003-11-24 03:18:41 +01:00
glPopMatrix ( ) ;
2003-12-27 07:26:03 +01:00
// TODO Gee: Report error.
2004-08-10 18:04:21 +02:00
debug_warn ( " CGUI::Draw error " ) ;
2003-11-03 17:22:45 +01:00
return ;
}
2003-11-24 03:18:41 +01:00
glPopMatrix ( ) ;
2003-11-03 17:22:45 +01:00
}
2004-12-15 22:24:46 +01:00
void CGUI : : DrawSprite ( CGUISpriteInstance & Sprite ,
2004-12-18 14:32:00 +01:00
int CellID ,
2005-08-09 18:02:15 +02:00
const float & Z ,
const CRect & Rect ,
const CRect & UNUSED ( Clipping ) )
2003-12-01 08:06:55 +01:00
{
2004-12-15 22:24:46 +01:00
// If the sprite doesn't exist (name == ""), don't bother drawing anything
if ( Sprite . IsEmpty ( ) )
2003-12-01 08:06:55 +01:00
return ;
2004-07-24 16:04:40 +02:00
// TODO: Clipping?
2003-12-01 08:06:55 +01:00
glPushMatrix ( ) ;
2004-07-14 00:48:53 +02:00
glTranslatef ( 0.0f , 0.0f , Z ) ;
2003-12-01 08:06:55 +01:00
2004-12-18 14:32:00 +01:00
Sprite . Draw ( Rect , CellID , m_Sprites ) ;
2004-09-02 05:02:32 +02:00
2003-12-01 08:06:55 +01:00
glPopMatrix ( ) ;
2004-12-15 22:24:46 +01:00
2003-12-01 08:06:55 +01:00
}
2003-11-03 17:22:45 +01:00
void CGUI : : Destroy ( )
{
// We can use the map to delete all
2003-11-22 16:07:22 +01:00
// now we don't want to cancel all if one Destroy fails
2003-11-03 17:22:45 +01:00
map_pObjects : : iterator it ;
for ( it = m_pAllObjects . begin ( ) ; it ! = m_pAllObjects . end ( ) ; + + it )
{
try
{
it - > second - > Destroy ( ) ;
}
catch ( PS_RESULT e )
{
2005-08-09 18:02:15 +02:00
UNUSED2 ( e ) ;
2004-08-10 18:04:21 +02:00
debug_warn ( " CGUI::Destroy error " ) ;
2003-12-27 07:26:03 +01:00
// TODO Gee: Handle
2003-11-03 17:22:45 +01:00
}
delete it - > second ;
}
2004-12-18 14:32:00 +01:00
for ( std : : map < CStr , CGUISprite > : : iterator it2 = m_Sprites . begin ( ) ; it2 ! = m_Sprites . end ( ) ; + + it2 )
for ( std : : vector < SGUIImage > : : iterator it3 = it2 - > second . m_Images . begin ( ) ; it3 ! = it2 - > second . m_Images . end ( ) ; + + it3 )
delete it3 - > m_Effects ;
2003-11-03 17:22:45 +01:00
// Clear all
m_pAllObjects . clear ( ) ;
m_Sprites . clear ( ) ;
2004-08-31 04:09:58 +02:00
m_Icons . clear ( ) ;
2003-11-03 17:22:45 +01:00
}
2003-11-24 18:13:37 +01:00
void CGUI : : UpdateResolution ( )
{
2003-11-25 03:47:12 +01:00
// Update ALL cached
2003-11-24 18:13:37 +01:00
GUI < > : : RecurseObject ( 0 , m_BaseObject , & IGUIObject : : UpdateCachedSize ) ;
}
2003-11-24 03:18:41 +01:00
void CGUI : : AddObject ( IGUIObject * pObject )
2003-11-03 17:22:45 +01:00
{
2003-12-01 08:06:55 +01:00
try
{
2003-11-03 17:22:45 +01:00
// Add CGUI pointer
2003-11-24 03:18:41 +01:00
GUI < CGUI * > : : RecurseObject ( 0 , pObject , & IGUIObject : : SetGUI , this ) ;
2003-11-03 17:22:45 +01:00
// Add child to base object
2004-12-13 13:07:12 +01:00
m_BaseObject - > AddChild ( pObject ) ; // can throw
2003-11-25 03:47:12 +01:00
// Cache tree
GUI < > : : RecurseObject ( 0 , pObject , & IGUIObject : : UpdateCachedSize ) ;
2004-05-29 06:06:50 +02:00
// Loaded
GUI < SGUIMessage > : : RecurseObject ( 0 , pObject , & IGUIObject : : HandleMessage , SGUIMessage ( GUIM_LOAD ) ) ;
2003-12-01 08:06:55 +01:00
}
2003-11-03 17:22:45 +01:00
catch ( PS_RESULT e )
{
throw e ;
2003-12-01 08:06:55 +01:00
}
2003-11-03 17:22:45 +01:00
}
void CGUI : : UpdateObjects ( )
{
// We'll fill a temporary map until we know everything
// succeeded
map_pObjects AllObjects ;
try
{
// Fill freshly
2003-11-24 03:18:41 +01:00
GUI < map_pObjects > : : RecurseObject ( 0 , m_BaseObject , & IGUIObject : : AddToPointersMap , AllObjects ) ;
2003-11-03 17:22:45 +01:00
}
catch ( PS_RESULT e )
{
// Throw the same error
throw e ;
}
// Else actually update the real one
2005-01-13 01:17:31 +01:00
m_pAllObjects . swap ( AllObjects ) ;
2003-11-03 17:22:45 +01:00
}
2004-06-18 16:07:06 +02:00
bool CGUI : : ObjectExists ( const CStr & Name ) const
2003-11-03 17:22:45 +01:00
{
2004-05-29 13:59:59 +02:00
return m_pAllObjects . count ( Name ) ! = 0 ;
2004-05-29 06:06:50 +02:00
}
2004-07-08 17:23:47 +02:00
IGUIObject * CGUI : : FindObjectByName ( const CStr & Name ) const
{
map_pObjects : : const_iterator it = m_pAllObjects . find ( Name ) ;
if ( it = = m_pAllObjects . end ( ) )
return NULL ;
else
return it - > second ;
}
2004-05-29 06:06:50 +02:00
// private struct used only in GenerateText(...)
2004-05-29 13:59:59 +02:00
struct SGenerateTextImage
2004-05-29 06:06:50 +02:00
{
2004-12-18 14:32:00 +01:00
float m_YFrom , // The image's starting location in Y
m_YTo , // The image's end location in Y
2004-09-03 07:48:47 +02:00
m_Indentation ; // The image width in other words
2004-05-29 06:06:50 +02:00
// Some help functions
// TODO Gee: CRect => CPoint ?
2004-12-18 14:32:00 +01:00
void SetupSpriteCall ( const bool Left , SGUIText : : SSpriteCall & SpriteCall ,
const float width , const float y ,
const CSize & Size , const CStr & TextureName ,
const float BufferZone , const int CellID )
2004-05-29 06:06:50 +02:00
{
// TODO Gee: Temp hardcoded values
SpriteCall . m_Area . top = y + BufferZone ;
SpriteCall . m_Area . bottom = y + BufferZone + Size . cy ;
if ( Left )
{
SpriteCall . m_Area . left = BufferZone ;
SpriteCall . m_Area . right = Size . cx + BufferZone ;
}
else
{
SpriteCall . m_Area . left = width - BufferZone - Size . cx ;
SpriteCall . m_Area . right = width - BufferZone ;
}
2004-12-18 14:32:00 +01:00
SpriteCall . m_CellID = CellID ;
2004-12-15 22:24:46 +01:00
SpriteCall . m_Sprite = TextureName ;
2004-05-29 06:06:50 +02:00
m_YFrom = SpriteCall . m_Area . top - BufferZone ;
m_YTo = SpriteCall . m_Area . bottom + BufferZone ;
m_Indentation = Size . cx + BufferZone * 2 ;
}
} ;
2004-08-31 04:09:58 +02:00
SGUIText CGUI : : GenerateText ( const CGUIString & string ,
2004-09-03 07:48:47 +02:00
const CStr & Font , const float & Width , const float & BufferZone ,
2004-08-31 04:09:58 +02:00
const IGUIObject * pObject )
2004-05-29 06:06:50 +02:00
{
SGUIText Text ; // object we're generating
if ( string . m_Words . size ( ) = = 0 )
return Text ;
2004-09-03 07:48:47 +02:00
float x = BufferZone , y = BufferZone ; // drawing pointer
2004-05-29 06:06:50 +02:00
int from = 0 ;
bool done = false ;
2004-09-04 22:35:12 +02:00
bool FirstLine = true ; // Necessary because text in the first line is shorter
// (it doesn't count the line spacing)
2004-05-29 06:06:50 +02:00
// Images on the left or the right side.
vector < SGenerateTextImage > Images [ 2 ] ;
int pos_last_img = - 1 ; // Position in the string where last img (either left or right) were encountered.
// in order to avoid duplicate processing.
// Easier to read.
bool WordWrapping = ( Width ! = 0 ) ;
// Go through string word by word
2004-05-29 13:59:59 +02:00
for ( int i = 0 ; i < ( int ) string . m_Words . size ( ) - 1 & & ! done ; + + i )
2004-05-29 06:06:50 +02:00
{
// Pre-process each line one time, so we know which floating images
// will be added for that line.
// Generated stuff is stored in Feedback.
CGUIString : : SFeedback Feedback ;
// Preliminary line_height, used for word-wrapping with floating images.
2004-09-03 07:48:47 +02:00
float prelim_line_height = 0.f ;
2004-05-29 06:06:50 +02:00
// Width and height of all text calls generated.
2004-08-31 04:09:58 +02:00
string . GenerateTextCall ( Feedback , Font ,
2004-09-04 22:35:12 +02:00
string . m_Words [ i ] , string . m_Words [ i + 1 ] ,
FirstLine ) ;
2004-05-29 06:06:50 +02:00
// Loop through our images queues, to see if images has been added.
// Check if this has already been processed.
// Also, floating images are only applicable if Word-Wrapping is on
if ( WordWrapping & & i > pos_last_img )
{
// Loop left/right
for ( int j = 0 ; j < 2 ; + + j )
{
for ( vector < CStr > : : const_iterator it = Feedback . m_Images [ j ] . begin ( ) ;
2004-08-31 04:09:58 +02:00
it ! = Feedback . m_Images [ j ] . end ( ) ;
2004-05-29 06:06:50 +02:00
+ + it )
{
SGUIText : : SSpriteCall SpriteCall ;
SGenerateTextImage Image ;
// Y is if no other floating images is above, y. Else it is placed
// after the last image, like a stack downwards.
2004-09-03 07:48:47 +02:00
float _y ;
2004-05-29 06:06:50 +02:00
if ( Images [ j ] . size ( ) > 0 )
2004-09-03 07:48:47 +02:00
_y = MAX ( y , Images [ j ] . back ( ) . m_YTo ) ;
2004-05-29 06:06:50 +02:00
else
_y = y ;
2004-08-31 04:09:58 +02:00
// Get Size from Icon database
SGUIIcon icon = GetIcon ( * it ) ;
CSize size = icon . m_Size ;
2005-07-25 02:52:03 +02:00
Image . SetupSpriteCall ( ( j = = CGUIString : : SFeedback : : Left ) , SpriteCall , Width , _y , size , icon . m_SpriteName , BufferZone , icon . m_CellID ) ;
2004-05-29 06:06:50 +02:00
// Check if image is the lowest thing.
2004-09-03 07:48:47 +02:00
Text . m_Size . cy = MAX ( Text . m_Size . cy , Image . m_YTo ) ;
2004-05-29 06:06:50 +02:00
Images [ j ] . push_back ( Image ) ;
Text . m_SpriteCalls . push_back ( SpriteCall ) ;
}
}
}
2004-09-03 07:48:47 +02:00
pos_last_img = MAX ( pos_last_img , i ) ;
2004-05-29 06:06:50 +02:00
x + = Feedback . m_Size . cx ;
2004-09-03 07:48:47 +02:00
prelim_line_height = MAX ( prelim_line_height , Feedback . m_Size . cy ) ;
2004-05-29 06:06:50 +02:00
// If Width is 0, then there's no word-wrapping, disable NewLine.
2004-07-24 16:04:40 +02:00
if ( ( WordWrapping & & ( x > Width - BufferZone | | Feedback . m_NewLine ) ) | | i = = ( int ) string . m_Words . size ( ) - 2 )
2004-05-29 06:06:50 +02:00
{
2004-08-31 04:09:58 +02:00
// Change 'from' to 'i', but first keep a copy of its value.
2004-05-29 06:06:50 +02:00
int temp_from = from ;
from = i ;
static const int From = 0 , To = 1 ;
//int width_from=0, width_to=width;
2004-09-03 07:48:47 +02:00
float width_range [ 2 ] ;
2004-05-29 06:06:50 +02:00
width_range [ From ] = BufferZone ;
width_range [ To ] = Width - BufferZone ;
2004-08-31 04:09:58 +02:00
// Floating images are only applicable if word-wrapping is enabled.
2004-05-29 06:06:50 +02:00
if ( WordWrapping )
{
// Decide width of the line. We need to iterate our floating images.
// this won't be exact because we're assuming the line_height
// will be as our preliminary calculation said. But that may change,
// although we'd have to add a couple of more loops to try straightening
2004-12-21 14:37:24 +01:00
// this problem out, and it is very unlikely to happen noticeably if one
// structures his text in a stylistically pure fashion. Even if not, it
2004-05-29 06:06:50 +02:00
// is still quite unlikely it will happen.
// Loop through left and right side, from and to.
for ( int j = 0 ; j < 2 ; + + j )
{
for ( vector < SGenerateTextImage > : : const_iterator it = Images [ j ] . begin ( ) ;
it ! = Images [ j ] . end ( ) ;
+ + it )
{
// We're working with two intervals here, the image's and the line height's.
// let's find the union of these two.
2004-09-03 07:48:47 +02:00
float union_from , union_to ;
2004-05-29 06:06:50 +02:00
2004-09-03 07:48:47 +02:00
union_from = MAX ( y , it - > m_YFrom ) ;
union_to = MIN ( y + prelim_line_height , it - > m_YTo ) ;
2004-05-29 06:06:50 +02:00
2004-07-31 15:37:35 +02:00
// The union is not empty
2004-05-29 06:06:50 +02:00
if ( union_to > union_from )
{
if ( j = = From )
2004-09-03 07:48:47 +02:00
width_range [ From ] = MAX ( width_range [ From ] , it - > m_Indentation ) ;
2004-05-29 06:06:50 +02:00
else
2004-09-03 07:48:47 +02:00
width_range [ To ] = MIN ( width_range [ To ] , Width - it - > m_Indentation ) ;
2004-05-29 06:06:50 +02:00
}
}
}
}
// Reset X for the next loop
x = width_range [ From ] ;
// Now we'll do another loop to figure out the height of
// the line (the height of the largest character). This
// couldn't be determined in the first loop (main loop)
// because it didn't regard images, so we don't know
// if all characters processed, will actually be involved
// in that line.
2004-09-03 07:48:47 +02:00
float line_height = 0.f ;
2004-05-29 06:06:50 +02:00
for ( int j = temp_from ; j < = i ; + + j )
{
// We don't want to use Feedback now, so we'll have to use
// another.
CGUIString : : SFeedback Feedback2 ;
2004-08-31 04:09:58 +02:00
// Don't attach object, it'll suppress the errors
// we want them to be reported in the final GenerateTextCall()
// so that we don't get duplicates.
string . GenerateTextCall ( Feedback2 , Font ,
2004-09-04 22:35:12 +02:00
string . m_Words [ j ] , string . m_Words [ j + 1 ] ,
FirstLine ) ;
2004-05-29 06:06:50 +02:00
// Append X value.
x + = Feedback2 . m_Size . cx ;
if ( WordWrapping & & x > width_range [ To ] & & j ! = temp_from & & ! Feedback2 . m_NewLine )
break ;
// Let line_height be the maximum m_Height we encounter.
2004-09-03 07:48:47 +02:00
line_height = MAX ( line_height , Feedback2 . m_Size . cy ) ;
2004-05-29 06:06:50 +02:00
if ( WordWrapping & & Feedback2 . m_NewLine )
break ;
}
// Reset x once more
x = width_range [ From ] ;
2004-07-14 00:48:53 +02:00
// Move down, because font drawing starts from the baseline
y + = line_height ;
2004-05-29 06:06:50 +02:00
// Do the real processing now
for ( int j = temp_from ; j < = i ; + + j )
{
// We don't want to use Feedback now, so we'll have to use
2004-08-31 04:09:58 +02:00
// another one.
2004-05-29 06:06:50 +02:00
CGUIString : : SFeedback Feedback2 ;
// Defaults
2004-08-31 04:09:58 +02:00
string . GenerateTextCall ( Feedback2 , Font ,
string . m_Words [ j ] , string . m_Words [ j + 1 ] ,
2004-09-04 22:35:12 +02:00
FirstLine , pObject ) ;
2004-05-29 06:06:50 +02:00
// Iterate all and set X/Y values
// Since X values are not set, we need to make an internal
// iteration with an increment that will append the internal
// x, that is what x_pointer is for.
2004-09-03 07:48:47 +02:00
float x_pointer = 0.f ;
2004-05-29 06:06:50 +02:00
vector < SGUIText : : STextCall > : : iterator it ;
for ( it = Feedback2 . m_TextCalls . begin ( ) ; it ! = Feedback2 . m_TextCalls . end ( ) ; + + it )
{
2004-07-31 15:37:35 +02:00
it - > m_Pos = CPos ( x + x_pointer , y ) ;
2004-05-29 06:06:50 +02:00
x_pointer + = it - > m_Size . cx ;
if ( it - > m_pSpriteCall )
{
2004-08-31 04:09:58 +02:00
it - > m_pSpriteCall - > m_Area + = it - > m_Pos - CSize ( 0 , it - > m_pSpriteCall - > m_Area . GetHeight ( ) ) ;
2004-05-29 06:06:50 +02:00
}
}
// Append X value.
x + = Feedback2 . m_Size . cx ;
2004-09-03 07:48:47 +02:00
Text . m_Size . cx = MAX ( Text . m_Size . cx , x + BufferZone ) ;
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
// The first word overrides the width limit, what we
// do, in those cases, are just drawing that word even
2004-05-29 06:06:50 +02:00
// though it'll extend the object.
if ( WordWrapping ) // only if word-wrapping is applicable
{
if ( Feedback2 . m_NewLine )
{
from = j + 1 ;
2004-08-31 04:09:58 +02:00
// Sprite call can exist within only a newline segment,
// therefore we need this.
Text . m_SpriteCalls . insert ( Text . m_SpriteCalls . end ( ) , Feedback2 . m_SpriteCalls . begin ( ) , Feedback2 . m_SpriteCalls . end ( ) ) ;
2004-05-29 06:06:50 +02:00
break ;
}
else
if ( x > width_range [ To ] & & j = = temp_from )
{
from = j + 1 ;
// do not break, since we want it to be added to m_TextCalls
}
else
if ( x > width_range [ To ] )
{
from = j ;
break ;
}
}
// Add the whole Feedback2.m_TextCalls to our m_TextCalls.
Text . m_TextCalls . insert ( Text . m_TextCalls . end ( ) , Feedback2 . m_TextCalls . begin ( ) , Feedback2 . m_TextCalls . end ( ) ) ;
Text . m_SpriteCalls . insert ( Text . m_SpriteCalls . end ( ) , Feedback2 . m_SpriteCalls . begin ( ) , Feedback2 . m_SpriteCalls . end ( ) ) ;
2004-07-24 16:04:40 +02:00
if ( j = = ( int ) string . m_Words . size ( ) - 2 )
2004-05-29 06:06:50 +02:00
done = true ;
}
2004-08-31 04:09:58 +02:00
2004-07-14 00:48:53 +02:00
// Reset X
2004-09-03 07:48:47 +02:00
x = 0.f ;
2004-05-29 06:06:50 +02:00
// Update height of all
2004-09-03 07:48:47 +02:00
Text . m_Size . cy = MAX ( Text . m_Size . cy , y + BufferZone ) ;
2004-05-29 06:06:50 +02:00
2004-09-04 22:35:12 +02:00
FirstLine = false ;
2004-05-29 06:06:50 +02:00
// Now if we entered as from = i, then we want
// i being one minus that, so that it will become
// the same i in the next loop. The difference is that
// we're on a new line now.
i = from - 1 ;
}
}
return Text ;
}
2004-12-15 22:24:46 +01:00
void CGUI : : DrawText ( SGUIText & Text , const CColor & DefaultColor ,
2005-07-24 02:01:41 +02:00
const CPos & pos , const float & z , const CRect & clipping )
2004-05-29 06:06:50 +02:00
{
2004-09-03 07:48:47 +02:00
// TODO Gee: All these really necessary? Some
2004-12-21 14:37:24 +01:00
// are defaults and if you changed them
2004-09-03 07:48:47 +02:00
// the opposite value at the end of the functions,
// some things won't be drawn correctly.
2004-07-14 00:48:53 +02:00
glEnable ( GL_TEXTURE_2D ) ;
glDisable ( GL_CULL_FACE ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glEnable ( GL_BLEND ) ;
glDisable ( GL_ALPHA_TEST ) ;
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
2005-07-24 02:01:41 +02:00
if ( clipping ! = CRect ( ) )
{
double eq [ 4 ] [ 4 ] =
{
{ 0.0 , 1.0 , 0.0 , - clipping . top } ,
{ 1.0 , 0.0 , 0.0 , - clipping . left } ,
{ 0.0 , - 1.0 , 0.0 , clipping . bottom } ,
{ - 1.0 , 0.0 , 0.0 , clipping . right }
} ;
for ( int i = 0 ; i < 4 ; + + i )
{
glClipPlane ( GL_CLIP_PLANE0 + i , eq [ i ] ) ;
glEnable ( GL_CLIP_PLANE0 + i ) ;
}
}
2004-08-28 00:08:30 +02:00
CFont * font = NULL ;
2004-07-14 00:48:53 +02:00
CStr LastFontName ;
for ( vector < SGUIText : : STextCall > : : const_iterator it = Text . m_TextCalls . begin ( ) ;
it ! = Text . m_TextCalls . end ( ) ;
2004-05-29 06:06:50 +02:00
+ + it )
{
2004-08-31 04:09:58 +02:00
// If this is just a placeholder for a sprite call, continue
2004-05-29 06:06:50 +02:00
if ( it - > m_pSpriteCall )
continue ;
2004-07-14 00:48:53 +02:00
// Switch fonts when necessary, but remember the last one used
if ( it - > m_Font ! = LastFontName )
{
2004-08-28 00:08:30 +02:00
delete font ;
font = new CFont ( it - > m_Font ) ;
font - > Bind ( ) ;
2004-07-14 00:48:53 +02:00
LastFontName = it - > m_Font ;
}
CColor color = it - > m_UseCustomColor ? it - > m_Color : DefaultColor ;
glPushMatrix ( ) ;
2004-09-06 04:21:21 +02:00
// TODO Gee: (2004-09-04) Why are font corrupted if inputted float value?
2004-09-06 05:05:36 +02:00
glTranslatef ( ( GLfloat ) int ( pos . x + it - > m_Pos . x ) , ( GLfloat ) int ( pos . y + it - > m_Pos . y ) , z ) ;
2004-12-31 13:20:22 +01:00
glColor4fv ( color . FloatArray ( ) ) ;
2004-09-06 14:54:35 +02:00
glwprintf ( L " %ls " , it - > m_String . c_str ( ) ) ; // "%ls" is necessary in case m_String contains % symbols
2004-07-14 00:48:53 +02:00
glPopMatrix ( ) ;
2004-05-29 06:06:50 +02:00
}
2005-02-05 08:25:16 +01:00
if ( font )
delete font ;
2004-07-14 00:48:53 +02:00
2004-12-15 22:24:46 +01:00
for ( list < SGUIText : : SSpriteCall > : : iterator it = Text . m_SpriteCalls . begin ( ) ;
2004-05-29 06:06:50 +02:00
it ! = Text . m_SpriteCalls . end ( ) ;
+ + it )
{
2004-12-18 14:32:00 +01:00
DrawSprite ( it - > m_Sprite , it - > m_CellID , z , it - > m_Area + pos ) ;
2004-05-29 06:06:50 +02:00
}
2004-09-03 07:48:47 +02:00
// TODO To whom it may concern: Thing were not reset, so
// I added this line, modify if incorrect --
2005-07-24 10:29:02 +02:00
if ( clipping ! = CRect ( ) )
{
for ( int i = 0 ; i < 4 ; + + i )
glDisable ( GL_CLIP_PLANE0 + i ) ;
}
2004-09-03 07:48:47 +02:00
glDisable ( GL_TEXTURE_2D ) ;
// -- GL
2003-11-03 17:22:45 +01:00
}
2005-07-25 21:06:18 +02:00
bool CGUI : : GetPreDefinedColor ( const CStr & name , CColor & Output )
{
if ( m_PreDefinedColors . count ( name ) = = 0 )
{
return false ;
}
else
{
Output = m_PreDefinedColors [ name ] ;
return true ;
}
}
2004-08-31 04:09:58 +02:00
void CGUI : : ReportParseError ( const char * str , . . . )
2003-11-03 17:22:45 +01:00
{
2004-08-31 04:09:58 +02:00
va_list argp ;
char buffer [ 512 ] ;
memset ( buffer , 0 , sizeof ( buffer ) ) ;
va_start ( argp , str ) ;
vsnprintf2 ( buffer , sizeof ( buffer ) , str , argp ) ;
va_end ( argp ) ;
2003-11-03 17:22:45 +01:00
// Print header
if ( m_Errors = = 0 )
{
2004-08-15 22:57:31 +02:00
LOG ( ERROR , LOG_CATEGORY , " *** GUI Tree Creation Errors: " ) ;
2003-11-03 17:22:45 +01:00
}
// Important, set ParseError to true
+ + m_Errors ;
2004-08-31 04:09:58 +02:00
LOG ( ERROR , LOG_CATEGORY , buffer ) ;
2003-11-03 17:22:45 +01:00
}
2003-11-24 03:18:41 +01:00
/**
* @ callgraph
*/
2003-11-07 02:55:29 +01:00
void CGUI : : LoadXMLFile ( const string & Filename )
2003-11-03 17:22:45 +01:00
{
// Reset parse error
// we can later check if this has increased
m_Errors = 0 ;
2004-07-08 17:23:47 +02:00
CXeromyces XeroFile ;
2004-07-29 18:17:21 +02:00
if ( XeroFile . Load ( Filename . c_str ( ) ) ! = PSRETURN_OK )
2004-07-15 21:10:33 +02:00
// Fail silently
2004-07-11 18:22:35 +02:00
return ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
XMBElement node = XeroFile . getRoot ( ) ;
2003-11-25 03:47:12 +01:00
2004-07-08 17:23:47 +02:00
// Check root element's (node) name so we know what kind of
// data we'll be expecting
2004-10-31 23:00:01 +01:00
CStr root_name ( XeroFile . getElementString ( node . getNodeName ( ) ) ) ;
2004-06-14 01:36:16 +02:00
2004-07-17 19:09:33 +02:00
try
2004-07-08 17:23:47 +02:00
{
2004-10-14 12:09:26 +02:00
2004-07-17 19:09:33 +02:00
if ( root_name = = " objects " )
{
Xeromyces_ReadRootObjects ( node , & XeroFile ) ;
// Re-cache all values so these gets cached too.
//UpdateResolution();
}
else
if ( root_name = = " sprites " )
{
Xeromyces_ReadRootSprites ( node , & XeroFile ) ;
}
else
if ( root_name = = " styles " )
{
Xeromyces_ReadRootStyles ( node , & XeroFile ) ;
}
else
if ( root_name = = " setup " )
{
Xeromyces_ReadRootSetup ( node , & XeroFile ) ;
}
else
{
2004-08-10 18:04:21 +02:00
debug_warn ( " CGUI::LoadXMLFile error " ) ;
2004-07-17 19:09:33 +02:00
// TODO Gee: Output in log
}
2004-07-08 17:23:47 +02:00
}
2005-05-24 02:00:40 +02:00
catch ( PSERROR_GUI & e )
2004-07-08 17:23:47 +02:00
{
2005-05-24 02:00:40 +02:00
LOG ( ERROR , LOG_CATEGORY , " Errors loading GUI file %s (%s) " , Filename . c_str ( ) , e . getCode ( ) ) ;
2004-07-17 19:09:33 +02:00
return ;
2004-07-08 17:23:47 +02:00
}
2003-12-27 07:26:03 +01:00
2004-07-08 17:23:47 +02:00
// Now report if any other errors occured
if ( m_Errors > 0 )
{
/// g_console.submit("echo GUI Tree Creation Reports %d errors", m_Errors);
2003-11-03 17:22:45 +01:00
}
2004-07-08 17:23:47 +02:00
2003-11-03 17:22:45 +01:00
}
//===================================================================
2004-07-08 17:23:47 +02:00
// XML Reading Xeromyces Specific Sub-Routines
2003-11-03 17:22:45 +01:00
//===================================================================
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadRootObjects ( XMBElement Element , CXeromyces * pFile )
2003-11-03 17:22:45 +01:00
{
2004-07-11 18:22:35 +02:00
int el_script = pFile - > getElementID ( " script " ) ;
2003-11-03 17:22:45 +01:00
// Iterate main children
2004-07-11 18:22:35 +02:00
// they should all be <object> or <script> elements
2004-07-08 17:23:47 +02:00
XMBElementList children = Element . getChildNodes ( ) ;
for ( int i = 0 ; i < children . Count ; + + i )
2003-11-03 17:22:45 +01:00
{
2005-05-11 20:56:30 +02:00
//debug_printf("Object %d\n", i);
2004-07-08 17:23:47 +02:00
XMBElement child = children . item ( i ) ;
2003-11-03 17:22:45 +01:00
2004-07-11 18:22:35 +02:00
if ( child . getNodeName ( ) = = el_script )
// Execute the inline script
Xeromyces_ReadScript ( child , pFile ) ;
else
// Read in this whole object into the GUI
Xeromyces_ReadObject ( child , pFile , m_BaseObject ) ;
2003-11-03 17:22:45 +01:00
}
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadRootSprites ( XMBElement Element , CXeromyces * pFile )
2003-11-03 17:22:45 +01:00
{
// Iterate main children
// they should all be <sprite> elements
2004-07-08 17:23:47 +02:00
XMBElementList children = Element . getChildNodes ( ) ;
for ( int i = 0 ; i < children . Count ; + + i )
2003-11-03 17:22:45 +01:00
{
2004-07-08 17:23:47 +02:00
XMBElement child = children . item ( i ) ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
// Read in this whole object into the GUI
Xeromyces_ReadSprite ( child , pFile ) ;
2003-11-03 17:22:45 +01:00
}
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadRootStyles ( XMBElement Element , CXeromyces * pFile )
2003-12-01 08:06:55 +01:00
{
// Iterate main children
// they should all be <styles> elements
2004-07-08 17:23:47 +02:00
XMBElementList children = Element . getChildNodes ( ) ;
for ( int i = 0 ; i < children . Count ; + + i )
2003-12-01 08:06:55 +01:00
{
2004-07-08 17:23:47 +02:00
XMBElement child = children . item ( i ) ;
2003-12-01 08:06:55 +01:00
2004-07-08 17:23:47 +02:00
// Read in this whole object into the GUI
Xeromyces_ReadStyle ( child , pFile ) ;
2003-12-01 08:06:55 +01:00
}
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadRootSetup ( XMBElement Element , CXeromyces * pFile )
2003-12-27 07:26:03 +01:00
{
// Iterate main children
// they should all be <icon>, <scrollbar> or <tooltip>.
2004-07-08 17:23:47 +02:00
XMBElementList children = Element . getChildNodes ( ) ;
for ( int i = 0 ; i < children . Count ; + + i )
2003-12-27 07:26:03 +01:00
{
2004-07-08 17:23:47 +02:00
XMBElement child = children . item ( i ) ;
2003-12-27 07:26:03 +01:00
2004-07-08 17:23:47 +02:00
// Read in this whole object into the GUI
2003-12-27 07:26:03 +01:00
2004-10-31 23:00:01 +01:00
CStr name ( pFile - > getElementString ( child . getNodeName ( ) ) ) ;
2003-12-27 07:26:03 +01:00
2004-07-10 22:33:42 +02:00
if ( name = = " scrollbar " )
2004-07-08 17:23:47 +02:00
{
Xeromyces_ReadScrollBarStyle ( child , pFile ) ;
2003-12-27 07:26:03 +01:00
}
2004-08-31 04:09:58 +02:00
else
if ( name = = " icon " )
{
Xeromyces_ReadIcon ( child , pFile ) ;
}
2004-12-21 14:37:24 +01:00
else
if ( name = = " tooltip " )
{
Xeromyces_ReadTooltip ( child , pFile ) ;
}
else
2005-07-25 21:06:18 +02:00
if ( name = = " color " )
{
Xeromyces_ReadColor ( child , pFile ) ;
}
else
2004-12-21 14:37:24 +01:00
{
debug_warn ( " Invalid data - DTD shouldn't allow this " ) ;
}
2003-12-27 07:26:03 +01:00
}
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadObject ( XMBElement Element , CXeromyces * pFile , IGUIObject * pParent )
2003-11-03 17:22:45 +01:00
{
2005-06-28 06:06:25 +02:00
debug_assert ( pParent ) ;
2004-07-08 17:23:47 +02:00
int i ;
2003-11-03 17:22:45 +01:00
// Our object we are going to create
2003-11-24 03:18:41 +01:00
IGUIObject * object = NULL ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
XMBAttributeList attributes = Element . getAttributes ( ) ;
2003-11-03 17:22:45 +01:00
// Well first of all we need to determine the type
2004-10-31 23:00:01 +01:00
CStr type ( attributes . getNamedItem ( pFile - > getAttributeID ( " type " ) ) ) ;
2003-11-03 17:22:45 +01:00
// Construct object from specified type
// henceforth, we need to do a rollback before aborting.
// i.e. releasing this object
2004-10-31 23:00:01 +01:00
object = ConstructObject ( type ) ;
2003-11-03 17:22:45 +01:00
if ( ! object )
{
// Report error that object was unsuccessfully loaded
2004-10-31 21:29:09 +01:00
ReportParseError ( " Unrecognized type \" %s \" " , type . c_str ( ) ) ;
2003-11-03 17:22:45 +01:00
return ;
}
2004-07-08 17:23:47 +02:00
// Cache some IDs for element attribute names, to avoid string comparisons
2004-07-10 22:33:42 +02:00
# define ELMT(x) int elmt_##x = pFile->getElementID(#x)
# define ATTR(x) int attr_##x = pFile->getAttributeID(#x)
2004-07-08 17:23:47 +02:00
ELMT ( object ) ;
ELMT ( action ) ;
ATTR ( style ) ;
ATTR ( type ) ;
ATTR ( name ) ;
2004-07-22 18:18:12 +02:00
ATTR ( hotkey ) ;
2004-07-08 17:23:47 +02:00
ATTR ( z ) ;
ATTR ( on ) ;
2004-07-11 18:22:35 +02:00
ATTR ( file ) ;
2004-07-08 17:23:47 +02:00
2003-12-01 08:06:55 +01:00
//
// Read Style and set defaults
//
2003-12-27 07:26:03 +01:00
// If the setting "style" is set, try loading that setting.
//
// Always load default (if it's available) first!
//
2004-10-31 23:00:01 +01:00
CStr argStyle ( attributes . getNamedItem ( attr_style ) ) ;
2003-12-01 08:06:55 +01:00
2004-12-21 14:37:24 +01:00
if ( m_Styles . count ( " default " ) = = 1 )
object - > LoadStyle ( * this , " default " ) ;
2003-12-27 07:26:03 +01:00
2004-12-15 22:24:46 +01:00
if ( argStyle . Length ( ) )
2003-12-01 08:06:55 +01:00
{
2003-12-27 07:26:03 +01:00
// additional check
2003-12-01 08:06:55 +01:00
if ( m_Styles . count ( argStyle ) = = 0 )
{
2004-08-31 04:09:58 +02:00
ReportParseError ( " Trying to use style '%s' that doesn't exist. " , argStyle . c_str ( ) ) ;
2003-12-01 08:06:55 +01:00
}
2003-12-27 07:26:03 +01:00
else object - > LoadStyle ( * this , argStyle ) ;
2003-12-01 08:06:55 +01:00
}
2003-12-27 07:26:03 +01:00
2003-11-03 17:22:45 +01:00
//
// Read Attributes
//
bool NameSet = false ;
2003-12-27 07:26:03 +01:00
bool ManuallySetZ = false ; // if z has been manually set, this turn true
2003-11-03 17:22:45 +01:00
2004-10-31 23:00:01 +01:00
CStr hotkeyTag ;
2004-07-22 18:18:12 +02:00
2003-11-03 17:22:45 +01:00
// Now we can iterate all attributes and store
2004-07-08 17:23:47 +02:00
for ( i = 0 ; i < attributes . Count ; + + i )
2003-11-03 17:22:45 +01:00
{
2004-07-08 17:23:47 +02:00
XMBAttribute attr = attributes . item ( i ) ;
2003-11-03 17:22:45 +01:00
2004-05-29 06:06:50 +02:00
// If value is "null", then it is equivalent as never being entered
2004-12-21 14:37:24 +01:00
if ( ( CStr ) attr . Value = = " null " )
2004-05-29 06:06:50 +02:00
continue ;
2003-12-01 08:06:55 +01:00
// Ignore "type" and "style", we've already checked it
2004-07-17 19:09:33 +02:00
if ( attr . Name = = attr_type | | attr . Name = = attr_style )
2003-11-03 17:22:45 +01:00
continue ;
// Also the name needs some special attention
2004-07-08 17:23:47 +02:00
if ( attr . Name = = attr_name )
2003-11-03 17:22:45 +01:00
{
2004-07-10 22:56:15 +02:00
object - > SetName ( ( CStr ) attr . Value ) ;
2003-11-03 17:22:45 +01:00
NameSet = true ;
continue ;
}
2004-07-22 18:18:12 +02:00
// Wire up the hotkey tag, if it has one
2004-10-31 23:00:01 +01:00
if ( attr . Name = = attr_hotkey )
2004-07-22 18:18:12 +02:00
hotkeyTag = attr . Value ;
2004-07-08 17:23:47 +02:00
if ( attr . Name = = attr_z )
2003-12-27 07:26:03 +01:00
ManuallySetZ = true ;
2003-11-03 17:22:45 +01:00
// Try setting the value
2005-02-05 08:25:16 +01:00
if ( object - > SetSetting ( pFile - > getAttributeString ( attr . Name ) , ( CStr ) attr . Value , true ) ! = PS_OK )
2003-11-03 17:22:45 +01:00
{
2005-02-05 08:25:16 +01:00
ReportParseError ( " (object: %s) Can't set \" %s \" to \" %s \" " , object - > GetPresentableName ( ) . c_str ( ) , pFile - > getAttributeString ( attr . Name ) . c_str ( ) , CStr ( attr . Value ) . c_str ( ) ) ;
2003-11-03 17:22:45 +01:00
// This is not a fatal error
}
}
2004-05-29 06:06:50 +02:00
// Check if name isn't set, generate an internal name in that case.
2003-11-03 17:22:45 +01:00
if ( ! NameSet )
{
2004-05-29 06:06:50 +02:00
object - > SetName ( CStr ( " __internal( " ) + CStr ( m_InternalNameNumber ) + CStr ( " ) " ) ) ;
+ + m_InternalNameNumber ;
2003-11-03 17:22:45 +01:00
}
2004-07-22 18:18:12 +02:00
// Attempt to register the hotkey tag, if one was provided
2004-12-21 14:37:24 +01:00
if ( hotkeyTag . Length ( ) )
hotkeyRegisterGUIObject ( object - > GetName ( ) , hotkeyTag ) ;
2004-07-08 17:23:47 +02:00
2004-10-31 23:00:01 +01:00
CStrW caption ( Element . getText ( ) ) ;
2004-07-08 17:23:47 +02:00
if ( caption . Length ( ) )
{
2004-12-13 13:07:12 +01:00
// Set the setting caption to this
2005-02-05 08:25:16 +01:00
object - > SetSetting ( " caption " , caption , true ) ;
2004-12-13 13:07:12 +01:00
// There is no harm if the object didn't have a "caption"
2004-07-08 17:23:47 +02:00
}
2003-11-03 17:22:45 +01:00
//
// Read Children
//
// Iterate children
2004-07-08 17:23:47 +02:00
XMBElementList children = Element . getChildNodes ( ) ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
for ( i = 0 ; i < children . Count ; + + i )
2003-11-03 17:22:45 +01:00
{
// Get node
2004-07-08 17:23:47 +02:00
XMBElement child = children . item ( i ) ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
// Check what name the elements got
int element_name = child . getNodeName ( ) ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
if ( element_name = = elmt_object )
{
// Call this function on the child
Xeromyces_ReadObject ( child , pFile , object ) ;
2003-11-03 17:22:45 +01:00
}
2004-07-08 17:23:47 +02:00
else if ( element_name = = elmt_action )
2003-11-03 17:22:45 +01:00
{
2004-07-11 18:22:35 +02:00
// Scripted <action> element
// Check for a 'file' parameter
2004-07-11 20:18:54 +02:00
CStr file ( child . getAttributes ( ) . getNamedItem ( attr_file ) ) ;
2004-07-11 18:22:35 +02:00
CStr code ;
// If there is a file, open it and use it as the code
if ( file . Length ( ) )
{
2004-07-29 18:17:21 +02:00
CVFSFile scriptfile ;
if ( scriptfile . Load ( file ) ! = PSRETURN_OK )
2004-07-11 18:22:35 +02:00
{
2004-08-15 22:57:31 +02:00
LOG ( ERROR , LOG_CATEGORY , " Error opening action file '%s' " , file . c_str ( ) ) ;
2004-07-17 19:09:33 +02:00
throw PSERROR_GUI_JSOpenFailed ( ) ;
}
2004-07-11 18:22:35 +02:00
2004-07-29 18:17:21 +02:00
code = scriptfile . GetAsString ( ) ;
2004-07-11 18:22:35 +02:00
}
// Read the inline code (concatenating to the file code, if both are specified)
2004-07-11 20:18:54 +02:00
code + = ( CStr ) child . getText ( ) ;
2004-07-11 18:22:35 +02:00
2004-07-10 22:56:15 +02:00
CStr action = ( CStr ) child . getAttributes ( ) . getNamedItem ( attr_on ) ;
2004-07-11 18:22:35 +02:00
object - > RegisterScriptHandler ( action . LowerCase ( ) , code , this ) ;
2003-11-03 17:22:45 +01:00
}
2005-04-07 11:13:10 +02:00
else
{
// Try making the object read the tag.
if ( ! object - > HandleAdditionalChildren ( child , pFile ) )
{
LOG ( ERROR , LOG_CATEGORY , " (object: %s) Reading unknown children for its type " ) ;
}
}
2003-12-01 08:06:55 +01:00
}
2003-11-03 17:22:45 +01:00
2003-12-27 07:26:03 +01:00
//
// Check if Z wasn't manually set
//
if ( ! ManuallySetZ )
{
// Set it automatically to 10 plus its parents
if ( pParent = = NULL )
{
2004-08-10 18:04:21 +02:00
debug_warn ( " CGUI::Xeromyces_ReadObject error " ) ;
2003-12-27 07:26:03 +01:00
// TODO Gee: Report error
}
else
{
2004-05-29 06:06:50 +02:00
bool absolute ;
GUI < bool > : : GetSetting ( object , " absolute " , absolute ) ;
2003-12-27 07:26:03 +01:00
// If the object is absolute, we'll have to get the parent's Z buffered,
// and add to that!
2004-05-29 06:06:50 +02:00
if ( absolute )
2003-12-27 07:26:03 +01:00
{
2005-02-05 08:25:16 +01:00
GUI < float > : : SetSetting ( object , " z " , pParent - > GetBufferedZ ( ) + 10.f , true ) ;
2003-12-27 07:26:03 +01:00
}
else
// If the object is relative, then we'll just store Z as "10"
{
2005-02-05 08:25:16 +01:00
GUI < float > : : SetSetting ( object , " z " , 10.f , true ) ;
2003-12-27 07:26:03 +01:00
}
}
}
2003-11-03 17:22:45 +01:00
//
// Input Child
//
try
{
if ( pParent = = m_BaseObject )
AddObject ( object ) ;
else
pParent - > AddChild ( object ) ;
}
catch ( PS_RESULT e )
2003-12-01 08:06:55 +01:00
{
2003-11-03 17:22:45 +01:00
ReportParseError ( e ) ;
}
}
2004-07-11 18:22:35 +02:00
void CGUI : : Xeromyces_ReadScript ( XMBElement Element , CXeromyces * pFile )
{
// Check for a 'file' parameter
CStr file ( Element . getAttributes ( ) . getNamedItem ( pFile - > getAttributeID ( " file " ) ) ) ;
2004-07-11 20:18:54 +02:00
// If there is a file specified, open and execute it
2004-07-11 18:22:35 +02:00
if ( file . Length ( ) )
2005-08-09 18:02:15 +02:00
g_ScriptingHost . RunScript ( file , m_ScriptObject ) ;
2004-07-11 18:22:35 +02:00
// Execute inline scripts
CStr code ( Element . getText ( ) ) ;
2004-07-12 17:50:12 +02:00
if ( code . Length ( ) )
2005-08-09 18:02:15 +02:00
g_ScriptingHost . RunMemScript ( code . c_str ( ) , code . Length ( ) , " Some XML file " , Element . getLineNumber ( ) , m_ScriptObject ) ;
2004-07-11 18:22:35 +02:00
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadSprite ( XMBElement Element , CXeromyces * pFile )
2003-11-03 17:22:45 +01:00
{
// Sprite object we're adding
CGUISprite sprite ;
// and what will be its reference name
CStr name ;
//
// Read Attributes
//
// Get name, we know it exists because of DTD requirements
2004-10-31 23:00:01 +01:00
name = Element . getAttributes ( ) . getNamedItem ( pFile - > getAttributeID ( " name " ) ) ;
2003-11-03 17:22:45 +01:00
2004-12-21 14:37:24 +01:00
if ( m_Sprites . find ( name ) ! = m_Sprites . end ( ) )
LOG ( WARNING , LOG_CATEGORY , " Sprite name '%s' used more than once; first definition will be discarded " , ( const char * ) name ) ;
2003-11-03 17:22:45 +01:00
//
// Read Children (the images)
//
2004-12-18 14:32:00 +01:00
SGUIImageEffects * effects = NULL ;
2003-11-03 17:22:45 +01:00
// Iterate children
2004-07-08 17:23:47 +02:00
XMBElementList children = Element . getChildNodes ( ) ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
for ( int i = 0 ; i < children . Count ; + + i )
2003-11-03 17:22:45 +01:00
{
// Get node
2004-07-08 17:23:47 +02:00
XMBElement child = children . item ( i ) ;
2003-11-03 17:22:45 +01:00
2004-12-18 14:32:00 +01:00
CStr ElementName ( pFile - > getElementString ( child . getNodeName ( ) ) ) ;
2003-11-03 17:22:45 +01:00
2004-12-18 14:32:00 +01:00
if ( ElementName = = " image " )
{
Xeromyces_ReadImage ( child , pFile , sprite ) ;
}
else if ( ElementName = = " effect " )
{
2005-06-28 06:06:25 +02:00
debug_assert ( ! effects ) ; // DTD should only allow one effect per sprite
2004-12-18 14:32:00 +01:00
effects = new SGUIImageEffects ;
Xeromyces_ReadEffects ( child , pFile , * effects ) ;
}
else
{
2004-12-21 14:37:24 +01:00
debug_warn ( " Invalid data - DTD shouldn't allow this " ) ;
2004-12-18 14:32:00 +01:00
}
2003-11-03 17:22:45 +01:00
}
2004-12-18 14:32:00 +01:00
// Apply the effects to every image (unless the image overrides it with
// different effects)
if ( effects )
for ( std : : vector < SGUIImage > : : iterator it = sprite . m_Images . begin ( ) ; it ! = sprite . m_Images . end ( ) ; + + it )
if ( ! it - > m_Effects )
it - > m_Effects = new SGUIImageEffects ( * effects ) ; // do a copy just so it can be deleted correctly later
delete effects ;
2003-11-03 17:22:45 +01:00
//
// Add Sprite
//
m_Sprites [ name ] = sprite ;
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadImage ( XMBElement Element , CXeromyces * pFile , CGUISprite & parent )
2003-11-03 17:22:45 +01:00
{
// Image object we're adding
SGUIImage image ;
2005-07-25 21:06:18 +02:00
// Set defaults (or maybe do that in DTD?)
image . m_TextureSize = CClientArea ( " 0 0 100% 100% " ) ;
image . m_Size = CClientArea ( " 0 0 100% 100% " ) ;
2004-07-14 00:48:53 +02:00
2003-12-27 07:26:03 +01:00
// TODO Gee: Setup defaults here (or maybe they are in the SGUIImage ctor)
2003-11-03 17:22:45 +01:00
//
// Read Attributes
//
// Now we can iterate all attributes and store
2004-07-08 17:23:47 +02:00
XMBAttributeList attributes = Element . getAttributes ( ) ;
for ( int i = 0 ; i < attributes . Count ; + + i )
2003-11-03 17:22:45 +01:00
{
2004-07-08 17:23:47 +02:00
XMBAttribute attr = attributes . item ( i ) ;
2004-10-31 23:00:01 +01:00
CStr attr_name ( pFile - > getAttributeString ( attr . Name ) ) ;
2004-07-10 22:56:15 +02:00
CStr attr_value ( attr . Value ) ;
2003-11-03 17:22:45 +01:00
2004-07-10 22:33:42 +02:00
if ( attr_name = = " texture " )
2003-11-03 17:22:45 +01:00
{
2004-10-31 23:00:01 +01:00
CStr TexFilename ( " art/textures/ui/ " ) ;
2004-07-14 00:48:53 +02:00
TexFilename + = attr_value ;
2004-12-15 22:24:46 +01:00
image . m_TextureName = TexFilename ;
2003-11-03 17:22:45 +01:00
}
else
2004-07-10 22:33:42 +02:00
if ( attr_name = = " size " )
2003-11-03 17:22:45 +01:00
{
2003-12-01 08:06:55 +01:00
CClientArea ca ;
if ( ! GUI < CClientArea > : : ParseString ( attr_value , ca ) )
2004-08-31 04:09:58 +02:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2003-12-01 08:06:55 +01:00
else image . m_Size = ca ;
}
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " texture_size " )
2004-07-14 00:48:53 +02:00
{
CClientArea ca ;
if ( ! GUI < CClientArea > : : ParseString ( attr_value , ca ) )
2004-08-31 04:09:58 +02:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2004-07-14 00:48:53 +02:00
else image . m_TextureSize = ca ;
}
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " real_texture_placement " )
2004-09-02 05:02:32 +02:00
{
CRect rect ;
if ( ! GUI < CRect > : : ParseString ( attr_value , rect ) )
2004-12-17 17:20:08 +01:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2004-09-02 05:02:32 +02:00
else image . m_TexturePlacementInFile = rect ;
}
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " cell_size " )
2004-12-17 17:20:08 +01:00
{
CSize size ;
if ( ! GUI < CSize > : : ParseString ( attr_value , size ) )
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2004-12-18 14:32:00 +01:00
else image . m_CellSize = size ;
2004-12-17 17:20:08 +01:00
}
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " z_level " )
2004-05-29 06:06:50 +02:00
{
2004-09-03 07:48:47 +02:00
float z_level ;
if ( ! GUI < float > : : ParseString ( attr_value , z_level ) )
2004-08-31 04:09:58 +02:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2004-09-03 07:48:47 +02:00
else image . m_DeltaZ = z_level / 100.f ;
2004-05-29 06:06:50 +02:00
}
else
2004-07-10 22:33:42 +02:00
if ( attr_name = = " backcolor " )
2003-12-01 08:06:55 +01:00
{
CColor color ;
if ( ! GUI < CColor > : : ParseString ( attr_value , color ) )
2004-08-31 04:09:58 +02:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2003-12-01 08:06:55 +01:00
else image . m_BackColor = color ;
}
2004-09-06 04:21:21 +02:00
else
if ( attr_name = = " bordercolor " )
{
CColor color ;
if ( ! GUI < CColor > : : ParseString ( attr_value , color ) )
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
else image . m_BorderColor = color ;
}
else
if ( attr_name = = " border " )
{
bool b ;
if ( ! GUI < bool > : : ParseString ( attr_value , b ) )
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
else image . m_Border = b ;
}
2004-12-18 14:32:00 +01:00
else
{
2004-12-21 14:37:24 +01:00
debug_warn ( " Invalid data - DTD shouldn't allow this " ) ;
2004-12-18 14:32:00 +01:00
}
}
// Look for effects
XMBElementList children = Element . getChildNodes ( ) ;
for ( int i = 0 ; i < children . Count ; + + i )
{
XMBElement child = children . item ( i ) ;
CStr ElementName ( pFile - > getElementString ( child . getNodeName ( ) ) ) ;
if ( ElementName = = " effect " )
{
2005-06-28 06:06:25 +02:00
debug_assert ( ! image . m_Effects ) ; // DTD should only allow one effect per sprite
2004-12-18 14:32:00 +01:00
image . m_Effects = new SGUIImageEffects ;
Xeromyces_ReadEffects ( child , pFile , * image . m_Effects ) ;
}
else
{
2004-12-21 14:37:24 +01:00
debug_warn ( " Invalid data - DTD shouldn't allow this " ) ;
2004-12-18 14:32:00 +01:00
}
2003-11-03 17:22:45 +01:00
}
2003-12-01 08:06:55 +01:00
2003-11-03 17:22:45 +01:00
//
// Input
//
parent . AddImage ( image ) ;
}
2003-12-01 08:06:55 +01:00
2004-12-18 14:32:00 +01:00
void CGUI : : Xeromyces_ReadEffects ( XMBElement Element , CXeromyces * pFile , SGUIImageEffects & effects )
{
XMBAttributeList attributes = Element . getAttributes ( ) ;
for ( int i = 0 ; i < attributes . Count ; + + i )
{
XMBAttribute attr = attributes . item ( i ) ;
CStr attr_name ( pFile - > getAttributeString ( attr . Name ) ) ;
CStr attr_value ( attr . Value ) ;
2005-01-03 23:23:27 +01:00
# define COLOR(xml, mem, alpha) \
2004-12-18 14:32:00 +01:00
if ( attr_name = = xml ) \
{ \
CColor color ; \
2005-01-03 23:23:27 +01:00
if ( ! GUI < int > : : ParseColor ( attr_value , color , alpha ) ) \
2004-12-18 14:32:00 +01:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ; \
else effects . m_ # # mem = color ; \
} \
else
2005-01-03 23:23:27 +01:00
2004-12-19 13:20:04 +01:00
# define BOOL(xml, mem) \
if ( attr_name = = xml ) \
{ \
effects . m_ # # mem = true ; \
} \
else
2005-01-03 23:23:27 +01:00
COLOR ( " add_color " , AddColor , 0.f )
COLOR ( " multiply_color " , MultiplyColor , 255.f )
2004-12-19 13:20:04 +01:00
BOOL ( " grayscale " , Greyscale )
2004-12-18 14:32:00 +01:00
{
2004-12-21 14:37:24 +01:00
debug_warn ( " Invalid data - DTD shouldn't allow this " ) ;
2004-12-18 14:32:00 +01:00
}
}
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadStyle ( XMBElement Element , CXeromyces * pFile )
2003-12-01 08:06:55 +01:00
{
// style object we're adding
SGUIStyle style ;
CStr name ;
//
// Read Attributes
//
// Now we can iterate all attributes and store
2004-07-08 17:23:47 +02:00
XMBAttributeList attributes = Element . getAttributes ( ) ;
for ( int i = 0 ; i < attributes . Count ; + + i )
2003-12-01 08:06:55 +01:00
{
2004-07-08 17:23:47 +02:00
XMBAttribute attr = attributes . item ( i ) ;
2004-10-31 23:00:01 +01:00
CStr attr_name ( pFile - > getAttributeString ( attr . Name ) ) ;
2004-07-10 22:56:15 +02:00
CStr attr_value ( attr . Value ) ;
2003-12-01 08:06:55 +01:00
// The "name" setting is actually the name of the style
// and not a new default
2004-07-10 22:33:42 +02:00
if ( attr_name = = " name " )
2003-12-01 08:06:55 +01:00
name = attr_value ;
else
2004-07-10 22:33:42 +02:00
style . m_SettingsDefaults [ attr_name ] = attr_value ;
2003-12-01 08:06:55 +01:00
}
//
// Add to CGUI
//
m_Styles [ name ] = style ;
}
2003-12-27 07:26:03 +01:00
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadScrollBarStyle ( XMBElement Element , CXeromyces * pFile )
2003-12-27 07:26:03 +01:00
{
// style object we're adding
SGUIScrollBarStyle scrollbar ;
CStr name ;
//
// Read Attributes
//
// Now we can iterate all attributes and store
2004-07-08 17:23:47 +02:00
XMBAttributeList attributes = Element . getAttributes ( ) ;
for ( int i = 0 ; i < attributes . Count ; + + i )
2003-12-27 07:26:03 +01:00
{
2004-07-08 17:23:47 +02:00
XMBAttribute attr = attributes . item ( i ) ;
2004-10-31 23:00:01 +01:00
CStr attr_name = pFile - > getAttributeString ( attr . Name ) ;
2004-07-10 22:56:15 +02:00
CStr attr_value ( attr . Value ) ;
2003-12-27 07:26:03 +01:00
2004-10-31 23:00:01 +01:00
if ( attr_value = = " null " )
2004-05-29 06:06:50 +02:00
continue ;
2004-07-10 22:33:42 +02:00
if ( attr_name = = " name " )
2003-12-27 07:26:03 +01:00
name = attr_value ;
else
2004-07-10 22:33:42 +02:00
if ( attr_name = = " width " )
2003-12-27 07:26:03 +01:00
{
2004-09-03 07:48:47 +02:00
float f ;
if ( ! GUI < float > : : ParseString ( attr_value , f ) )
2003-12-27 07:26:03 +01:00
{
2004-08-31 04:09:58 +02:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2003-12-27 07:26:03 +01:00
}
2004-09-03 07:48:47 +02:00
scrollbar . m_Width = f ;
2003-12-27 07:26:03 +01:00
}
2004-05-29 06:06:50 +02:00
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " minimum_bar_size " )
2004-05-29 06:06:50 +02:00
{
2004-09-03 07:48:47 +02:00
float f ;
if ( ! GUI < float > : : ParseString ( attr_value , f ) )
2004-05-29 06:06:50 +02:00
{
2004-08-31 04:09:58 +02:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2004-05-29 06:06:50 +02:00
}
2004-09-03 07:48:47 +02:00
scrollbar . m_MinimumBarSize = f ;
2004-05-29 06:06:50 +02:00
}
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " sprite_button_top " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTop = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_button_top_pressed " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTopPressed = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_button_top_disabled " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTopDisabled = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_button_top_over " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTopOver = attr_value ;
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " sprite_button_bottom " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottom = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_button_bottom_pressed " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottomPressed = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_button_bottom_disabled " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottomDisabled = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_button_bottom_over " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottomOver = attr_value ;
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " sprite_back_vertical " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBackVertical = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_bar_vertical " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBarVertical = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_bar_vertical_over " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBarVerticalOver = attr_value ;
else
2005-04-07 11:13:10 +02:00
if ( attr_name = = " sprite_bar_vertical_pressed " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBarVerticalPressed = attr_value ;
2004-08-31 04:09:58 +02:00
}
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
//
2005-04-07 11:13:10 +02:00
// Add to CGUI
2004-08-31 04:09:58 +02:00
//
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
m_ScrollBarStyles [ name ] = scrollbar ;
}
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
void CGUI : : Xeromyces_ReadIcon ( XMBElement Element , CXeromyces * pFile )
{
// Icon we're adding
SGUIIcon icon ;
CStr name ;
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
XMBAttributeList attributes = Element . getAttributes ( ) ;
for ( int i = 0 ; i < attributes . Count ; + + i )
{
XMBAttribute attr = attributes . item ( i ) ;
2004-10-31 23:00:01 +01:00
CStr attr_name ( pFile - > getAttributeString ( attr . Name ) ) ;
2004-08-31 04:09:58 +02:00
CStr attr_value ( attr . Value ) ;
2004-05-29 06:06:50 +02:00
2004-10-31 23:00:01 +01:00
if ( attr_value = = " null " )
2004-08-31 04:09:58 +02:00
continue ;
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
if ( attr_name = = " name " )
name = attr_value ;
else
2005-07-25 02:52:03 +02:00
if ( attr_name = = " sprite " )
icon . m_SpriteName = attr_value ;
2004-08-31 04:09:58 +02:00
else
if ( attr_name = = " size " )
{
CSize size ;
if ( ! GUI < CSize > : : ParseString ( attr_value , size ) )
2004-12-18 14:32:00 +01:00
ReportParseError ( " Error parsing '%s' ( \" %s \" ) inside <icon>. " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
2004-08-31 04:09:58 +02:00
icon . m_Size = size ;
}
2004-12-18 14:32:00 +01:00
else
2005-01-01 13:06:17 +01:00
if ( attr_name = = " cell_id " )
2004-12-18 14:32:00 +01:00
{
int cell_id ;
if ( ! GUI < int > : : ParseString ( attr_value , cell_id ) )
ReportParseError ( " Error parsing '%s' ( \" %s \" ) inside <icon>. " , attr_name . c_str ( ) , attr_value . c_str ( ) ) ;
icon . m_CellID = cell_id ;
}
else
{
2004-12-21 14:37:24 +01:00
debug_warn ( " Invalid data - DTD shouldn't allow this " ) ;
2004-12-18 14:32:00 +01:00
}
2003-12-27 07:26:03 +01:00
}
2004-08-31 04:09:58 +02:00
m_Icons [ name ] = icon ;
2003-12-27 07:26:03 +01:00
}
2004-12-21 14:37:24 +01:00
void CGUI : : Xeromyces_ReadTooltip ( XMBElement Element , CXeromyces * pFile )
{
2004-12-23 14:56:34 +01:00
// Read the tooltip, and store it as a specially-named object
2004-12-21 14:37:24 +01:00
2004-12-23 14:56:34 +01:00
IGUIObject * object = new CTooltip ;
2004-12-21 14:37:24 +01:00
XMBAttributeList attributes = Element . getAttributes ( ) ;
for ( int i = 0 ; i < attributes . Count ; + + i )
{
XMBAttribute attr = attributes . item ( i ) ;
CStr attr_name ( pFile - > getAttributeString ( attr . Name ) ) ;
CStr attr_value ( attr . Value ) ;
if ( attr_name = = " name " )
{
2004-12-23 14:56:34 +01:00
object - > SetName ( " __tooltip_ " + attr_value ) ;
2004-12-21 14:37:24 +01:00
}
else
{
object - > SetSetting ( attr_name , attr_value ) ;
}
}
AddObject ( object ) ;
}
2005-07-25 21:06:18 +02:00
// Reads Custom Color
void CGUI : : Xeromyces_ReadColor ( XMBElement Element , CXeromyces * pFile )
{
// Read the color and stor in m_PreDefinedColors
XMBAttributeList attributes = Element . getAttributes ( ) ;
//IGUIObject* object = new CTooltip;
CColor color ;
CStr name = attributes . getNamedItem ( pFile - > getAttributeID ( " name " ) ) ;
// Try parsing value
CStr value ( Element . getText ( ) ) ;
if ( value . Length ( ) )
{
// Try setting color to value
if ( ! color . ParseString ( value , 255.f ) )
{
ReportParseError ( " Unable to create custom color '%s'. Invalid color syntax. " , name . c_str ( ) ) ;
}
else
{
// input color
m_PreDefinedColors [ name ] = color ;
}
}
}