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,9 +18,15 @@
<box proportion="1" width="100%" layout="vertical-row"> <box proportion="1" width="100%" layout="vertical-row">
<spacer height="20" width="10"/> <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" <scrollable_ribbon id="resolutions" proportion="2" label_location="each"
width="100%" square_items="false" width="100%" square_items="false"
align="center" child_width="128" child_height="128" max_height="150" /> align="center" child_width="128" child_height="128" max_height="150" />

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

View File

@ -83,8 +83,11 @@ public:
class IntUserConfigParam : public UserConfigParam class IntUserConfigParam : public UserConfigParam
{ {
int value; int m_value;
int m_default_value;
public: public:
IntUserConfigParam(int defaultValue, const char* paramName, const char* comment = NULL); IntUserConfigParam(int defaultValue, const char* paramName, const char* comment = NULL);
IntUserConfigParam(int defaultValue, const char* paramName, GroupUserConfigParam* group, 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); void findYourDataInAnAttributeOf(const XMLNode* node);
std::string toString() const; std::string toString() const;
void revertToDefaults() { m_value = m_default_value; }
operator int() const { return value; } operator int() const { return m_value; }
int& operator++(int dummy) { value++; return value; } int& operator++(int dummy) { m_value++; return m_value; }
int& operator=(const int& v) { value = v; return value; } int& operator=(const int& v) { m_value = v; return m_value; }
int& operator=(const IntUserConfigParam& v) { value = (int)v; return value; } int& operator=(const IntUserConfigParam& v) { m_value = (int)v; return m_value; }
}; };
class StringUserConfigParam : public UserConfigParam class StringUserConfigParam : public UserConfigParam
{ {
std::string value; std::string m_value;
std::string m_default_value;
public: public:
StringUserConfigParam(const char* defaultValue, const char* paramName, const char* comment = NULL); StringUserConfigParam(const char* defaultValue, const char* paramName, const char* comment = NULL);
StringUserConfigParam(const char* defaultValue, const char* paramName, GroupUserConfigParam* group, 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 findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node);
void revertToDefaults() { m_value = m_default_value; }
std::string toString() const; std::string toString() const;
operator std::string() const { return value; } operator std::string() const { return m_value; }
std::string& operator=(const std::string& v) { value = v; return value; } std::string& operator=(const std::string& v) { m_value = v; return m_value; }
std::string& operator=(const StringUserConfigParam& v) { value = (std::string)v; return 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 class BoolUserConfigParam : public UserConfigParam
{ {
bool value; bool m_value;
bool m_default_value;
public: public:
BoolUserConfigParam(bool defaultValue, const char* paramName, const char* comment = NULL); BoolUserConfigParam(bool defaultValue, const char* paramName, const char* comment = NULL);
BoolUserConfigParam(bool defaultValue, const char* paramName, GroupUserConfigParam* group, 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); void findYourDataInAnAttributeOf(const XMLNode* node);
std::string toString() const; std::string toString() const;
void revertToDefaults() { m_value = m_default_value; }
operator bool() const { return value; } operator bool() const { return m_value; }
bool& operator=(const bool& v) { value = v; return value; } bool& operator=(const bool& v) { m_value = v; return m_value; }
bool& operator=(const BoolUserConfigParam& v) { value = (bool)v; return value; } bool& operator=(const BoolUserConfigParam& v) { m_value = (bool)v; return m_value; }
}; };
class FloatUserConfigParam : public UserConfigParam class FloatUserConfigParam : public UserConfigParam
{ {
float value; float m_value;
float m_default_value;
public: public:
FloatUserConfigParam(float defaultValue, const char* paramName, const char* comment = NULL); FloatUserConfigParam(float defaultValue, const char* paramName, const char* comment = NULL);
FloatUserConfigParam(float defaultValue, const char* paramName, GroupUserConfigParam* group, 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); void findYourDataInAnAttributeOf(const XMLNode* node);
std::string toString() const; std::string toString() const;
void revertToDefaults() { m_value = m_default_value; }
operator float() const { return value; } operator float() const { return m_value; }
float& operator=(const float& v) { value = v; return value; } float& operator=(const float& v) { m_value = v; return m_value; }
float& operator=(const FloatUserConfigParam& v) { value = (float)v; return 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_DEFAULT( StringUserConfigParam("jungle", "last_track", "Name of the last track used.") );
PARAM_PREFIX StringUserConfigParam m_skin_file 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 PARAM_PREFIX bool m_no_start_screen PARAM_DEFAULT( false ); // not saved to file

View File

@ -617,8 +617,27 @@ void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, AbstractStateManager
To keep the standard g_font for tool tip text, we set it to To keep the standard g_font for tool tip text, we set it to
the built-in g_font. the built-in g_font.
*/ */
try
{
g_skin = new Skin(g_env->getSkin()); g_skin = new Skin(g_env->getSkin());
g_env->setSkin(g_skin); 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(); //g_skin = g_env->getSkin();
// font size is resolution-dependent. // font size is resolution-dependent.
@ -666,6 +685,33 @@ void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, AbstractStateManager
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
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);
}
// -----------------------------------------------------------------------------
void render(float elapsed_time) void render(float elapsed_time)
{ {
GUIEngine::dt = elapsed_time; GUIEngine::dt = elapsed_time;

View File

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

View File

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

View File

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

View File

@ -271,9 +271,16 @@ namespace GUIEngine
bool m_dialog; bool m_dialog;
float m_dialog_size; 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* fallback_skin);
~Skin(); ~Skin();
irr::gui::IGUISkin* getFallbackSkin() { return m_fallback_skin; }
void renderSections(ptr_vector<Widget>* within_vector=NULL); void renderSections(ptr_vector<Widget>* within_vector=NULL);
void drawBgImage(); void drawBgImage();
void drawBGFadeColor(); void drawBGFadeColor();

View File

@ -53,15 +53,29 @@ void SpinnerWidget::add()
int i; int i;
std::istringstream myStream(min_s); std::istringstream myStream(min_s);
bool is_number = (myStream >> i)!=0; bool is_number = (myStream >> i)!=0;
if(is_number) m_min = i; if (is_number)
else m_min = 0; {
m_min = i;
}
else
{
std::cerr << "WARNING : invalid value from spinner widget minimum value '" << min_s << "'\n";
m_min = 0;
}
} }
{ {
int i; int i;
std::istringstream myStream(max_s); std::istringstream myStream(max_s);
bool is_number = (myStream >> i)!=0; bool is_number = (myStream >> i)!=0;
if(is_number) m_max = i; if (is_number)
else m_max = 10; {
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; 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_event_handler = this;
m_children[2].m_properties[PROP_ID] = "right"; m_children[2].m_properties[PROP_ID] = "right";
m_children[2].id = m_children[2].m_element->getID(); 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_labels.push_back(label);
m_min = 0; m_min = 0;
m_max = m_labels.size()-1; 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) 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() ); m_children[1].m_element->setText(m_labels[new_value].c_str() );
} }
else if (m_text.size() > 0) else if (m_text.size() > 0)

View File

@ -31,7 +31,7 @@
#include "guiengine/widget.hpp" #include "guiengine/widget.hpp"
#include "io/file_manager.hpp" #include "io/file_manager.hpp"
#include "states_screens/state_manager.hpp" #include "states_screens/state_manager.hpp"
#include "utils/string_utils.hpp"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -52,6 +52,45 @@ OptionsScreenVideo::OptionsScreenVideo() : Screen("options_video.stkgui")
void OptionsScreenVideo::loadedFromFile() void OptionsScreenVideo::loadedFromFile()
{ {
m_inited = false; 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"); RibbonWidget* ribbon = this->getWidget<RibbonWidget>("options_choice");
if (ribbon != NULL) ribbon->select( "tab_video", PLAYER_ID_GAME_MASTER ); if (ribbon != NULL) ribbon->select( "tab_video", PLAYER_ID_GAME_MASTER );
GUIEngine::SpinnerWidget* skinSelector = this->getWidget<GUIEngine::SpinnerWidget>("skinchoice");
assert( skinSelector != NULL );
// ---- video modes // ---- video modes
DynamicRibbonWidget* res = this->getWidget<DynamicRibbonWidget>("resolutions"); DynamicRibbonWidget* res = this->getWidget<DynamicRibbonWidget>("resolutions");
assert( res != NULL ); assert( res != NULL );
@ -125,6 +167,28 @@ void OptionsScreenVideo::init()
} }
} // end for } // 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()); 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() 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(); OptionsScreenVideo();
bool m_inited; bool m_inited;
std::vector<std::string> m_skins;
public: public:
friend class GUIEngine::ScreenSingleton<OptionsScreenVideo>; friend class GUIEngine::ScreenSingleton<OptionsScreenVideo>;