1) Added warp-around feature to spinners, made player ident spinners warp-around. 2) Moved GUI engine documentation from .hpp file to .cpp file, so that a documentation change doesn't trigger large re-compilations of everything 3) Formatted GUI engine documentation for Doxygen, now Doxygen will generate us a nice documentation about the GUI engine

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@5248 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2010-04-23 19:47:17 +00:00
parent a572f7bf1b
commit 183ff21c91
7 changed files with 441 additions and 215 deletions

View File

@ -15,6 +15,358 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/**
\page gui_overview GUI Module Overview
In XML files, widgets are declared in the following fashion :
\code
<widget_name property1="value1" property2="value2" />
\endcode
or, for widgets of "spawn" type, with children :
\code
<widget_name property1="value1" property2="value2" />
<child1 />
<child2 />
</widget_name>
\endcode
The first section of this document describes the widgets you can use; the second describes the properties
widgets can take. Not all properties can be applied to all widgets, see the docs for a given widget and a
given property for full information.
\section toc Table of Contents
\ref widgets
\li \ref widget1
\li \ref widget2
\li \ref widget3
\li \ref widget4
\li \ref widget5
\li \ref widget6
\li \ref widget7
\li \ref widget8
\li \ref widget9
\li \ref widget10
\li \ref widget11
\ref props
\li \ref prop1
\li \ref prop2
\li \ref prop3
\li \ref prop4
\li \ref prop5
\li \ref prop6
\li \ref prop7
\li \ref prop8
\li \ref prop9
\li \ref prop10
\li \ref prop11
\li \ref prop12
\li \ref prop13
\li \ref prop14
\li \ref prop15
\li \ref prop16
\li \ref prop17
\li \ref prop18
\ref code
\n
\n
\section widgets Widgets
This section describes the widgets you can use in STK's GUI XML files. The upper-case name starting with
WTYPE_* is the internal name of the widget (see the GUIEngine::WidgetType enum).
\subsection widget1 WTYPE_RIBBON
<em> Names in XML files: </em> \c "ribbon", \c "buttonbar", \c "tabs"
Appears as an horizontal bar containing elements laid in a row, each being and icon and/or a label
\li The "ribbon" subcategory will behave a bit like a radio button group, i.e. one element must selected.
events are triggered as soon as a choice is selected (can be simply by hovering).
\li The "buttonbar" subcategory treats children buttons as action buttons, which means they can't have a
'selected' state, only focused or not (i.e. there is no selection that remains if you leave this area).
events are triggered only on enter/fire.
\li The "tabs" subcategory will show a tab bar. behaviour is same as normal ribbon, only looks are different.
Orientation of tabs (up or down) is automatically inferred from on-screen position
\note Ribbon widgets are of spawn type (\<ribbon\> ... \</ribbon\>) and may contain icon-buttons or buttons as children.
\note Property PROP_SQUARE can be set to tell the engine if the ribbon's contents are rectangular or not (this will
affect the type of highlighting used)
\note All elements within a ribbon must have an 'ID' property
\n
\subsection widget2 WTYPE_SPINNER
Names in XML files: </em> \c "spinner", \c "gauge"
A spinner component (lets you choose numbers).
Specify PROP_MIN_VALUE and PROP_MAX_VALUE to have control over values (default will be from 0 to 10).
You can specify an icon; then, include a sprintf format string like %i in the name, and at runtime the
current number will be inserted into the given name to find the
right file for each possible value the spinner can take. It may also display arbitrary text instead of
numbers, though this cannot be achieve in the XML file; use the -\>addLabel(...) method in code to do this.
It can also display arbitrary text containing the value; just define the PROP_TEXT property to contain
the text you want, including a format string %i where the value should appear.
\note The "gauge" variant behaves similarly, but a fill band shows how close to the max the value is.
\n
\subsection widget3 WTYPE_BUTTON
<em> Name in XML files: </em> \c "button"
A plain text button.
\n
\subsection widget4 WTYPE_ICON_BUTTON
<em> Names in XML files: </em> \c "icon-button", \c "icon"
A component with an image, and optional text to go under it.
\note The "icon" variant will have no border and will not be clickable. PROP_ICON is mandatory for this component.
There are three ways to place the texture within the allocated space; the default (and only way currently accessible
through xml files) is to scale the texture to fit, while preserving its aspect ratio; other methods, currently only
accessible through C++ code, are to stretch the texture to fill the area without caring for aspect ratio, and another
to respect an aspect ratio other than the texture's (useful for track screenshots, which are 4:3 compressed to fit
in a power-of-two 256x256 texture)
\n
\subsection widget5 WTYPE_CHECKBOX
<em> Name in XML files: </em> \c "checkbox"
A checkbox.
\n
\subsection widget6 WTYPE_LABEL
<em> Names in XML files: </em> \c "label", \c "header"
A plain label.
Supports properties PROP_WORD_WRAP and PROP_TEXT_ALIGN.
\note The "Header" variant uses a bigger and more colourful font.
\n
\subsection widget7 WTYPE_SPACER
<em> Name in XML files: </em> \c "spacer"
Some blank space; not visible on screen.
\n
\subsection widget8 WTYPE_DIV
<em> Name sin XML files: </em> \c "div", \c "box"
An invisible container.
\li Divs do not do much on themselves, but are useful to lay out children automatically (Supports property PROP_LAYOUT)
\li Divs can be nested.
\li Of spawn type (\<div\>...\</div\>, place children within)
\note "box" is a variant that acts exactly the same but is visible on-screen
\n
\subsection widget9 WTYPE_DYNAMIC_RIBBON
Names in XML files: </em> \c "ribbon_grid", \c "scrollable_ribbon", \c "scrollable_toolbar"
Builds upon the basic Ribbon to be more dynamic (dynamics contents, possibly with scrolling, possibly multi-line)
\li NOT of spawn type (\<ribbon_grid .../\>), i.e. children are not specified in the XML file but
programmatically at runtime.
\li PROP_CHILD_WIDTH and PROP_CHILD_HEIGHT are mandatory (so at least aspect ratio of elements that will later be
added is known) An interesting aspect of PROP_CHILD_WIDTH and PROP_CHILD_HEIGHT is that you can use them to
show textures to any aspect ratio you want (so you can e.g. save textures to a power-of-two size like 256x256,
but then show it in 4:3 ratio).
\li Property PROP_SQUARE can be set to tell the engine if the ribbon's contents are rectangular or icons (this will
affect the type of highlighting used).
\li Supports an optional label at the bottom if PROP_LABELS_LOCATION is set (see more on PROP_LABELS_LOCATION below).
\note The "scrollable_ribbon" and "scrollable_toolbar" subtypes are single-line scrollable ribbons.
The difference between both is that 'scrollable_ribbon' always has a value selected (like in
a combo box, or radio buttons), while 'scrollable_toolbar' is a scrollable list of buttons that can be
pressed to trigger actions.
\n
\subsection widget10 WTYPE_MODEL_VIEW
<em> Name in XML files: </em> \c "model"
Displays a 3D model.
\note Contents must be set programmatically.
\n
\subsection widget11 WTYPE_LIST
<em> Name in XML files: </em> \c "list"
Displays a list.
\note Contents must be set programmatically.
\n
\n
\section props Properties
\subsection prop1 PROP_ID
<em> Name in XML files: </em> \c "id"
Gives a unique internal name to each object using this property. It will be
used in events callbacks to determine what action occurred. Can be omitted
on components that do not trigger events (e.g. labels)
\n
\subsection prop2 PROP_TEXT
<em> Name in XML files: </em> \c "text"
gives text (a label) to the widget where supported. Ribbon-grids give a special meaning
to this parameter, see ribbon-grid docs above.
\n
\subsection prop3 PROP_ICON
<em> Name in XML files: </em> \c "icon"
give an icon to the widget. Property contents is the path to the file, by default relative
relative to the /data directory of STK (several methods of IconButtonWidget and DynamicRibbon
can enable you to use absolute paths if you wish, however).
\n
\subsection prop4 PROP_TEXT_ALIGN
<em> Name in XML files: </em> \c "text_align"
used exclusively by label components. Value can be "right" or "center" (left used if not specified).
\n
\subsection prop5 PROP_WORD_WRAP
<em> Name in XML files: </em> \c "word_wrap"
used exclusively by label components. Value can be "true" to indicate that long text should spawn on
multiple lines.
\n
\subsection prop6 PROP_MIN_VALUE, PROP_MAX_VALUE
<em> Name in XML files: </em> \c "min_value", \c "max_value"
used to specify a minimum and maximum value for numeric widgets (c.f. spinner)
\n
\subsection prop7 PROP_X, PROP_Y
<em> Name in XML files: </em> \c "x", "y"
sets the position (location) of a widget, relative to its parent (container \<div\> or screen if none).
A plain number will be interpreted as an aabsolute position in pixels. A '%' sign may be added to the
given number to mean that the location is specified in terms of a percentage of parent size (parent size
means the parent \<div\> or the whole screen if none). A negative value can also be passed to start coordinate
from right and/or bottom, instead of starting from top-left corner as usual.
Note that in many cases, it is not necessary to manually a position. Div layouts will often manage that
for you (see PROP_LAYOUT). Other widgets will also automativally manage the position and size of their children,
for instance ribbons.
\n
\subsection prop8 PROP_WIDTH, PROP_HEIGHT
<em> Name in XML files: </em> \c "width", \c "height"
give dimensions to the widget. A plain number will be interpreted as an aabsolute position in pixels.
A '%' sign may be added to the given number to mean that the size is specified in terms of a percentage
of parent size (parent size means the parent \<div\> or the whole screen if none).
Note that in many cases, it is not necessary to manually a size. Div layouts will often manage that
for you (see PROP_LAYOUT). In addition, sizes are automatically calculated for widgets made of icons
and/or text like labels and plain icons. Other widgets will also automativally manage the position and
size of their children, for instance ribbons.
\n
\subsection prop9 PROP_MAX_WIDTH, PROP_MAX_HEIGHT
<em> Names in XML files: </em> \c "max_width", \c "max_height"
The maximum size a widget can take; especially useful when using percentages and proportions.
\n
\subsection prop10 PROP_CHILD_WIDTH, PROP_CHILD_HEIGHT
<em> Names in XML files: </em> \c "child_width", \c "child_height"
Used exclusively by the ribbon grid widget. See docs for this widget above.
\n
\subsection prop11 PROP_LAYOUT
<em> Name in XML files: </em> \c "layout"
Valid on 'div' containers. Value can be "horizontal-row" or "vertical-row". This means x and y coordinates
of all children will automatically be calculated at runtime, so they are laid in a row. Width and height can
be set absolutely as usual, but can also be determined dynamically according to available screen space. Also
see PROP_ALIGN and PROP_PROPORTION to known more about controlling layouts. Note that all components within a
layed-out div will ignore all x/y coordinates you may give them as parameter.
\n
\subsection prop12 PROP_ALIGN
<em> Name in XML files: </em> \c "align"
For widgets located inside a vertical-row layout div : Changes how the x coord of the widget is determined.
value can be "left", "center" or "right".
For widgets located inside a horizontal-row layout div : Changes how the y coord of the widget is determined.
value can be "top", "center" or "bottom".
\n
\subsection prop13 PROP_PROPORTION
<em> Name in XML files: </em> \c "proportion"
Helps determining widget size dynamically (according to available screen space) in layed-out divs. In a
vertical row layout, proportion sets the height of the item. In an horizontal row, it sets the width of
the item. Proportions are always evaluated relative to the proportions of other widgets in the same div.
If one div contains 4 widgets, and their proportions are 1-2-1-1, it means the second must take twice as
much space as the 3 others. In this case, 10-20-10-10 would do the exact same effect. 1-1-1-1 would mean
all take 1/4 of the available space. Note that it is allowed to mix absolute widget sizes and proportions;
in this case, widgets with absolute size are evaluated first, and the dynamically-sized ones split the
remaining space according to their proportions.
\n
\subsection prop14 PROP_SQUARE
<em> Name in XML files: </em> \c "square_items"
Valid on Ribbons or RibbonGrids. Can be "true" (omitting it means "false"). Indicates whether the contents
use rectangular icons as opposed to "round" icons (this will affect the type of focus/highlighting used)
\n
\subsection prop15 PROP_EXTEND_LABEL
<em> Name in XML files: </em> \c "extend_label"
How many pixels the label is allowed to expand beyond the boundaries of the widget itself. Currently only
allowed on icon widgets.
\n
\subsection prop16 PROP_LABELS_LOCATION
<em> Name in XML files: </em> \c "label_location"
Currently only used by dynamic ribbons. Decides where the label is. Value can be "each", "bottom", or "none"
(if ommitted, "none" is the default). "each" means that every item has its own label. "bottom" means there
is a single label for all at the bottom, that displays the name of the current item.
\n
\subsection prop17 PROP_MAX_ROWS
<em> Name in XML files: </em> \c "max_rows"
Currently used for ribbon grids only. Indicates the maximum amount of rows this ribbon can have.
\n
\subsection prop18 PROP_WARP_AROUND
<em> Name in XML files: </em> \c "warp_around"
Currently used for spinners only. Value can be "true" or "false"
\n
\section code 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.
*/
#include "guiengine/engine.hpp" #include "guiengine/engine.hpp"

View File

@ -16,208 +16,6 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*
+---------+
+ Widgets +
+---------+
_______________________________________________________
Internal constant Name in XML files
_______________________________________________________
WTYPE_RIBBON "ribbon", "buttonbar", "tabs"
appears an horizontal bar containing elements laid in a row, each being and icon and/or a label
the "ribbon" subcategory will behave a bit like a radio button group, i.e. one element must selected.
events are triggered as soon as a choice is selected (can be simply by hovering).
the "buttonbar" subcategory treats children buttons as action buttons, which means they can't have a
'selected' state, only focused or not (i.e. there is no selection that remains if you leave this area).
events are triggered only on enter/fire.
the "tabs" subcategory will show a tab bar. behaviour is same as normal ribbon, only looks are different.
Orientation of tabs (up or down) is automatically inferred from on-screen position
Ribbon widgets are of spawn type (<ribbon> ... </ribbon>) and may contain icon-buttons or buttons as children.
Property PROP_SQUARE can be set to tell the engine if the ribbon's contents are rectangular or not (this will
affect the type of highlighting used)
* Note : all elements within a ribbon must have an 'ID' property
WTYPE_SPINNER "spinner", "gauge"
A spinner component (lets you choose numbers). Sprecify PROP_MIN_VALUE and PROP_MAX_VALUE to have control
over values (default will be from 0 to 10). You can specify an icon; then, include a sprintf format string
like %i in the name, and at runtime the current number will be inserted into the given name to find the
right file for each possible value the spinner can take. It may also display arbitrary text instead of
numbers, though this cannot be achieve in the XML file; use the ->addLabel(...) method in code to do this.
It can also display arbitrary text containing the value; just define the PROP_TEXT property to contain
the text you want, including a format string %i where the value should appear.
The "gauge" variant behaves similarly, but a fill band shows how close to the max the value is.
WTYPE_BUTTON "button"
A plain text buttons.
WTYPE_ICON_BUTTON "icon-button", "icon"
A component with an image, and optional text to go under it. The "icon" variant will have no border and will not
be clickable. PROP_ICON is mandatory for this component.
There are three ways to place the texture within the allocated space; the default (and only way currently accessible
through xml files) is to scale the texture to fit, while preserving its aspect ratio; other methods, currently only
accessible through C++ code, are to stretch the texture to fill the area without caring for aspect ratio, and another
to respect an aspect ratio other than the texture's (useful for track screenshots, which are 4:3 compressed to fit
in a power-of-two 256x256 texture)
WTYPE_CHECKBOX "checkbox"
A checkbox. Not used at the moment.
WTYPE_LABEL "label" "header"
A plain label. Supports properties PROP_WORD_WRAP and PROP_TEXT_ALIGN.
The "Header" variant uses a bigger and more colourful font.
WTYPE_SPACER "spacer"
Some blank space; not visible on screen.
WTYPE_DIV "div", "box"
A container. Does not do much on itself, but is useful to lay out children automatically. Divs can be nested.
Supports property PROP_LAYOUT. Of spawn type (<div>...</div>, place children within)
"box" is a variant that acts exactly the same but is visible on-screen
WTYPE_DYNAMIC_RIBBON "ribbon_grid", "scrollable_ribbon", "scrollable_toolbar"
Builds upon the basic Ribbon to be more dynamic (dynamics contents, possibly with scrolling, possibly multi-line)
NOT of spawn type (<ribbon_grid .../>), contents must be programmatically set at runtime.
Property PROP_SQUARE can be set to tell the engine if the ribbon's contents are rectangular or icons (this will
affect the type of highlighting used).
PROP_CHILD_WIDTH and PROP_CHILD_HEIGHT are mandatory (so at least aspect ratio of elements that will later be
added is known) An interesting aspect of PROP_CHILD_WIDTH and PROP_CHILD_HEIGHT is that you can use them to
show textures to any aspect ratio you want (so you can e.g. save textures to a power-of-two size like 256x256,
but then show it in 4:3 ratio).
Supports an optional label at the bottom if PROP_LABELS_LOCATION is set (see more on PROP_LABELS_LOCATION below).
The "scrollable_ribbon" and "scrollable_toolbar" subtypes are single-line
scrollable ribbons. The difference between both is that 'scrollable_ribbon' always has a value selected (like in
a combo box, or radio buttons), while 'scrollable_toolbar' is a scrollable list of buttons that can be pressed to
trigger actions.
WTYPE_MODEL_VIEW "model"
Displays a model. Currently incomplete. Contents must be set programmatically.
WTYPE_LIST "list"
Displays a list. Currently incomplete. Contents must be set programmatically.
+------------+
+ Properties +
+------------+
_______________________________________________________
Internal constant Name in XML files
_______________________________________________________
PROP_ID "id"
gives a unique internal name to each object using this property. It will be
used in events callbacks to determine what action occurred. Can be omitted
on components that do not trigger events (e.g. labels)
PROP_TEXT "text"
gives text (a label) to the widget where supported. Ribbon-grids give a special meaning
to this parameter, see ribbon-grid docs above.
PROP_ICON "icon"
give an icon to the widget. Property contents is the path to the file, by default relative
relative to the /data directory of STK (several methods of IconButtonWidget and DynamicRibbon
can enable you to use absolute paths if you wish).
PROP_TEXT_ALIGN "text_align"
used exclusively by label components. Value can be "right" or "center" (left used if not specified).
PROP_WORD_WRAP "word_wrap"
used exclusively by label components. Value can be "true" to indicate that long text should spawn on
multiple lines.
PROP_MIN_VALUE "min_value"
PROP_MAX_VALUE "max_value"
used to specify a minimum and maximum value for numeric widgets (c.f. spinner)
PROP_X "x"
PROP_Y "y"
sets the position (location) of a widget, relative to its parent (container <div> or screen if none).
A plain number will be interpreted as an aabsolute position in pixels. A '%' sign may be added to the
given number to mean that the location is specified in terms of a percentage of parent size (parent size
means the parent <div> or the whole screen if none). A negative value can also be passed to start coordinate
from right and/or bottom, instead of starting from top-left corner as usual.
Note that in many cases, it is not necessary to manually a position. Div layouts will often manage that
for you (see PROP_LAYOUT). Other widgets will also automativally manage the position and size of their children,
for instance ribbons.
PROP_WIDTH "width"
PROP_HEIGHT "height"
give dimensions to the widget. A plain number will be interpreted as an aabsolute position in pixels.
A '%' sign may be added to the given number to mean that the size is specified in terms of a percentage
of parent size (parent size means the parent <div> or the whole screen if none).
Note that in many cases, it is not necessary to manually a size. Div layouts will often manage that
for you (see PROP_LAYOUT). In addition, sizes are automatically calculated for widgets made of icons
and/or text like labels and plain icons. Other widgets will also automativally manage the position and
size of their children, for instance ribbons.
PROP_MAX_WIDTH "max_width"
PROP_MAX_HEIGHT "max_height"
The maximum size a widget can take; especially useful when using percentages and proportions.
PROP_CHILD_WIDTH "child_width"
PROP_CHILD_HEIGHT "child_height"
Used exclusively by the ribbon grid widget. See docs for this widget above.
PROP_GROW_WITH_TEXT "grow_with_text"
Reserved, but currently unimplemented and unused.
PROP_LAYOUT "layout"
Valid on 'div' containers. Value can be "horizontal-row" or "vertical-row". This means x and y coordinates
of all children will automatically be calculated at runtime, so they are laid in a row. Width and height can
be set absolutely as usual, but can also be determined dynamically according to available screen space. Also
see PROP_ALIGN and PROP_PROPORTION to known more about controlling layouts. Note that all components within a
layed-out div will ignore all x/y coordinates you may give them as parameter.
PROP_ALIGN "align"
For widgets located inside a vertical-row layout div : Changes how the x coord of the widget is determined.
value can be "left", "center" or "right".
For widgets located inside a horizontal-row layout div : Changes how the y coord of the widget is determined.
value can be "top", "center" or "bottom".
PROP_PROPORTION "proportion"
Helps determining widget size dynamically (according to available screen space) in layed-out divs. In a
vertical row layout, proportion sets the height of the item. In an horizontal row, it sets the width of
the item. Proportions are always evaluated relative to the proportions of other widgets in the same div.
If one div contains 4 widgets, and their proportions are 1-2-1-1, it means the second must take twice as
much space as the 3 others. In this case, 10-20-10-10 would do the exact same effect. 1-1-1-1 would mean
all take 1/4 of the available space. Note that it is allowed to mix absolute widget sizes and proportions;
in this case, widgets with absolute size are evaluated first, and the dynamically-sized ones split the
remaining space according to their proportions.
PROP_SQUARE "square_items"
Valid on Ribbons or RibbonGrids. Can be "true" (omitting it means "false"). Indicates whether the contents
use rectangular icons as opposed to "round" icons (this will affect the type of focus/highlighting used)
PROP_EXTEND_LABEL "extend_label"
How many pixels the label is allowed to expand beyond the boundaries of the widget itself. Currently only
allowed on icon widgets.
PROP_LABELS_LOCATION "label_location"
Currently only used by dynamic ribbons. Decides where the label is. Value can be "each", "bottom", or "none"
(if ommitted, "none" is the default). "each" means that every item has its own label. "bottom" means there
is a single label for all at the bottom, that displays the name of the current item.
PROP_MAX_ROWS "max_rows"
Currently used for ribbon grids only. Indicates the maximum amount of rows this ribbon can have.
+--------------------------+
+ 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
#define HEADER_ENGINE_HPP #define HEADER_ENGINE_HPP

View File

@ -166,7 +166,7 @@ if(prop_name != NULL) widget.m_properties[prop_flag] = prop_name; else widget.m_
READ_PROPERTY(child_width, PROP_CHILD_WIDTH); READ_PROPERTY(child_width, PROP_CHILD_WIDTH);
READ_PROPERTY(child_height, PROP_CHILD_HEIGHT); READ_PROPERTY(child_height, PROP_CHILD_HEIGHT);
READ_PROPERTY(word_wrap, PROP_WORD_WRAP); READ_PROPERTY(word_wrap, PROP_WORD_WRAP);
READ_PROPERTY(grow_with_text, PROP_GROW_WITH_TEXT); //READ_PROPERTY(grow_with_text, PROP_GROW_WITH_TEXT);
READ_PROPERTY(x, PROP_X); READ_PROPERTY(x, PROP_X);
READ_PROPERTY(y, PROP_Y); READ_PROPERTY(y, PROP_Y);
READ_PROPERTY(layout, PROP_LAYOUT); READ_PROPERTY(layout, PROP_LAYOUT);
@ -183,6 +183,7 @@ if(prop_name != NULL) widget.m_properties[prop_flag] = prop_name; else widget.m_
READ_PROPERTY(extend_label, PROP_EXTEND_LABEL); READ_PROPERTY(extend_label, PROP_EXTEND_LABEL);
READ_PROPERTY(label_location, PROP_LABELS_LOCATION); READ_PROPERTY(label_location, PROP_LABELS_LOCATION);
READ_PROPERTY(max_rows, PROP_MAX_ROWS); READ_PROPERTY(max_rows, PROP_MAX_ROWS);
READ_PROPERTY(warp_around, PROP_WARP_AROUND);
#undef READ_PROPERTY #undef READ_PROPERTY
const char* text = xml->getAttributeValue( "text" ); const char* text = xml->getAttributeValue( "text" );

View File

@ -65,7 +65,7 @@ namespace GUIEngine
PROP_CHILD_WIDTH, PROP_CHILD_WIDTH,
PROP_CHILD_HEIGHT, PROP_CHILD_HEIGHT,
PROP_WORD_WRAP, PROP_WORD_WRAP,
PROP_GROW_WITH_TEXT, // yet unused //PROP_GROW_WITH_TEXT, // yet unused
PROP_X, PROP_X,
PROP_Y, PROP_Y,
PROP_LAYOUT, PROP_LAYOUT,
@ -80,7 +80,8 @@ namespace GUIEngine
PROP_SQUARE, PROP_SQUARE,
PROP_EXTEND_LABEL, PROP_EXTEND_LABEL,
PROP_LABELS_LOCATION, PROP_LABELS_LOCATION,
PROP_MAX_ROWS PROP_MAX_ROWS,
PROP_WARP_AROUND
}; };
bool isWithinATextBox(); bool isWithinATextBox();
@ -127,12 +128,19 @@ namespace GUIEngine
bool m_check_inside_me; bool m_check_inside_me;
/** /**
* called when left/right keys pressed and focus is on widget. * called when right key is pressed and focus is on widget.
* Returns 'EVENT_LET' if user's event handler should be notified of a change. * Returns 'EVENT_LET' if user's event handler should be notified of a change.
* Override in children to be notified of left/right events and/or make * Override in children to be notified of left/right events and/or make
* the event propagate to the user's event handler. * the event propagate to the user's event handler.
*/ */
virtual EventPropagation rightPressed(const int playerID) { return EVENT_BLOCK; } virtual EventPropagation rightPressed(const int playerID) { return EVENT_BLOCK; }
/**
* called when left key is pressed and focus is on widget.
* Returns 'EVENT_LET' if user's event handler should be notified of a change.
* Override in children to be notified of left/right events and/or make
* the event propagate to the user's event handler.
*/
virtual EventPropagation leftPressed (const int playerID) { return EVENT_BLOCK; } virtual EventPropagation leftPressed (const int playerID) { return EVENT_BLOCK; }
/** used when you set eventSupervisors - see m_event_handler explainations below /** used when you set eventSupervisors - see m_event_handler explainations below

View File

@ -36,6 +36,7 @@ SpinnerWidget::SpinnerWidget(const bool gauge) : Widget(WTYPE_SPINNER)
m_check_inside_me = true; //FIXME: not sure this is necessary m_check_inside_me = true; //FIXME: not sure this is necessary
m_supports_multiplayer = true; m_supports_multiplayer = true;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -46,6 +47,9 @@ void SpinnerWidget::add()
std::string min_s = m_properties[PROP_MIN_VALUE]; std::string min_s = m_properties[PROP_MIN_VALUE];
std::string max_s = m_properties[PROP_MAX_VALUE]; std::string max_s = m_properties[PROP_MAX_VALUE];
m_warp_around = (m_properties[PROP_WARP_AROUND] == "true");
std::cout << "SpinnerWidget::add() : m_warp_around=" << m_warp_around << " (" << m_properties[PROP_WARP_AROUND].c_str() << ")"<< std::endl;
{ {
int i; int i;
std::istringstream myStream(min_s); std::istringstream myStream(min_s);
@ -195,7 +199,14 @@ EventPropagation SpinnerWidget::rightPressed(const int playerID)
if (m_deactivated) return EVENT_BLOCK; if (m_deactivated) return EVENT_BLOCK;
//std::cout << "Right pressed\n"; //std::cout << "Right pressed\n";
if (m_value+1 <= m_max) setValue(m_value+1); if (m_value+1 <= m_max)
{
setValue(m_value+1);
}
else if (m_warp_around)
{
setValue(m_min);
}
//GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID ); //GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID );
@ -210,7 +221,14 @@ EventPropagation SpinnerWidget::leftPressed(const int playerID)
if (m_deactivated) return EVENT_BLOCK; if (m_deactivated) return EVENT_BLOCK;
//std::cout << "Left pressed\n"; //std::cout << "Left pressed\n";
if (m_value-1 >= m_min) setValue(m_value-1); if (m_value-1 >= m_min)
{
setValue(m_value-1);
}
else if (m_warp_around)
{
setValue(m_max);
}
//GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID ); //GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID );

View File

@ -31,13 +31,30 @@ namespace GUIEngine
class SpinnerWidget : public Widget class SpinnerWidget : public Widget
{ {
int m_value, m_min, m_max; int m_value, m_min, m_max;
/** If each value the spinner can take has an associated text, this vector will be non-empty */
std::vector<irr::core::stringw> m_labels; std::vector<irr::core::stringw> m_labels;
/** Whether the value of this spinner is displayed using an icon rather than with a plain label */
bool m_graphical; bool m_graphical;
/** \brief Whether this widget is a gauge
* the behaviour is the same but the look is a bit different, instead of displaying a number,
* it displays how close the value is to the maximum by filling a line
*/
bool m_gauge; bool m_gauge;
EventPropagation transmitEvent(Widget* w, std::string& originator, const int playerID); /** \brief Whether to warp back to the first value when going "beyond" the last value */
EventPropagation rightPressed(const int playerID); bool m_warp_around;
EventPropagation leftPressed(const int playerID);
/** \brief implementing method from base class Widget */
virtual EventPropagation transmitEvent(Widget* w, std::string& originator, const int playerID);
/** \brief implementing method from base class Widget */
virtual EventPropagation rightPressed(const int playerID);
/** \brief implementing method from base class Widget */
virtual EventPropagation leftPressed(const int playerID);
/** When inferring widget size from its label length, this method will be called to /** When inferring widget size from its label length, this method will be called to
* if/how much space must be added to the raw label's size for the widget to be large enough */ * if/how much space must be added to the raw label's size for the widget to be large enough */
@ -58,19 +75,49 @@ namespace GUIEngine
void addLabel(irr::core::stringw label); void addLabel(irr::core::stringw label);
void clearLabels(); void clearLabels();
irr::core::stringw getStringValue() const;
void add(); /** \brief implement method from base class Widget */
void setValue(const int new_value); virtual void add();
/** /**
* @precondition the 'new_value' string passed must be the name of an item in the spinner * \brief sets the current value of the spinner
* \param new_value the new value that will be become the current value of this spinner.
*/
void setValue(const int new_value);
/**
* \brief sets the current value of the spinner
* \precondition the 'new_value' string passed must be the name of an item
* (added through SpinnerWidget::addLabel)in the spinner
*/ */
void setValue(irr::core::stringw new_value); void setValue(irr::core::stringw new_value);
/**
* \return whether this spinner is of "gauge" type
*/
bool isGauge() const { return m_gauge; } bool isGauge() const { return m_gauge; }
/**
* \brief retrieve the current value of the spinner
* \return the current value of the spinner, in a int form
*/
int getValue() const { return m_value; } int getValue() const { return m_value; }
/**
* \brief retrieve the current value of the spinner
* \return the current value of the spinner, in a string form
*/
irr::core::stringw getStringValue() const;
/**
* \return the maximum value the spinner can take
*/
int getMax() const { return m_max; } int getMax() const { return m_max; }
/**
* \return the minimum value the spinner can take
*/
int getMin() const { return m_min; } int getMin() const { return m_min; }
}; };

View File

@ -269,6 +269,8 @@ public:
playerName->m_properties[PROP_MIN_VALUE] = "0"; playerName->m_properties[PROP_MIN_VALUE] = "0";
playerName->m_properties[PROP_MAX_VALUE] = (playerAmount-1); playerName->m_properties[PROP_MAX_VALUE] = (playerAmount-1);
playerName->m_properties[PROP_ID] = spinnerID; playerName->m_properties[PROP_ID] = spinnerID;
playerName->m_properties[PROP_WARP_AROUND] = "true";
//playerName->m_event_handler = this; //playerName->m_event_handler = this;
m_children.push_back(playerName); m_children.push_back(playerName);