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();
|
||||
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;
|
||||
|
||||
/**
|
||||
* Called every frame, to allow updating animations if there is any need.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -178,6 +178,20 @@ PROP_SQUARE "square_items"
|
||||
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)
|
||||
|
||||
+--------------------------+
|
||||
+ 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
|
||||
@ -224,11 +238,8 @@ namespace GUIEngine
|
||||
void reshowCurrentScreen();
|
||||
|
||||
void render(float dt);
|
||||
|
||||
void transmitEvent(Widget* widget, std::string& name);
|
||||
|
||||
|
||||
void onUpdate(float elapsedTime);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -34,8 +34,13 @@ namespace GUIEngine
|
||||
class Widget;
|
||||
|
||||
/**
|
||||
* Class to handle irrLicht events (GUI and input as well)
|
||||
* Input events will be redirected to the input module
|
||||
* Class to handle irrLicht events (GUI and input as well : input events will be redirected to the input
|
||||
* 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
|
||||
{
|
||||
|
@ -13,6 +13,10 @@ using namespace gui;
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -125,7 +125,7 @@ void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
|
||||
left_space -= (horizontal ? widgets[n].w : widgets[n].h);
|
||||
} // next widget
|
||||
|
||||
// lay widgets in row
|
||||
// ---- lay widgets in row
|
||||
int x = parent->x, y = parent->y;
|
||||
for(int n=0; n<widgets_amount; n++)
|
||||
{
|
||||
@ -235,6 +235,7 @@ void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#if 0
|
||||
#pragma mark -
|
||||
#pragma mark Adding/Removing widgets
|
||||
@ -306,12 +307,13 @@ void Screen::manualAddWidget(Widget* w)
|
||||
{
|
||||
m_widgets.push_back(w);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void Screen::manualRemoveWidget(Widget* w)
|
||||
{
|
||||
m_widgets.remove(w);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#if 0
|
||||
#pragma mark -
|
||||
#pragma mark Getting widgets
|
||||
|
@ -41,6 +41,12 @@ namespace GUIEngine
|
||||
|
||||
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
|
||||
{
|
||||
friend class Skin;
|
||||
|
@ -33,6 +33,11 @@ using namespace io;
|
||||
using namespace gui;
|
||||
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
|
||||
{
|
||||
|
||||
|
@ -29,6 +29,75 @@ using namespace video;
|
||||
using namespace io;
|
||||
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
|
||||
{
|
||||
|
||||
|
@ -75,6 +75,18 @@ namespace GUIEngine
|
||||
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
|
||||
{
|
||||
friend class EventHandler;
|
||||
@ -85,6 +97,11 @@ namespace GUIEngine
|
||||
friend class Skin;
|
||||
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 getNewNoFocusID();
|
||||
|
||||
@ -111,10 +128,26 @@ namespace GUIEngine
|
||||
/** override in children if you need to know when the widget is 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);
|
||||
|
||||
/**
|
||||
* An irrlicht parent (most often used to put widgets in dialogs)
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
@ -122,6 +155,14 @@ namespace GUIEngine
|
||||
*/
|
||||
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:
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
||||
/** 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();
|
||||
virtual ~Widget() {}
|
||||
|
||||
bool m_show_bounding_box;
|
||||
|
||||
/**
|
||||
* Get the underlying irrLicht GUI element, casted to the right type.
|
||||
*/
|
||||
template<typename T> T* getIrrlichtElement()
|
||||
{
|
||||
#if defined(WIN32) || defined(NDEBUG)
|
||||
@ -149,21 +199,6 @@ namespace GUIEngine
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
@ -177,16 +212,6 @@ namespace GUIEngine
|
||||
/** Type of this widget */
|
||||
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)*/
|
||||
std::map<Property, std::string> m_properties;
|
||||
|
||||
@ -199,6 +224,25 @@ namespace GUIEngine
|
||||
|
||||
|
||||
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