Added support for selecting GUI skin through user interface; aded skins by Dakal as a proof it works

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@5442 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2010-05-15 18:10:55 +00:00
parent dd0caa5f0a
commit 5cddb8ffb6
73 changed files with 949 additions and 348 deletions

View File

@ -18,8 +18,14 @@
<box proportion="1" width="100%" layout="vertical-row">
<spacer height="20" width="10"/>
<label width="100%" I18N="In the graphics settings" text="Skin"/>
<!-- FIXME: don't hardcode size -->
<spinner id="skinchoice" width="300" height="50" />
<spacer height="40" width="10"/>
<label width="100%" I18N="In the graphics settings" text="Resolution"/>
<scrollable_ribbon id="resolutions" proportion="2" label_location="each"
width="100%" square_items="false"

View File

@ -0,0 +1,193 @@
<!--
Ocean skin by Dakal and Marianne Gagnon, released under creative-commons BY-SA 3.0+
Except background.jpg, by elisee
To make your own skin, I suggest simply duplicating this file and modifying it as needed.
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.
-->
<skin name="Ocean" author="Dakal & Marianne Gagnon (Auria)">
<!-- Stateless -->
<element type="background" image="ocean/background.jpg" />
<element type="button" state="focused" image="ocean/glassbutton_focused.png"
left_border="80" right_border="80" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" />
<element type="button" state="neutral" image="ocean/glassbutton.png"
left_border="80" right_border="80" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" />
<!-- TODO : buttons could support 'pressed' state -->
<element type="tab" state="neutral" image="ocean/glasstab.png"
left_border="75" right_border="75" top_border="0" bottom_border="15"
hborder_out_portion="0.2" />
<element type="tab" state="focused" image="ocean/glasstab_focus.png"
left_border="75" right_border="75" top_border="0" bottom_border="15"
hborder_out_portion="0.2" />
<element type="tab" state="down" image="ocean/glasstab_down.png"
left_border="75" right_border="75" top_border="0" bottom_border="15"
hborder_out_portion="0.2" />
<!-- Stateless -->
<element type="squareFocusHalo" image="ocean/glass_square_focused.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<element type="squareFocusHalo2" image="ocean/glass_square_focused2.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<element type="squareFocusHalo3" image="ocean/glass_square_focused3.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<element type="squareFocusHalo4" image="ocean/glass_square_focused4.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<!-- Stateless. No splitting into 9 areas is done; the image is just resized. -->
<element type="selectionHalo" image="ocean/bubble.png" />
<element type="focusHalo" image="ocean/glass_iconhighlight_focus.png" />
<element type="spinner" state="neutral" image="ocean/glassspinner.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner" state="focused" image="ocean/glassspinner_focus.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner2" state="neutral" image="ocean/glassspinner2.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner2" state="focused" image="ocean/glassspinner2_focus.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<!-- This one is a bit special. Only area(s) LEFT and/or RIGHT will be rendered. They will be overlaid
on top of the spinner's background -->
<element type="spinner" state="down" image="ocean/glassspinner_down.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner2" state="down" image="ocean/glassspinner2_down.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<!-- For checkboxes, no splitting into 9 areas is done; the image is just stretched -->
<element type="checkbox" state="neutral+unchecked" image="ocean/glasscheckbox.png"/>
<element type="checkbox" state="neutral+checked" image="ocean/glasscheckbox_checked.png"/>
<element type="checkbox" state="focused+unchecked" image="ocean/glasscheckbox_focus.png"/>
<element type="checkbox" state="focused+checked" image="ocean/glasscheckbox_checked_focus.png"/>
<!-- are always in neutral state for now. No splitting into 9 areas is done; the image is just stretched.
Note: the body of a guage is the same as for for spinners. -->
<element type="gaugefill" image="ocean/glasssgauge_fill.png" />
<!-- Lists are always in neutral state for now -->
<element type="list" image="ocean/glass_section.png"
left_border="15" right_border="15" top_border="15" bottom_border="15"
hborder_out_portion="0.5" vborder_out_portion="1.0" />
<element type="listitem" state="focused" image="ocean/select.png"
left_border="0" right_border="0" top_border="0" bottom_border="0"
hborder_out_portion="0.0" vborder_out_portion="0.0" />
<element type="listitem" state="down" image="ocean/glassbutton.png"
left_border="80" right_border="80" top_border="0" bottom_border="36"
hborder_out_portion="1.0" vborder_out_portion="1.0"
areas="body" />
<!-- Scrollbars. Background and thumb have no state (always neutral state).
The buttons are the top and bottom arrows. Image must be top arrow, will
be mirrorred for bottom. Buttons can be in neutral or down state.
Advanced stretching is not used here.
-->
<element type="scrollbar_background" image="ocean/scrollbar_bg.png" />
<element type="scrollbar_thumb" image="ocean/scrollbar_thumb.png" />
<element type="scrollbar_button" image="ocean/scrollbar_btn.png" />
<element type="scrollbar_button" state="down" image="ocean/scrollbar_btn_down.png" />
<!-- Stateless -->
<element type="section" image="ocean/glass_section.png"
left_border="15" right_border="15" top_border="15" bottom_border="15"
hborder_out_portion="1.0" vborder_out_portion="0.2" />
<!-- Stateless -->
<element type="window" image="ocean/dialog.png"
left_border="7" right_border="7" top_border="50" bottom_border="50"
hborder_out_portion="1.0" vborder_out_portion="0.2" />
<!-- Colors -->
<color type="text" state="neutral" r="0" g="0" b="0" />
<!-- For highlighted items, e.g. in list -->
<color type="text" state="focused" r="255" g="255" b="255" />
<!-- Color used to fade out background when a dialog is shown -->
<color type="dialog_background" state="neutral" a="120" r="0" g="0" b="0" />
<!-- Text field color -->
<color type="text_field" state="neutral" a="255" r="215" g="215" b="215" />
<color type="text_field" state="focused" a="255" r="138" g="138" b="138" />
</skin>

View File

@ -0,0 +1,193 @@
<!--
Peach skin by Dakal and Marianne Gagnon, released under creative-commons BY-SA 3.0+
Except background.jpg, by elisee
To make your own skin, I suggest simply duplicating this file and modifying it as needed.
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.
-->
<skin name="Peach" author="Dakal & Marianne Gagnon (Auria)">
<!-- Stateless -->
<element type="background" image="peach/background.jpg" />
<element type="button" state="focused" image="peach/glassbutton_focused.png"
left_border="80" right_border="80" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" />
<element type="button" state="neutral" image="peach/glassbutton.png"
left_border="80" right_border="80" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" />
<!-- TODO : buttons could support 'pressed' state -->
<element type="tab" state="neutral" image="peach/glasstab.png"
left_border="75" right_border="75" top_border="0" bottom_border="15"
hborder_out_portion="0.2" />
<element type="tab" state="focused" image="peach/glasstab_focus.png"
left_border="75" right_border="75" top_border="0" bottom_border="15"
hborder_out_portion="0.2" />
<element type="tab" state="down" image="peach/glasstab_down.png"
left_border="75" right_border="75" top_border="0" bottom_border="15"
hborder_out_portion="0.2" />
<!-- Stateless -->
<element type="squareFocusHalo" image="peach/glass_square_focused.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<element type="squareFocusHalo2" image="peach/glass_square_focused2.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<element type="squareFocusHalo3" image="peach/glass_square_focused3.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<element type="squareFocusHalo4" image="peach/glass_square_focused4.png"
left_border="6" right_border ="6" top_border="6" bottom_border="6"
hborder_out_portion="1.0" />
<!-- Stateless. No splitting into 9 areas is done; the image is just resized. -->
<element type="selectionHalo" image="peach/bubble.png" />
<element type="focusHalo" image="peach/glass_iconhighlight_focus.png" />
<element type="spinner" state="neutral" image="peach/glassspinner.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner" state="focused" image="peach/glassspinner_focus.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner2" state="neutral" image="peach/glassspinner2.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner2" state="focused" image="peach/glassspinner2_focus.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<!-- This one is a bit special. Only area(s) LEFT and/or RIGHT will be rendered. They will be overlaid
on top of the spinner's background -->
<element type="spinner" state="down" image="peach/glassspinner_down.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<element type="spinner2" state="down" image="peach/glassspinner2_down.png"
left_border="110" right_border="110" top_border="0" bottom_border="36"
preserve_h_aspect_ratios="true" hborder_out_portion="0.0" />
<!-- For checkboxes, no splitting into 9 areas is done; the image is just stretched -->
<element type="checkbox" state="neutral+unchecked" image="peach/glasscheckbox.png"/>
<element type="checkbox" state="neutral+checked" image="peach/glasscheckbox_checked.png"/>
<element type="checkbox" state="focused+unchecked" image="peach/glasscheckbox_focus.png"/>
<element type="checkbox" state="focused+checked" image="peach/glasscheckbox_checked_focus.png"/>
<!-- are always in neutral state for now. No splitting into 9 areas is done; the image is just stretched.
Note: the body of a guage is the same as for for spinners. -->
<element type="gaugefill" image="peach/glasssgauge_fill.png" />
<!-- Lists are always in neutral state for now -->
<element type="list" image="peach/glass_section.png"
left_border="15" right_border="15" top_border="15" bottom_border="15"
hborder_out_portion="0.5" vborder_out_portion="1.0" />
<element type="listitem" state="focused" image="peach/select.png"
left_border="0" right_border="0" top_border="0" bottom_border="0"
hborder_out_portion="0.0" vborder_out_portion="0.0" />
<element type="listitem" state="down" image="peach/glassbutton.png"
left_border="80" right_border="80" top_border="0" bottom_border="36"
hborder_out_portion="1.0" vborder_out_portion="1.0"
areas="body" />
<!-- Scrollbars. Background and thumb have no state (always neutral state).
The buttons are the top and bottom arrows. Image must be top arrow, will
be mirrorred for bottom. Buttons can be in neutral or down state.
Advanced stretching is not used here.
-->
<element type="scrollbar_background" image="peach/scrollbar_bg.png" />
<element type="scrollbar_thumb" image="peach/scrollbar_thumb.png" />
<element type="scrollbar_button" image="peach/scrollbar_btn.png" />
<element type="scrollbar_button" state="down" image="peach/scrollbar_btn_down.png" />
<!-- Stateless -->
<element type="section" image="peach/glass_section.png"
left_border="15" right_border="15" top_border="15" bottom_border="15"
hborder_out_portion="1.0" vborder_out_portion="0.2" />
<!-- Stateless -->
<element type="window" image="peach/dialog.png"
left_border="7" right_border="7" top_border="50" bottom_border="50"
hborder_out_portion="1.0" vborder_out_portion="0.2" />
<!-- Colors -->
<color type="text" state="neutral" r="0" g="0" b="0" />
<!-- For highlighted items, e.g. in list -->
<color type="text" state="focused" r="255" g="255" b="255" />
<!-- Color used to fade out background when a dialog is shown -->
<color type="dialog_background" state="neutral" a="120" r="0" g="0" b="0" />
<!-- Text field color -->
<color type="text_field" state="neutral" a="255" r="215" g="215" b="215" />
<color type="text_field" state="focused" a="255" r="138" g="138" b="138" />
</skin>

View File

@ -0,0 +1,2 @@
This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,2 @@
This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -116,15 +116,22 @@ void GroupUserConfigParam::addChild(UserConfigParam* child)
IntUserConfigParam::IntUserConfigParam(int defaultValue, const char* paramName, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
all_params.push_back(this);
if(comment != NULL) this->comment = comment;
}
// ---------------------------------------------------------------------------------------
IntUserConfigParam::IntUserConfigParam(int defaultValue, const char* paramName,
GroupUserConfigParam* group, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
group->addChild(this);
if(comment != NULL) this->comment = comment;
@ -133,13 +140,13 @@ IntUserConfigParam::IntUserConfigParam(int defaultValue, const char* paramName,
void IntUserConfigParam::write(std::ofstream& stream) const
{
if(comment.size() > 0) stream << " <!-- " << comment.c_str() << " -->\n";
stream << " <" << paramName << " value=\"" << value << "\" />\n\n";
stream << " <" << paramName << " value=\"" << m_value << "\" />\n\n";
}
std::string IntUserConfigParam::toString() const
{
char buffer[16];
sprintf(buffer, "%i", value);
sprintf(buffer, "%i", m_value);
return buffer;
}
@ -152,19 +159,22 @@ void IntUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
return;
}
child->get( "value", &value );
child->get( "value", &m_value );
//std::cout << "read int " << paramName << ", value=" << value << std::endl;
}
void IntUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node)
{
node->get( paramName, &value );
node->get( paramName, &m_value );
}
// ---------------------------------------------------------------------------------------
StringUserConfigParam::StringUserConfigParam(const char* defaultValue, const char* paramName, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
all_params.push_back(this);
if(comment != NULL) this->comment = comment;
@ -172,7 +182,9 @@ StringUserConfigParam::StringUserConfigParam(const char* defaultValue, const cha
StringUserConfigParam::StringUserConfigParam(const char* defaultValue, const char* paramName,
GroupUserConfigParam* group, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
group->addChild(this);
if(comment != NULL) this->comment = comment;
@ -182,30 +194,32 @@ StringUserConfigParam::StringUserConfigParam(const char* defaultValue, const cha
void StringUserConfigParam::write(std::ofstream& stream) const
{
if(comment.size() > 0) stream << " <!-- " << comment.c_str() << " -->\n";
stream << " <" << paramName << " value=\"" << value << "\" />\n\n";
stream << " <" << paramName << " value=\"" << m_value << "\" />\n\n";
}
void StringUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
{
const XMLNode* child = node->getNode( paramName );
if(child == NULL) return;
child->get( "value", &value );
child->get( "value", &m_value );
}
void StringUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node)
{
node->get( paramName, &value );
node->get( paramName, &m_value );
}
std::string StringUserConfigParam::toString() const
{
return value;
return m_value;
}
// ---------------------------------------------------------------------------------------
BoolUserConfigParam::BoolUserConfigParam(bool defaultValue, const char* paramName, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
all_params.push_back(this);
if(comment != NULL) this->comment = comment;
@ -213,7 +227,9 @@ BoolUserConfigParam::BoolUserConfigParam(bool defaultValue, const char* paramNam
BoolUserConfigParam::BoolUserConfigParam(bool defaultValue, const char* paramName,
GroupUserConfigParam* group, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
group->addChild(this);
if(comment != NULL) this->comment = comment;
@ -223,7 +239,7 @@ BoolUserConfigParam::BoolUserConfigParam(bool defaultValue, const char* paramNam
void BoolUserConfigParam::write(std::ofstream& stream) const
{
if(comment.size() > 0) stream << " <!-- " << comment.c_str() << " -->\n";
stream << " <" << paramName << " value=\"" << (value ? "true" : "false" ) << "\" />\n\n";
stream << " <" << paramName << " value=\"" << (m_value ? "true" : "false" ) << "\" />\n\n";
}
void BoolUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
{
@ -235,35 +251,40 @@ void BoolUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
if(textValue == "true")
{
value = true;
m_value = true;
}
else if(textValue == "false")
{
value = false;
m_value = false;
}
else
{
std::cerr << "Unknown value for " << paramName << "; expected true or false\n";
}
}
void BoolUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node)
{
std::string textValue = "";
node->get( paramName, &textValue );
if(textValue == "true")
if (textValue == "true")
{
value = true;
m_value = true;
}
else if(textValue == "false")
else if (textValue == "false")
{
value = false;
m_value = false;
}
else
{
std::cerr << "Unknown value for " << paramName << "; expected true or false\n";
}
}
std::string BoolUserConfigParam::toString() const
{
return (value ? "true" : "false" );
return (m_value ? "true" : "false" );
}
@ -271,15 +292,20 @@ std::string BoolUserConfigParam::toString() const
FloatUserConfigParam::FloatUserConfigParam(float defaultValue, const char* paramName, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
all_params.push_back(this);
if(comment != NULL) this->comment = comment;
}
FloatUserConfigParam::FloatUserConfigParam(float defaultValue, const char* paramName,
GroupUserConfigParam* group, const char* comment)
{
this->value = defaultValue;
m_value = defaultValue;
m_default_value = defaultValue;
this->paramName = paramName;
group->addChild(this);
if(comment != NULL) this->comment = comment;
@ -288,24 +314,26 @@ FloatUserConfigParam::FloatUserConfigParam(float defaultValue, const char* param
void FloatUserConfigParam::write(std::ofstream& stream) const
{
if(comment.size() > 0) stream << " <!-- " << comment.c_str() << " -->\n";
stream << " <" << paramName << " value=\"" << value << "\" />\n\n";
stream << " <" << paramName << " value=\"" << m_value << "\" />\n\n";
}
void FloatUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
{
const XMLNode* child = node->getNode( paramName );
if(child == NULL) return;
child->get( "value", &value );
child->get( "value", &m_value );
}
void FloatUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node)
{
node->get( paramName, &value );
node->get( paramName, &m_value );
}
std::string FloatUserConfigParam::toString() const
{
char buffer[16];
sprintf(buffer, "%f", value);
sprintf(buffer, "%f", m_value);
return buffer;
}

View File

@ -83,8 +83,11 @@ public:
class IntUserConfigParam : public UserConfigParam
{
int value;
int m_value;
int m_default_value;
public:
IntUserConfigParam(int defaultValue, const char* paramName, const char* comment = NULL);
IntUserConfigParam(int defaultValue, const char* paramName, GroupUserConfigParam* group, const char* comment = NULL);
@ -93,17 +96,21 @@ public:
void findYourDataInAnAttributeOf(const XMLNode* node);
std::string toString() const;
operator int() const { return value; }
int& operator++(int dummy) { value++; return value; }
int& operator=(const int& v) { value = v; return value; }
int& operator=(const IntUserConfigParam& v) { value = (int)v; return value; }
void revertToDefaults() { m_value = m_default_value; }
operator int() const { return m_value; }
int& operator++(int dummy) { m_value++; return m_value; }
int& operator=(const int& v) { m_value = v; return m_value; }
int& operator=(const IntUserConfigParam& v) { m_value = (int)v; return m_value; }
};
class StringUserConfigParam : public UserConfigParam
{
std::string value;
std::string m_value;
std::string m_default_value;
public:
StringUserConfigParam(const char* defaultValue, const char* paramName, const char* comment = NULL);
StringUserConfigParam(const char* defaultValue, const char* paramName, GroupUserConfigParam* group, const char* comment = NULL);
@ -112,18 +119,22 @@ public:
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
void revertToDefaults() { m_value = m_default_value; }
std::string toString() const;
operator std::string() const { return value; }
std::string& operator=(const std::string& v) { value = v; return value; }
std::string& operator=(const StringUserConfigParam& v) { value = (std::string)v; return value; }
operator std::string() const { return m_value; }
std::string& operator=(const std::string& v) { m_value = v; return m_value; }
std::string& operator=(const StringUserConfigParam& v) { m_value = (std::string)v; return m_value; }
const char* c_str() const { return value.c_str(); }
const char* c_str() const { return m_value.c_str(); }
};
class BoolUserConfigParam : public UserConfigParam
{
bool value;
bool m_value;
bool m_default_value;
public:
BoolUserConfigParam(bool defaultValue, const char* paramName, const char* comment = NULL);
BoolUserConfigParam(bool defaultValue, const char* paramName, GroupUserConfigParam* group, const char* comment = NULL);
@ -134,15 +145,18 @@ public:
void findYourDataInAnAttributeOf(const XMLNode* node);
std::string toString() const;
void revertToDefaults() { m_value = m_default_value; }
operator bool() const { return value; }
bool& operator=(const bool& v) { value = v; return value; }
bool& operator=(const BoolUserConfigParam& v) { value = (bool)v; return value; }
operator bool() const { return m_value; }
bool& operator=(const bool& v) { m_value = v; return m_value; }
bool& operator=(const BoolUserConfigParam& v) { m_value = (bool)v; return m_value; }
};
class FloatUserConfigParam : public UserConfigParam
{
float value;
float m_value;
float m_default_value;
public:
FloatUserConfigParam(float defaultValue, const char* paramName, const char* comment = NULL);
FloatUserConfigParam(float defaultValue, const char* paramName, GroupUserConfigParam* group, const char* comment = NULL);
@ -152,10 +166,11 @@ public:
void findYourDataInAnAttributeOf(const XMLNode* node);
std::string toString() const;
void revertToDefaults() { m_value = m_default_value; }
operator float() const { return value; }
float& operator=(const float& v) { value = v; return value; }
float& operator=(const FloatUserConfigParam& v) { value = (float)v; return value; }
operator float() const { return m_value; }
float& operator=(const float& v) { m_value = v; return m_value; }
float& operator=(const FloatUserConfigParam& v) { m_value = (float)v; return m_value; }
};
@ -295,7 +310,7 @@ namespace UserConfigParams
PARAM_DEFAULT( StringUserConfigParam("jungle", "last_track", "Name of the last track used.") );
PARAM_PREFIX StringUserConfigParam m_skin_file
PARAM_DEFAULT( StringUserConfigParam("glass.stkskin", "skin_file", "Name of the skin to use") );
PARAM_DEFAULT( StringUserConfigParam("Glass.stkskin", "skin_file", "Name of the skin to use") );
PARAM_PREFIX bool m_no_start_screen PARAM_DEFAULT( false ); // not saved to file

View File

@ -52,7 +52,7 @@
\li \ref widget9
\li \ref widget10
\li \ref widget11
\ref props
\li \ref prop1
\li \ref prop2
@ -72,7 +72,7 @@
\li \ref prop16
\li \ref prop17
\li \ref prop18
\ref code
\n
@ -97,12 +97,12 @@
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.
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)
(this will affect the type of highlighting used)
\note All elements within a ribbon must have an 'ID' property
\note Ribbons (e.g. tabs) can have their elements dynamically added at runtime, too. Just add
no children to the ribbon in the XML file, and add them at runtime through the method for this.
no children to the ribbon in the XML file, and add them at runtime through the method for this.
\n
\subsection widget2 WTYPE_SPINNER
@ -412,7 +412,7 @@ using namespace irr::video;
namespace GUIEngine
{
namespace Private
{
IGUIEnvironment* g_env;
@ -431,12 +431,12 @@ namespace GUIEngine
int small_font_height;
}
using namespace Private;
ptr_vector<Widget, REF> needsUpdate;
//FIXME: the contents of this vector are never ever freed
ptr_vector<Screen, REF> g_loaded_screens;
float dt = 0;
float getLatestDt()
@ -466,7 +466,7 @@ namespace GUIEngine
// add message
gui_messages.push_back( MenuMessage(message, time) );
}
Widget* getFocusForPlayer(const int playerID)
@ -495,7 +495,7 @@ namespace GUIEngine
// otherwise check if the focus is the given widget
return g_focus_for_player[playerID]->isSameIrrlichtWidgetAs(w);
}
int getFontHeight()
{
return Private::font_height;
@ -506,311 +506,357 @@ namespace GUIEngine
return Private::small_font_height;
}
// -----------------------------------------------------------------------------
void clear()
{
g_env->clear();
if (g_current_screen != NULL) g_current_screen->elementsWereDeleted();
g_current_screen = NULL;
}
// -----------------------------------------------------------------------------
void cleanForGame()
{
clear();
//FIXME: I'm not very sure why this isn't called in the regular clear() method??
needsUpdate.clearWithoutDeleting();
}
// -----------------------------------------------------------------------------
void switchToScreen(const char* screen_name)
{
needsUpdate.clearWithoutDeleting();
// clean what was left by the previous screen
g_env->clear();
if (g_current_screen != NULL) g_current_screen->elementsWereDeleted();
g_current_screen = NULL;
Widget::resetIDCounters();
// check if we already loaded this screen
const int screen_amount = g_loaded_screens.size();
for(int n=0; n<screen_amount; n++)
// -----------------------------------------------------------------------------
void clear()
{
if (g_loaded_screens[n].getName() == screen_name)
{
g_current_screen = g_loaded_screens.get(n);
break;
}
g_env->clear();
if (g_current_screen != NULL) g_current_screen->elementsWereDeleted();
g_current_screen = NULL;
}
// -----------------------------------------------------------------------------
// screen not found in list of existing ones
if (g_current_screen == NULL)
void cleanForGame()
{
assert(false);
return;
}
// show screen
g_current_screen->addWidgets();
}
// -----------------------------------------------------------------------------
void addScreenToList(Screen* cutscene)
{
g_loaded_screens.push_back(cutscene);
}
// -----------------------------------------------------------------------------
void reshowCurrentScreen()
{
needsUpdate.clearWithoutDeleting();
g_state_manager->reshowTopMostMenu();
//g_current_screen->addWidgets();
}
// -----------------------------------------------------------------------------
void cleanUp()
{
if (g_skin != NULL) delete g_skin;
g_skin = NULL;
for (int i=0; i<g_loaded_screens.size(); i++)
{
g_loaded_screens[i].unload();
}
g_current_screen = NULL;
needsUpdate.clearWithoutDeleting();
if (ModalDialog::isADialogActive()) ModalDialog::dismiss();
delete g_font;
g_font = NULL;
delete g_title_font;
g_title_font = NULL;
delete g_small_font;
g_small_font = NULL;
clear();
// nothing else to delete for now AFAIK, irrlicht will automatically kill everything along the device
}
// -----------------------------------------------------------------------------
void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, AbstractStateManager* state_manager )
{
g_env = device_a->getGUIEnvironment();
g_device = device_a;
g_driver = driver_a;
g_state_manager = state_manager;
for (int n=0; n<MAX_PLAYER_COUNT; n++)
{
g_focus_for_player[n] = NULL;
//FIXME: I'm not very sure why this isn't called in the regular clear() method??
needsUpdate.clearWithoutDeleting();
}
/*
To make the g_font a little bit nicer, we load an external g_font
and set it as the new default g_font in the g_skin.
To keep the standard g_font for tool tip text, we set it to
the built-in g_font.
*/
g_skin = new Skin(g_env->getSkin());
g_env->setSkin(g_skin);
//g_skin = g_env->getSkin();
// -----------------------------------------------------------------------------
void switchToScreen(const char* screen_name)
{
needsUpdate.clearWithoutDeleting();
// clean what was left by the previous screen
g_env->clear();
if (g_current_screen != NULL) g_current_screen->elementsWereDeleted();
g_current_screen = NULL;
Widget::resetIDCounters();
// check if we already loaded this screen
const int screen_amount = g_loaded_screens.size();
for(int n=0; n<screen_amount; n++)
{
if (g_loaded_screens[n].getName() == screen_name)
{
g_current_screen = g_loaded_screens.get(n);
break;
}
}
// screen not found in list of existing ones
if (g_current_screen == NULL)
{
assert(false);
return;
}
// show screen
g_current_screen->addWidgets();
}
// -----------------------------------------------------------------------------
// font size is resolution-dependent.
// normal text will range from 0.8, in 640x* resolutions (won't scale below that) to
// 1.0, in 1024x* resolutions, and linearly up
// normal text will range from 0.2, in 640x* resolutions (won't scale below that) to
// 0.4, in 1024x* resolutions, and linearly up
const int screen_width = irr_driver->getFrameSize().Width;
const float normal_text_scale = 0.7f + 0.2f*std::max(0, screen_width - 640)/564.0f;
const float title_text_scale = 0.2f + 0.2f*std::max(0, screen_width - 640)/564.0f;
//ScalableFont* sfont = new ScalableFont(g_env, (file_manager->getGUIDir() + "/okolaks.xml").c_str());
ScalableFont* sfont = new ScalableFont(g_env, file_manager->getFontFile("StkFont.xml").c_str() );
sfont->setScale(normal_text_scale);
sfont->setKerningHeight(-5);
g_font = sfont;
void addScreenToList(Screen* cutscene)
{
g_loaded_screens.push_back(cutscene);
}
Private::font_height = g_font->getDimension( L"X" ).Height;
//ScalableFont* sfont_smaller = new ScalableFont(g_env, file_manager->getFontFile("StkFont.xml").c_str() );
ScalableFont* sfont_smaller = sfont->getHollowCopy();
sfont_smaller->setScale(normal_text_scale*0.8f);
sfont_smaller->setKerningHeight(-5);
g_small_font = sfont_smaller;
// -----------------------------------------------------------------------------
Private::small_font_height = g_small_font->getDimension( L"X" ).Height;
ScalableFont* sfont2 = new ScalableFont(g_env, file_manager->getFontFile("title_font.xml").c_str() );
sfont2->m_fallback_font = sfont;
sfont2->m_fallback_font_scale = 4.0f; // because the fallback font is much smaller than the title font
sfont2->m_fallback_kerning_width = 15;
sfont2->setScale(title_text_scale);
sfont2->setKerningWidth(-18);
sfont2->m_black_border = true;
g_title_font = sfont2;
void reshowCurrentScreen()
{
needsUpdate.clearWithoutDeleting();
g_state_manager->reshowTopMostMenu();
//g_current_screen->addWidgets();
}
if (g_font != NULL) g_skin->setFont(g_font);
// -----------------------------------------------------------------------------
void cleanUp()
{
if (g_skin != NULL) delete g_skin;
g_skin = NULL;
for (int i=0; i<g_loaded_screens.size(); i++)
{
g_loaded_screens[i].unload();
}
g_current_screen = NULL;
needsUpdate.clearWithoutDeleting();
if (ModalDialog::isADialogActive()) ModalDialog::dismiss();
delete g_font;
g_font = NULL;
delete g_title_font;
g_title_font = NULL;
delete g_small_font;
g_small_font = NULL;
// nothing else to delete for now AFAIK, irrlicht will automatically kill everything along the device
}
//g_skin->setFont(g_env->getBuiltInFont(), EGDF_TOOLTIP);
// -----------------------------------------------------------------------------
void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, AbstractStateManager* state_manager )
{
g_env = device_a->getGUIEnvironment();
g_device = device_a;
g_driver = driver_a;
g_state_manager = state_manager;
for (int n=0; n<MAX_PLAYER_COUNT; n++)
{
g_focus_for_player[n] = NULL;
}
/*
To make the g_font a little bit nicer, we load an external g_font
and set it as the new default g_font in the g_skin.
To keep the standard g_font for tool tip text, we set it to
the built-in g_font.
*/
try
{
g_skin = new Skin(g_env->getSkin());
g_env->setSkin(g_skin);
}
catch (std::runtime_error& err)
{
std::cerr << "ERROR, cannot load skin specified in user config. Falling back to defaults.\n";
UserConfigParams::m_skin_file.revertToDefaults();
try
{
g_skin = new Skin(g_env->getSkin());
g_env->setSkin(g_skin);
}
catch (std::runtime_error& err)
{
std::cerr << "FATAL, cannot load default GUI skin\n";
throw err;
}
}
//g_skin = g_env->getSkin();
// font size is resolution-dependent.
// normal text will range from 0.8, in 640x* resolutions (won't scale below that) to
// 1.0, in 1024x* resolutions, and linearly up
// normal text will range from 0.2, in 640x* resolutions (won't scale below that) to
// 0.4, in 1024x* resolutions, and linearly up
const int screen_width = irr_driver->getFrameSize().Width;
const float normal_text_scale = 0.7f + 0.2f*std::max(0, screen_width - 640)/564.0f;
const float title_text_scale = 0.2f + 0.2f*std::max(0, screen_width - 640)/564.0f;
//ScalableFont* sfont = new ScalableFont(g_env, (file_manager->getGUIDir() + "/okolaks.xml").c_str());
ScalableFont* sfont = new ScalableFont(g_env, file_manager->getFontFile("StkFont.xml").c_str() );
sfont->setScale(normal_text_scale);
sfont->setKerningHeight(-5);
g_font = sfont;
Private::font_height = g_font->getDimension( L"X" ).Height;
//ScalableFont* sfont_smaller = new ScalableFont(g_env, file_manager->getFontFile("StkFont.xml").c_str() );
ScalableFont* sfont_smaller = sfont->getHollowCopy();
sfont_smaller->setScale(normal_text_scale*0.8f);
sfont_smaller->setKerningHeight(-5);
g_small_font = sfont_smaller;
Private::small_font_height = g_small_font->getDimension( L"X" ).Height;
ScalableFont* sfont2 = new ScalableFont(g_env, file_manager->getFontFile("title_font.xml").c_str() );
sfont2->m_fallback_font = sfont;
sfont2->m_fallback_font_scale = 4.0f; // because the fallback font is much smaller than the title font
sfont2->m_fallback_kerning_width = 15;
sfont2->setScale(title_text_scale);
sfont2->setKerningWidth(-18);
sfont2->m_black_border = true;
g_title_font = sfont2;
if (g_font != NULL) g_skin->setFont(g_font);
//g_skin->setFont(g_env->getBuiltInFont(), EGDF_TOOLTIP);
// set event receiver
g_device->setEventReceiver(EventHandler::get());
}
// set event receiver
g_device->setEventReceiver(EventHandler::get());
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void render(float elapsed_time)
{
GUIEngine::dt = elapsed_time;
void reloadSkin()
{
assert(g_skin != NULL);
irr::gui::IGUISkin* fallbackSkin = g_skin->getFallbackSkin();
Skin* newSkin;
try
{
// it's important to create the new skin before deleting the old one
//so that the fallback skin is not dropped
newSkin = new Skin(fallbackSkin);
}
catch (std::runtime_error& err)
{
std::cerr << "ERROR, cannot load newly specified skin!\n";
return;
}
delete g_skin;
g_skin = newSkin;
g_env->setSkin(g_skin);
}
// ---- menu drawing
// -----------------------------------------------------------------------------
// draw background image and sections
void render(float elapsed_time)
{
GUIEngine::dt = elapsed_time;
// ---- menu drawing
// draw background image and sections
const GameState gamestate = g_state_manager->getGameState();
if (gamestate == MENU && !GUIEngine::getCurrentScreen()->needs3D())
{
g_skin->drawBgImage();
}
else if (gamestate == INGAME_MENU)
{
g_skin->drawBGFadeColor();
}
g_driver->enableMaterial2D();
if (gamestate == MENU || gamestate == INGAME_MENU)
{
g_skin->renderSections();
}
// let irrLicht do the rest (the Skin object will be called for further render)
g_env->drawAll();
// ---- some menus may need updating
if (gamestate != GAME)
{
if (ModalDialog::isADialogActive()) ModalDialog::getCurrent()->onUpdate(dt);
else getCurrentScreen()->onUpdate(elapsed_time, g_driver);
}
else
{
if (ModalDialog::isADialogActive()) ModalDialog::getCurrent()->onUpdate(dt);
else World::getWorld()->getRaceGUI()->renderGlobal(elapsed_time);
}
if (gamestate != GAME && !gui_messages.empty())
{
core::dimension2d<u32> screen_size = irr_driver->getFrameSize();
const int text_height = getFontHeight() + 20;
const int y_from = screen_size.Height - text_height;
int count = 0;
std::vector<MenuMessage>::iterator it;
for (it=gui_messages.begin(); it != gui_messages.end();)
{
if ((*it).m_time > 0.0f)
{
(*it).m_time -= dt;
core::rect<s32> msgRect(core::position2d<s32>(0, y_from - count*text_height),
core::dimension2d<s32>(screen_size.Width, text_height) );
Private::g_driver->draw2DRectangle( SColor(255,252,248,230), msgRect);
Private::g_font->draw((*it).m_message.c_str(),
msgRect,
video::SColor(255, 255, 0, 0),
true /* hcenter */, true /* vcenter */);
count++;
it++;
}
else
{
it = gui_messages.erase(it);
}
}
}
g_driver->enableMaterial2D(false);
} // render
const GameState gamestate = g_state_manager->getGameState();
// -----------------------------------------------------------------------------
if (gamestate == MENU && !GUIEngine::getCurrentScreen()->needs3D())
void renderLoading()
{
g_skin->drawBgImage();
}
else if (gamestate == INGAME_MENU)
{
g_skin->drawBGFadeColor();
}
g_driver->enableMaterial2D();
if (gamestate == MENU || gamestate == INGAME_MENU)
{
g_skin->renderSections();
}
// let irrLicht do the rest (the Skin object will be called for further render)
g_env->drawAll();
// ---- some menus may need updating
if (gamestate != GAME)
{
if (ModalDialog::isADialogActive()) ModalDialog::getCurrent()->onUpdate(dt);
else getCurrentScreen()->onUpdate(elapsed_time, g_driver);
}
else
{
if (ModalDialog::isADialogActive()) ModalDialog::getCurrent()->onUpdate(dt);
else World::getWorld()->getRaceGUI()->renderGlobal(elapsed_time);
}
if (gamestate != GAME && !gui_messages.empty())
{
core::dimension2d<u32> screen_size = irr_driver->getFrameSize();
const int text_height = getFontHeight() + 20;
const int y_from = screen_size.Height - text_height;
ITexture* loading = irr_driver->getTexture( file_manager->getGUIDir() + "/loading.png" );
int count = 0;
const int texture_w = loading->getSize().Width;
const int texture_h = loading->getSize().Height;
std::vector<MenuMessage>::iterator it;
for (it=gui_messages.begin(); it != gui_messages.end();)
core::dimension2d<u32> frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize();
const int screen_w = frame_size.Width;
const int screen_h = frame_size.Height;
const core::rect< s32 > dest_area = core::rect< s32 >(screen_w/2 - texture_w/2,
screen_h/2 - texture_h/2,
screen_w/2 + texture_w/2,
screen_h/2 + texture_h/2);
const core::rect< s32 > source_area = core::rect< s32 >(0, 0, texture_w, texture_h);
GUIEngine::getDriver()->draw2DImage( loading, dest_area, source_area,
0 /* no clipping */, 0, true /* alpha */);
g_title_font->draw(_("Loading"),
core::rect< s32 >( 0, screen_h/2 + texture_h/2, screen_w, screen_h ),
SColor(255,255,255,255),
true/* center h */, false /* center v */ );
} // renderLoading
// -----------------------------------------------------------------------------
Widget* getWidget(const char* name)
{
// if a modal dialog is shown, search within it too
if (ModalDialog::isADialogActive())
{
if ((*it).m_time > 0.0f)
{
(*it).m_time -= dt;
core::rect<s32> msgRect(core::position2d<s32>(0, y_from - count*text_height),
core::dimension2d<s32>(screen_size.Width, text_height) );
Private::g_driver->draw2DRectangle( SColor(255,252,248,230), msgRect);
Private::g_font->draw((*it).m_message.c_str(),
msgRect,
video::SColor(255, 255, 0, 0),
true /* hcenter */, true /* vcenter */);
count++;
it++;
}
else
{
it = gui_messages.erase(it);
}
Widget* widgetWithinDialog = Screen::getWidget(name, &(ModalDialog::getCurrent()->m_children));
if (widgetWithinDialog != NULL) return widgetWithinDialog;
}
}
g_driver->enableMaterial2D(false);
} // render
// -----------------------------------------------------------------------------
void renderLoading()
{
g_skin->drawBgImage();
ITexture* loading = irr_driver->getTexture( file_manager->getGUIDir() + "/loading.png" );
const int texture_w = loading->getSize().Width;
const int texture_h = loading->getSize().Height;
core::dimension2d<u32> frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize();
const int screen_w = frame_size.Width;
const int screen_h = frame_size.Height;
const core::rect< s32 > dest_area = core::rect< s32 >(screen_w/2 - texture_w/2,
screen_h/2 - texture_h/2,
screen_w/2 + texture_w/2,
screen_h/2 + texture_h/2);
const core::rect< s32 > source_area = core::rect< s32 >(0, 0, texture_w, texture_h);
GUIEngine::getDriver()->draw2DImage( loading, dest_area, source_area,
0 /* no clipping */, 0, true /* alpha */);
g_title_font->draw(_("Loading"),
core::rect< s32 >( 0, screen_h/2 + texture_h/2, screen_w, screen_h ),
SColor(255,255,255,255),
true/* center h */, false /* center v */ );
} // renderLoading
// -----------------------------------------------------------------------------
Widget* getWidget(const char* name)
{
// if a modal dialog is shown, search within it too
if (ModalDialog::isADialogActive())
{
Widget* widgetWithinDialog = Screen::getWidget(name, &(ModalDialog::getCurrent()->m_children));
if (widgetWithinDialog != NULL) return widgetWithinDialog;
}
Screen* screen = getCurrentScreen();
if (screen == NULL) return NULL;
return screen->getWidget(name);
}
// -----------------------------------------------------------------------------
Widget* getWidget(const int id)
{
// if a modal dialog is shown, search within it too
if (ModalDialog::isADialogActive())
{
Widget* widgetWithinDialog = Screen::getWidget(id, &(ModalDialog::getCurrent()->m_children));
if (widgetWithinDialog != NULL) return widgetWithinDialog;
}
Screen* screen = getCurrentScreen();
if (screen == NULL) return NULL;
return screen->getWidget(id);
}
Screen* screen = getCurrentScreen();
if (screen == NULL) return NULL;
return screen->getWidget(name);
}
// -----------------------------------------------------------------------------
Widget* getWidget(const int id)
{
// if a modal dialog is shown, search within it too
if (ModalDialog::isADialogActive())
{
Widget* widgetWithinDialog = Screen::getWidget(id, &(ModalDialog::getCurrent()->m_children));
if (widgetWithinDialog != NULL) return widgetWithinDialog;
}
Screen* screen = getCurrentScreen();
if (screen == NULL) return NULL;
return screen->getWidget(id);
}
}

View File

@ -208,6 +208,11 @@ namespace GUIEngine
* \return the widget that bears that irrlicht ID, or NULL if it was not found
*/
Widget* getWidget(const int id);
/**
* \brief call when skin in user config was updated
*/
void reloadSkin();
}
#endif

View File

@ -82,6 +82,7 @@ Screen::~Screen()
void Screen::loadFromFile()
{
assert(m_magic_number == 0xCAFEC001);
//FIXME: need to delete this pointer
IrrXMLReader* xml = irr::io::createIrrXMLReader( (file_manager->getGUIDir() + "/" + m_filename).c_str() );
parseScreenFileDiv(xml, m_widgets);
m_loaded = true;

View File

@ -26,6 +26,7 @@
#include "io/file_manager.hpp"
#include "states_screens/state_manager.hpp"
#include <cassert>
#include <stdexcept>
#include <iostream>
using namespace GUIEngine;
@ -133,12 +134,17 @@ namespace SkinConfig
m_colors[type+"::"+state] = color;
}
/**
* \brief loads skin information from a STK skin file
* \throw std::runtime_error if file cannot be read
*/
static void loadFromFile(std::string file)
{
XMLNode* root = file_manager->createXMLTree(file);
if(!root)
{
std::cerr << "Could not read XML file " << file.c_str() << std::endl;
throw std::runtime_error("Invalid skin file");
}
const int amount = root->getNumNodes();

View File

@ -271,8 +271,15 @@ namespace GUIEngine
bool m_dialog;
float m_dialog_size;
/**
* \brief load a skin from the file specified in the user configuration file
* \throw std::runtime_error if file cannot be read
*/
Skin(irr::gui::IGUISkin* fallback_skin);
~Skin();
irr::gui::IGUISkin* getFallbackSkin() { return m_fallback_skin; }
void renderSections(ptr_vector<Widget>* within_vector=NULL);
void drawBgImage();

View File

@ -53,15 +53,29 @@ void SpinnerWidget::add()
int i;
std::istringstream myStream(min_s);
bool is_number = (myStream >> i)!=0;
if(is_number) m_min = i;
else m_min = 0;
if (is_number)
{
m_min = i;
}
else
{
std::cerr << "WARNING : invalid value from spinner widget minimum value '" << min_s << "'\n";
m_min = 0;
}
}
{
int i;
std::istringstream myStream(max_s);
bool is_number = (myStream >> i)!=0;
if(is_number) m_max = i;
else m_max = 10;
if (is_number)
{
m_max = i;
}
else
{
std::cerr << "WARNING : invalid value from spinner widget maximal value '" << max_s << "'\n";
m_max = 10;
}
}
m_value = (m_min + m_max)/2;
@ -146,6 +160,9 @@ void SpinnerWidget::add()
m_children[2].m_event_handler = this;
m_children[2].m_properties[PROP_ID] = "right";
m_children[2].id = m_children[2].m_element->getID();
// refresh display
setValue(m_value);
}
// -----------------------------------------------------------------------------
@ -262,7 +279,8 @@ void SpinnerWidget::addLabel(stringw label)
m_labels.push_back(label);
m_min = 0;
m_max = m_labels.size()-1;
setValue(0);
if (m_element != NULL) setValue(0);
}
// -----------------------------------------------------------------------------
@ -280,6 +298,8 @@ void SpinnerWidget::setValue(const int new_value)
}
else if (m_labels.size() > 0)
{
assert(new_value >= 0);
assert(new_value < (int)m_labels.size());
m_children[1].m_element->setText(m_labels[new_value].c_str() );
}
else if (m_text.size() > 0)

View File

@ -68,7 +68,7 @@ namespace GUIEngine
/** Call only if this spinner is graphical. Returns the current texture to display */
irr::video::ITexture* getTexture();
public:
SpinnerWidget(const bool gauge=false);

View File

@ -31,7 +31,7 @@
#include "guiengine/widget.hpp"
#include "io/file_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/string_utils.hpp"
#include <iostream>
#include <sstream>
@ -52,6 +52,45 @@ OptionsScreenVideo::OptionsScreenVideo() : Screen("options_video.stkgui")
void OptionsScreenVideo::loadedFromFile()
{
m_inited = false;
GUIEngine::SpinnerWidget* skinSelector = this->getWidget<GUIEngine::SpinnerWidget>("skinchoice");
assert( skinSelector != NULL );
skinSelector->m_properties[PROP_WARP_AROUND] = "true";
m_skins.clear();
skinSelector->clearLabels();
std::set<std::string> skinFiles;
file_manager->listFiles(skinFiles /* out */, file_manager->getGUIDir() + "/skins",
true /* is full path */, true /* make full path */ );
for (std::set<std::string>::iterator it = skinFiles.begin(); it != skinFiles.end(); it++)
{
if ( (*it).find(".stkskin") != std::string::npos )
{
m_skins.push_back( *it );
}
}
if (m_skins.size() == 0)
{
std::cerr << "WARNING: could not find a single skin, make sure that "
"the data files are correctly installed\n";
skinSelector->m_deactivated = true;
return;
}
const int skinCount = m_skins.size();
for (int n=0; n<skinCount; n++)
{
const std::string skinFileName = StringUtils::getBasename(m_skins[n]);
const std::string skinName = StringUtils::removeExtension( skinFileName );
skinSelector->addLabel( core::stringw(skinName.c_str()) );
}
skinSelector->m_properties[GUIEngine::PROP_MIN_VALUE] = "0";
skinSelector->m_properties[GUIEngine::PROP_MAX_VALUE] = StringUtils::toString(skinCount-1);
}
// -----------------------------------------------------------------------------
@ -61,6 +100,9 @@ void OptionsScreenVideo::init()
RibbonWidget* ribbon = this->getWidget<RibbonWidget>("options_choice");
if (ribbon != NULL) ribbon->select( "tab_video", PLAYER_ID_GAME_MASTER );
GUIEngine::SpinnerWidget* skinSelector = this->getWidget<GUIEngine::SpinnerWidget>("skinchoice");
assert( skinSelector != NULL );
// ---- video modes
DynamicRibbonWidget* res = this->getWidget<DynamicRibbonWidget>("resolutions");
assert( res != NULL );
@ -125,6 +167,28 @@ void OptionsScreenVideo::init()
}
} // end for
// --- select the right skin in the spinner
bool currSkinFound = false;
const int skinCount = m_skins.size();
for (int n=0; n<skinCount; n++)
{
const std::string skinFileName = StringUtils::getBasename(m_skins[n]);
if (UserConfigParams::m_skin_file.c_str() == skinFileName)
{
skinSelector->setValue(n);
currSkinFound = true;
break;
}
}
if (!currSkinFound)
{
std::cerr << "WARNING: couldn't find current skin in the list of skins!!\n";
skinSelector->setValue(0);
GUIEngine::reloadSkin();
}
}
// -----------------------------------------------------------------------------
@ -166,6 +230,15 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name,
irr_driver->changeResolution(w, h, w2->getState());
}
else if (name == "skinchoice")
{
GUIEngine::SpinnerWidget* skinSelector = this->getWidget<GUIEngine::SpinnerWidget>("skinchoice");
assert( skinSelector != NULL );
const core::stringw selectedSkin = skinSelector->getStringValue();
UserConfigParams::m_skin_file = core::stringc(selectedSkin.c_str()).c_str() + std::string(".stkskin");
GUIEngine::reloadSkin();
}
}
@ -173,6 +246,8 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name,
void OptionsScreenVideo::tearDown()
{
// save changes when leaving screen
user_config->saveConfig();
}
// -----------------------------------------------------------------------------

View File

@ -37,6 +37,8 @@ class OptionsScreenVideo : public GUIEngine::Screen, public GUIEngine::ScreenSin
OptionsScreenVideo();
bool m_inited;
std::vector<std::string> m_skins;
public:
friend class GUIEngine::ScreenSingleton<OptionsScreenVideo>;