Added much documentation and did some cleanup to GUI engine (hopefully if I'm hit by a meteorite, others will be able to continue working with the code)
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@3802 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
86e5f5c71d
commit
6b15d31d6b
@ -36,9 +36,27 @@ public:
|
|||||||
bool isGameState();
|
bool isGameState();
|
||||||
void reshowTopMostMenu();
|
void reshowTopMostMenu();
|
||||||
|
|
||||||
// method to override in children
|
/* ***********************************
|
||||||
|
* methods to override in children *
|
||||||
|
*********************************** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callback called whenever escape was pressed (or any similar cancel operation)
|
||||||
|
*/
|
||||||
virtual void escapePressed() = 0;
|
virtual void escapePressed() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called every frame, to allow updating animations if there is any need.
|
||||||
|
*/
|
||||||
virtual void onUpdate(float elpased_time) = 0;
|
virtual void onUpdate(float elpased_time) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* will be called everytime sometimes happens.
|
||||||
|
* Events are generally a widget state change. In this case, a pointer to the said widget is passed along its
|
||||||
|
* name, so you get its new state and/or act. There are two special events, passed with a NULL widget, and which
|
||||||
|
* bear the anmes "init" and "tearDown", called respectively when a screen is being made visible and when it's
|
||||||
|
* being left, allowing for setup/clean-up.
|
||||||
|
*/
|
||||||
virtual void eventCallback(Widget* widget, const std::string& name) = 0;
|
virtual void eventCallback(Widget* widget, const std::string& name) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,6 +178,20 @@ PROP_SQUARE "square_items"
|
|||||||
Valid on Ribbons or RibbonGrids. Can be "true" (omitting it means "false"). Indicates whether the contents
|
Valid on Ribbons or RibbonGrids. Can be "true" (omitting it means "false"). Indicates whether the contents
|
||||||
use rectangular icons (this will affect the type of focus/highlighting used)
|
use rectangular icons (this will affect the type of focus/highlighting used)
|
||||||
|
|
||||||
|
+--------------------------+
|
||||||
|
+ Using the Engine in Code +
|
||||||
|
+--------------------------+
|
||||||
|
|
||||||
|
The first thing to do is to derive a class of your own from AbstractStateManager. There are a few callbacks
|
||||||
|
you will need to override. Once it's done, you have all AbstractStateManager methods ready to be used to
|
||||||
|
push/pop/set menus on the screen stack.
|
||||||
|
Once you have instanciated your state manager class, call GUIEngine::init and pass it as argument.
|
||||||
|
One of the most important callbacks is 'eventCallback', which will be called everytime sometimes happens.
|
||||||
|
Events are generally a widget state change. In this case, a pointer to the said widget is passed along its
|
||||||
|
name, so you get its new state and/or act. There are two special events, passed with a NULL widget, and which
|
||||||
|
bear the anmes "init" and "tearDown", called respectively when a screen is being made visible and when it's
|
||||||
|
being left, allowing for setup/clean-up.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HEADER_ENGINE_HPP
|
#ifndef HEADER_ENGINE_HPP
|
||||||
@ -224,11 +238,8 @@ namespace GUIEngine
|
|||||||
void reshowCurrentScreen();
|
void reshowCurrentScreen();
|
||||||
|
|
||||||
void render(float dt);
|
void render(float dt);
|
||||||
|
|
||||||
void transmitEvent(Widget* widget, std::string& name);
|
void transmitEvent(Widget* widget, std::string& name);
|
||||||
|
|
||||||
|
|
||||||
void onUpdate(float elapsedTime);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,8 +34,13 @@ namespace GUIEngine
|
|||||||
class Widget;
|
class Widget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to handle irrLicht events (GUI and input as well)
|
* Class to handle irrLicht events (GUI and input as well : input events will be redirected to the input
|
||||||
* Input events will be redirected to the input module
|
* module in game mode). In menu mode, input is mapped to game actions with the help of the input
|
||||||
|
* module, then calls are made to move focus / trigger an event / etc.
|
||||||
|
*
|
||||||
|
* This is really only the irrLicht events bit, not to be confused with my own simple events dispatched
|
||||||
|
* mainly through AbstractStateManager, and also to widgets (this class is some kind of bridge between
|
||||||
|
* the base irrLicht GUI engine and the STK layer on top of it)
|
||||||
*/
|
*/
|
||||||
class EventHandler : public IEventReceiver
|
class EventHandler : public IEventReceiver
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,10 @@ using namespace gui;
|
|||||||
namespace GUIEngine
|
namespace GUIEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base irrLicht button, doesn't allow to stretch bitmaps inside it, so we "forked" it
|
||||||
|
* with a patch of our own.
|
||||||
|
*/
|
||||||
class MyGUIButton : public IGUIButton
|
class MyGUIButton : public IGUIButton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -125,7 +125,7 @@ void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
|
|||||||
left_space -= (horizontal ? widgets[n].w : widgets[n].h);
|
left_space -= (horizontal ? widgets[n].w : widgets[n].h);
|
||||||
} // next widget
|
} // next widget
|
||||||
|
|
||||||
// lay widgets in row
|
// ---- lay widgets in row
|
||||||
int x = parent->x, y = parent->y;
|
int x = parent->x, y = parent->y;
|
||||||
for(int n=0; n<widgets_amount; n++)
|
for(int n=0; n<widgets_amount; n++)
|
||||||
{
|
{
|
||||||
@ -235,6 +235,7 @@ void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
#if 0
|
#if 0
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Adding/Removing widgets
|
#pragma mark Adding/Removing widgets
|
||||||
@ -306,12 +307,13 @@ void Screen::manualAddWidget(Widget* w)
|
|||||||
{
|
{
|
||||||
m_widgets.push_back(w);
|
m_widgets.push_back(w);
|
||||||
}
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
void Screen::manualRemoveWidget(Widget* w)
|
void Screen::manualRemoveWidget(Widget* w)
|
||||||
{
|
{
|
||||||
m_widgets.remove(w);
|
m_widgets.remove(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
#if 0
|
#if 0
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Getting widgets
|
#pragma mark Getting widgets
|
||||||
|
@ -41,6 +41,12 @@ namespace GUIEngine
|
|||||||
|
|
||||||
void parseScreenFileDiv(irr::io::IrrXMLReader* xml, ptr_vector<Widget>& append_to);
|
void parseScreenFileDiv(irr::io::IrrXMLReader* xml, ptr_vector<Widget>& append_to);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single screen. Mainly responsible of its children widgets; Screen lays them
|
||||||
|
* out, asks them to add themselves, asks them to remove themselves, etc.
|
||||||
|
*
|
||||||
|
* Also initiates the read of GUI files, even though most of that work is done in "screen_loader.cpp"
|
||||||
|
*/
|
||||||
class Screen
|
class Screen
|
||||||
{
|
{
|
||||||
friend class Skin;
|
friend class Skin;
|
||||||
|
@ -33,6 +33,11 @@ using namespace io;
|
|||||||
using namespace gui;
|
using namespace gui;
|
||||||
using namespace GUIEngine;
|
using namespace GUIEngine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a GUI screen from its XML file. Builds a hierarchy of Widget objects whose
|
||||||
|
* contents are a direct transcription of the XML file, with little analysis or layout
|
||||||
|
* performed on them.
|
||||||
|
*/
|
||||||
namespace GUIEngine
|
namespace GUIEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -29,6 +29,75 @@ using namespace video;
|
|||||||
using namespace io;
|
using namespace io;
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Here lies the skin handling. It loads images and their sizing from a XML file.
|
||||||
|
Since the irrLicht way of handling skin is quite "boxy" and results in games
|
||||||
|
looking like Window 95, this class overrides it very much; in pretty much all
|
||||||
|
callbacks, rather drawing plainly what irrLicht asks it to draw, it first
|
||||||
|
checks which widget we're asked to render and redirects the call to a more
|
||||||
|
specific method.
|
||||||
|
Furthermore, since irrLicht widgets were quite basic, a few widgets were created
|
||||||
|
by combining several irrLicht widgets (e.g. 2 buttons and a label in a box make
|
||||||
|
a spinner). Because of this, some jumping through hoops is performed (we get a
|
||||||
|
callback for each of these sub-widgets, but want to draw the whole thing as a single
|
||||||
|
block)
|
||||||
|
|
||||||
|
= Rendering =
|
||||||
|
There are two types of images : some will be simply stretched as a whole, others will
|
||||||
|
have non-stretchable borders (you cannot choose which one you must use, it's hardcoded
|
||||||
|
for each element type; though, as you will see below, for all "advanced stretching" images
|
||||||
|
you can easily fake "simple stretch")
|
||||||
|
|
||||||
|
All elements will have at least 2 properties :
|
||||||
|
type="X" sets what you're skinning with this entry
|
||||||
|
image="skinDirectory/imageName.png" sets which image is used for this element
|
||||||
|
|
||||||
|
Most elements also support states :
|
||||||
|
state="neutral"
|
||||||
|
state="focused"
|
||||||
|
state="down"
|
||||||
|
You can thus give different looks for different states. Not all widgets support all states,
|
||||||
|
see entries and comments below to know what's supported.
|
||||||
|
Note that checkboxes are an exception and have the following styles :
|
||||||
|
"neutral+unchecked"
|
||||||
|
"neutral+checked"
|
||||||
|
"focused+unchecked"
|
||||||
|
"focused+checked"
|
||||||
|
|
||||||
|
"Advanced stretching" images are split this way :
|
||||||
|
|
||||||
|
+----+--------------------+----+
|
||||||
|
| | | |
|
||||||
|
+----+--------------------+----+
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
+----+--------------------+----+
|
||||||
|
| | | |
|
||||||
|
+----+--------------------+----+
|
||||||
|
|
||||||
|
The center border will be stretched in all directions. The 4 corners will not stretch at all.
|
||||||
|
Horizontal borders will stretch horizontally, verticallt borders will stretch vertically.
|
||||||
|
Use properties left_border="X" right_border="X" top_border="X" bottom_border="X" to specify
|
||||||
|
the size of each border in pixels (setting all borders to '0' makes the whole image scaled).
|
||||||
|
|
||||||
|
In some cases, you may not want vertical stretching to occur (like if the left and right sides
|
||||||
|
of the image must not be stretched vertically, e.g. for the spinner). In this case, pass
|
||||||
|
parameter preserve_h_aspect_ratios="true" to make the left and right areas stretch by keeping
|
||||||
|
their aspect ratio.
|
||||||
|
|
||||||
|
Some components may fill the full inner area with stuff; others will only take a smaller
|
||||||
|
area at the center. To adjust for this, there are properties "hborder_out_portion" and "vborder_out_portion"
|
||||||
|
that take a float from 0 to 1, representing the percentage of each border that goes out of the widget's
|
||||||
|
area (this might include stuff like shadows, etc.). The 'h' one is for horizontal borders,
|
||||||
|
the 'v' one is for vertical borders.
|
||||||
|
|
||||||
|
Finnally : the image is split, as shown above, into 9 areas. In osme cases, you may not want
|
||||||
|
all areas to be rendered. Then you can pass parameter areas="body+left+right+top+bottom"
|
||||||
|
and explicitely specify which parts you want to see. The 4 corner areas are only visible
|
||||||
|
when the border that intersect at this corner are enabled.
|
||||||
|
|
||||||
|
*/
|
||||||
namespace GUIEngine
|
namespace GUIEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -75,6 +75,18 @@ namespace GUIEngine
|
|||||||
PROP_SQUARE
|
PROP_SQUARE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The nearly-abstract base of all widgets (not fully abstract since a bare Widget
|
||||||
|
* can be created for the sore goal of containing children widgets in a group)
|
||||||
|
*
|
||||||
|
* Provides basic common functionnality, as well as providing a few callbacks
|
||||||
|
* for children to override if they need to do something special on event.
|
||||||
|
*
|
||||||
|
* Each widget may have an irrlicht parent (most often used to put widgets in dialogs)
|
||||||
|
* and also optionally one or many children.
|
||||||
|
*
|
||||||
|
* Each widget also has a set of properties stored in a ma (see enum above)
|
||||||
|
*/
|
||||||
class Widget : public SkinWidgetContainer
|
class Widget : public SkinWidgetContainer
|
||||||
{
|
{
|
||||||
friend class EventHandler;
|
friend class EventHandler;
|
||||||
@ -85,6 +97,11 @@ namespace GUIEngine
|
|||||||
friend class Skin;
|
friend class Skin;
|
||||||
friend class RibbonGridWidget;
|
friend class RibbonGridWidget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These methods provide new unique IDs each time you call them.
|
||||||
|
* Since IDs are used to determine tabbing order, "non-tabbable"
|
||||||
|
* objects are being given very different IDs so that they don't interfere.
|
||||||
|
*/
|
||||||
int getNewID();
|
int getNewID();
|
||||||
int getNewNoFocusID();
|
int getNewNoFocusID();
|
||||||
|
|
||||||
@ -111,10 +128,26 @@ namespace GUIEngine
|
|||||||
/** override in children if you need to know when the widget is focused */
|
/** override in children if you need to know when the widget is focused */
|
||||||
virtual void focused() {}
|
virtual void focused() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The XML loader stored coords in their raw string form inside this widget.
|
||||||
|
* This method parses the strings. Most notably, expands coords relative to parent
|
||||||
|
* and calculates percentages.
|
||||||
|
*/
|
||||||
void readCoords(Widget* parent=NULL);
|
void readCoords(Widget* parent=NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An irrlicht parent (most often used to put widgets in dialogs)
|
||||||
|
*/
|
||||||
IGUIElement* m_parent;
|
IGUIElement* m_parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives as string the raw property value retrieved from XML file.
|
||||||
|
* Will try to make sense of it, as an absolute value or a percentage.
|
||||||
|
*
|
||||||
|
* Return values :
|
||||||
|
* Will write to either absolute or percentage, depending on the case.
|
||||||
|
* Returns false if couldn't convert to either
|
||||||
|
*/
|
||||||
static bool convertToCoord(std::string& x, int* absolute, int* percentage);
|
static bool convertToCoord(std::string& x, int* absolute, int* percentage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,6 +155,14 @@ namespace GUIEngine
|
|||||||
*/
|
*/
|
||||||
IGUIElement* m_element;
|
IGUIElement* m_element;
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME... i forgot the m_ everywhere ... XD
|
||||||
|
|
||||||
|
/** numerical ID used by irrLicht to identify this widget
|
||||||
|
* (not the same as the string identificator specified in the XML file)
|
||||||
|
*/
|
||||||
|
int id;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* This is set to NULL by default; set to something else in a widget to mean
|
* This is set to NULL by default; set to something else in a widget to mean
|
||||||
@ -132,11 +173,20 @@ namespace GUIEngine
|
|||||||
*/
|
*/
|
||||||
Widget* m_event_handler;
|
Widget* m_event_handler;
|
||||||
|
|
||||||
|
|
||||||
|
/** Coordinates of the widget */
|
||||||
|
int x, y, w, h;
|
||||||
|
|
||||||
|
/** Whether to show a bounding box around this widget (used for sections) */
|
||||||
|
bool m_show_bounding_box;
|
||||||
|
|
||||||
|
|
||||||
Widget();
|
Widget();
|
||||||
virtual ~Widget() {}
|
virtual ~Widget() {}
|
||||||
|
|
||||||
bool m_show_bounding_box;
|
/**
|
||||||
|
* Get the underlying irrLicht GUI element, casted to the right type.
|
||||||
|
*/
|
||||||
template<typename T> T* getIrrlichtElement()
|
template<typename T> T* getIrrlichtElement()
|
||||||
{
|
{
|
||||||
#if defined(WIN32) || defined(NDEBUG)
|
#if defined(WIN32) || defined(NDEBUG)
|
||||||
@ -149,21 +199,6 @@ namespace GUIEngine
|
|||||||
|
|
||||||
IGUIElement* getIrrlichtElement() { return m_element; }
|
IGUIElement* getIrrlichtElement() { return m_element; }
|
||||||
|
|
||||||
|
|
||||||
virtual void update(float delta) { }
|
|
||||||
|
|
||||||
/** All widgets, including their parents (m_event_handler) will be notified on event through
|
|
||||||
this call. Must return whether main (GUI engine user) event callback should be notified or not.
|
|
||||||
Note that in the case of a hierarchy of widgets (with m_event_handler), only the topmost widget
|
|
||||||
of the chain decides whether the main handler is notified; return value is not read for others. */
|
|
||||||
virtual bool transmitEvent(Widget* w, std::string& originator) { return true; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and add the irrLicht widget(s) associated with this object.
|
|
||||||
* Call after Widget was read from XML file and laid out.
|
|
||||||
*/
|
|
||||||
virtual void add() {}
|
|
||||||
|
|
||||||
void setParent(IGUIElement* parent);
|
void setParent(IGUIElement* parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,16 +212,6 @@ namespace GUIEngine
|
|||||||
/** Type of this widget */
|
/** Type of this widget */
|
||||||
WidgetType m_type;
|
WidgetType m_type;
|
||||||
|
|
||||||
// FIXME... i forgot the m_ everywhere ... XD
|
|
||||||
|
|
||||||
/** coordinates of the widget */
|
|
||||||
int x, y, w, h;
|
|
||||||
|
|
||||||
/** numerical ID used by irrLicht to identify this widget
|
|
||||||
* (not the same as the string identificator specified in the XML file)
|
|
||||||
*/
|
|
||||||
int id;
|
|
||||||
|
|
||||||
/** A map that holds values for all specified widget properties (in the XML file)*/
|
/** A map that holds values for all specified widget properties (in the XML file)*/
|
||||||
std::map<Property, std::string> m_properties;
|
std::map<Property, std::string> m_properties;
|
||||||
|
|
||||||
@ -199,6 +224,25 @@ namespace GUIEngine
|
|||||||
|
|
||||||
|
|
||||||
bool isSelected() const { return m_selected; }
|
bool isSelected() const { return m_selected; }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override in children to possibly receive updates (you may need to register to
|
||||||
|
* them first)
|
||||||
|
*/
|
||||||
|
virtual void update(float delta) { }
|
||||||
|
|
||||||
|
/** All widgets, including their parents (m_event_handler) will be notified on event through
|
||||||
|
this call. Must return whether main (GUI engine user) event callback should be notified or not.
|
||||||
|
Note that in the case of a hierarchy of widgets (with m_event_handler), only the topmost widget
|
||||||
|
of the chain decides whether the main handler is notified; return value is not read for others. */
|
||||||
|
virtual bool transmitEvent(Widget* w, std::string& originator) { return true; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and add the irrLicht widget(s) associated with this object.
|
||||||
|
* Call after Widget was read from XML file and laid out.
|
||||||
|
*/
|
||||||
|
virtual void add() {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user