mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
Merge branch '587-make-the-help-component-more-configurable-by-the-theme'
This commit is contained in:
commit
db77b6d0df
|
@ -53,8 +53,9 @@ Again, the `[CURRENT_THEME_SET]` value is set in the "UI Settings" menu. If it
|
|||
Here is a very simple theme that changes the description text's color:
|
||||
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<view name="detailed">
|
||||
<text name="description">
|
||||
<color>00FF00</color>
|
||||
|
@ -73,11 +74,10 @@ Here is a very simple theme that changes the description text's color:
|
|||
|
||||
Everything must be inside a `<theme>` tag.
|
||||
|
||||
**The `<formatVersion>` tag *must* be specified**. This is the version of the theming system the theme was designed for. The current version is 6.
|
||||
**The `<formatVersion>` tag *must* be specified**. This is the version of the theming system the theme was designed for.
|
||||
The current version is 7.
|
||||
|
||||
|
||||
|
||||
A *view* can be thought of as a particular "screen" within EmulationStation. Views are defined like this:
|
||||
A *view* can be thought of as a particular "screen" within EmulationStation. Views are defined like this:
|
||||
|
||||
```xml
|
||||
<view name="ViewNameHere">
|
||||
|
@ -124,8 +124,9 @@ You can include theme files within theme files, similar to `#include` in C (thou
|
|||
|
||||
`~/.emulationstation/all_themes.xml`:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<view name="detailed">
|
||||
<text name="description">
|
||||
<fontPath>./all_themes/myfont.ttf</fontPath>
|
||||
|
@ -137,8 +138,9 @@ You can include theme files within theme files, similar to `#include` in C (thou
|
|||
|
||||
`~/.emulationstation/snes/theme.xml`:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<include>./../all_themes.xml</include>
|
||||
<view name="detailed">
|
||||
<text name="description">
|
||||
|
@ -150,8 +152,9 @@ You can include theme files within theme files, similar to `#include` in C (thou
|
|||
|
||||
Is equivalent to this `snes/theme.xml`:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<view name="detailed">
|
||||
<text name="description">
|
||||
<fontPath>./all_themes/myfont.ttf</fontPath>
|
||||
|
@ -169,8 +172,9 @@ Notice that properties that were not specified got merged (`<fontPath>`) and the
|
|||
Sometimes you want to apply the same properties to the same elements across multiple views. The `name` attribute actually works as a list (delimited by any characters of `\t\r\n ,` - that is, whitespace and commas). So, for example, to easily apply the same header to the basic, grid, and system views:
|
||||
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<view name="basic, grid, system">
|
||||
<image name="logo">
|
||||
<path>./snes_art/snes_header.png</path>
|
||||
|
@ -186,8 +190,9 @@ Sometimes you want to apply the same properties to the same elements across mult
|
|||
|
||||
This is equivalent to:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<view name="basic">
|
||||
<image name="logo">
|
||||
<path>./snes_art/snes_header.png</path>
|
||||
|
@ -218,8 +223,9 @@ This is equivalent to:
|
|||
You can theme multiple elements *of the same type* simultaneously. The `name` attribute actually works as a list (delimited by any characters of `\t\r\n ,` - that is, whitespace and commas), just like it does for views, as long as the elements have the same type. This is useful if you want to, say, apply the same color to all the metadata labels:
|
||||
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<view name="detailed">
|
||||
<!-- Weird spaces/newline on purpose! -->
|
||||
<text name="md_lbl_rating, md_lbl_releasedate, md_lbl_developer, md_lbl_publisher,
|
||||
|
@ -232,8 +238,9 @@ You can theme multiple elements *of the same type* simultaneously. The `name` a
|
|||
|
||||
Which is equivalent to:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<view name="detailed">
|
||||
<text name="md_lbl_rating">
|
||||
<color>48474D</color>
|
||||
|
@ -290,8 +297,9 @@ Jul 12 11:28:58 Debug: Sound::getFromTheme(): Tag not found, using fallback sou
|
|||
Example `navigationsounds.xml`, to be included from the main theme file:
|
||||
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<formatVersion>7</formatVersion>
|
||||
<feature supported="navigationsounds">
|
||||
<view name="all">
|
||||
<sound name="systembrowse">
|
||||
|
@ -851,13 +859,53 @@ EmulationStation borrows the concept of "nine patches" from Android (or "9-Slice
|
|||
|
||||
#### helpsystem
|
||||
|
||||
* `pos` - type: NORMALIZED_PAIR. Default is "0.012 0.9515"
|
||||
* `pos` - type: NORMALIZED_PAIR. Default is "0.012 0.9515"
|
||||
* `origin` - type: NORMALIZED_PAIR.
|
||||
- Where on the component `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the component exactly in the middle of the screen.
|
||||
* `textColor` - type: COLOR. Default is 777777FF.
|
||||
* `iconColor` - type: COLOR. Default is 777777FF.
|
||||
- Where on the component `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place
|
||||
the component exactly in the middle of the screen.
|
||||
* `textColor` - type: COLOR. Default is 777777FF.
|
||||
* `textColorDimmed` - type: COLOR. Default is 777777FF.
|
||||
* `iconColor` - type: COLOR. Default is 777777FF.
|
||||
* `iconColorDimmed` - type: COLOR. Default is 777777FF.
|
||||
* `fontPath` - type: PATH.
|
||||
* `fontSize` - type: FLOAT.
|
||||
* `entrySpacing` - type: FLOAT. Default is 16.0.
|
||||
- Spacing in pixels between the help system components.
|
||||
* `iconTextSpacing` - type: FLOAT. Default is 8.0.
|
||||
- Spacing in pixels within a help system component between it's icon and text.
|
||||
* `textStyle` - type: STRING. Default is `uppercase`.
|
||||
- The style of the text. Options: `uppercase`, `lowercase`, `camelcase`.
|
||||
* `customButtonIcon` - type: PATH.
|
||||
- A button icon override. Specify the button type in the attribute `button`. The available buttons are:
|
||||
`dpad_updown`,
|
||||
`dpad_leftright`,
|
||||
`dpad_all`,
|
||||
`thumbstick_click`,
|
||||
`button_l`,
|
||||
`button_r`,
|
||||
`button_lr`,
|
||||
`button_a_SNES`,
|
||||
`button_b_SNES`,
|
||||
`button_x_SNES`,
|
||||
`button_y_SNES`,
|
||||
`button_back_SNES`,
|
||||
`button_start_SNES`,
|
||||
`button_a_PS`,
|
||||
`button_b_PS`,
|
||||
`button_x_PS`,
|
||||
`button_y_PS`,
|
||||
`button_back_PS4`,
|
||||
`button_start_PS4`,
|
||||
`button_back_PS5`,
|
||||
`button_start_PS5`,
|
||||
`button_a_XBOX`,
|
||||
`button_b_XBOX`,
|
||||
`button_x_XBOX`,
|
||||
`button_y_XBOX`,
|
||||
`button_back_XBOX`,
|
||||
`button_start_XBOX`,
|
||||
`button_back_XBOX360`,
|
||||
`button_start_XBOX360`.
|
||||
|
||||
#### carousel
|
||||
|
||||
|
|
27
THEMES.md
27
THEMES.md
|
@ -71,20 +71,18 @@ Here is a very simple theme that changes the description text's color:
|
|||
|
||||
Everything must be inside a `<theme>` tag.
|
||||
|
||||
**The `<formatVersion>` tag *must* be specified**. This is the version of the theming system the theme was designed for. The current version is 6.
|
||||
**The `<formatVersion>` tag *must* be specified**. This is the version of the theming system the theme was designed for.
|
||||
The current version is 6.
|
||||
|
||||
|
||||
|
||||
A *view* can be thought of as a particular "screen" within EmulationStation. Views are defined like this:
|
||||
A *view* can be thought of as a particular "screen" within EmulationStation. Views are defined like this:
|
||||
|
||||
```xml
|
||||
|
||||
<view name="ViewNameHere">
|
||||
... define elements here ...
|
||||
</view>
|
||||
```
|
||||
|
||||
|
||||
|
||||
An *element* is a particular visual element, such as an image or a piece of text. You can either modify an element that already exists for a particular view (as is done in the "description" example), like this:
|
||||
|
||||
```xml
|
||||
|
@ -122,6 +120,7 @@ You can include theme files within theme files, similar to `#include` in C (thou
|
|||
|
||||
`~/.emulationstation/all_themes.xml`:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<view name="detailed">
|
||||
|
@ -135,6 +134,7 @@ You can include theme files within theme files, similar to `#include` in C (thou
|
|||
|
||||
`~/.emulationstation/snes/theme.xml`:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<include>./../all_themes.xml</include>
|
||||
|
@ -148,6 +148,7 @@ You can include theme files within theme files, similar to `#include` in C (thou
|
|||
|
||||
Is equivalent to this `snes/theme.xml`:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<view name="detailed">
|
||||
|
@ -167,6 +168,7 @@ Notice that properties that were not specified got merged (`<fontPath>`) and the
|
|||
Sometimes you want to apply the same properties to the same elements across multiple views. The `name` attribute actually works as a list (delimited by any characters of `\t\r\n ,` - that is, whitespace and commas). So, for example, to easily apply the same header to the basic, grid, and system views:
|
||||
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<view name="basic, grid, system">
|
||||
|
@ -184,6 +186,7 @@ Sometimes you want to apply the same properties to the same elements across mult
|
|||
|
||||
This is equivalent to:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<view name="basic">
|
||||
|
@ -216,6 +219,7 @@ This is equivalent to:
|
|||
You can theme multiple elements *of the same type* simultaneously. The `name` attribute actually works as a list (delimited by any characters of `\t\r\n ,` - that is, whitespace and commas), just like it does for views, as long as the elements have the same type. This is useful if you want to, say, apply the same color to all the metadata labels:
|
||||
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<view name="detailed">
|
||||
|
@ -230,6 +234,7 @@ You can theme multiple elements *of the same type* simultaneously. The `name` a
|
|||
|
||||
Which is equivalent to:
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<view name="detailed">
|
||||
|
@ -288,6 +293,7 @@ Jul 12 11:28:58 Debug: Sound::getFromTheme(): Tag not found, using fallback sou
|
|||
Example `navigationsounds.xml`, to be included from the main theme file:
|
||||
|
||||
```xml
|
||||
|
||||
<theme>
|
||||
<formatVersion>6</formatVersion>
|
||||
<feature supported="navigationsounds">
|
||||
|
@ -849,11 +855,12 @@ EmulationStation borrows the concept of "nine patches" from Android (or "9-Slice
|
|||
|
||||
#### helpsystem
|
||||
|
||||
* `pos` - type: NORMALIZED_PAIR. Default is "0.012 0.9515"
|
||||
* `pos` - type: NORMALIZED_PAIR. Default is "0.012 0.9515"
|
||||
* `origin` - type: NORMALIZED_PAIR.
|
||||
- Where on the component `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the component exactly in the middle of the screen.
|
||||
* `textColor` - type: COLOR. Default is 777777FF.
|
||||
* `iconColor` - type: COLOR. Default is 777777FF.
|
||||
- Where on the component `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place
|
||||
the component exactly in the middle of the screen.
|
||||
* `textColor` - type: COLOR. Default is 777777FF.
|
||||
* `iconColor` - type: COLOR. Default is 777777FF.
|
||||
* `fontPath` - type: PATH.
|
||||
* `fontSize` - type: FLOAT.
|
||||
|
||||
|
|
|
@ -16,8 +16,13 @@ HelpStyle::HelpStyle()
|
|||
position =
|
||||
glm::vec2{Renderer::getScreenWidth() * 0.012f, Renderer::getScreenHeight() * 0.9515f};
|
||||
origin = glm::vec2{};
|
||||
iconColor = 0x777777FF;
|
||||
textColor = 0x777777FF;
|
||||
textColorDimmed = 0x777777FF;
|
||||
iconColor = 0x777777FF;
|
||||
iconColorDimmed = 0x777777FF;
|
||||
entrySpacing = 16.0f;
|
||||
iconTextSpacing = 8.0f;
|
||||
textStyle = "uppercase";
|
||||
|
||||
if (FONT_SIZE_SMALL != 0)
|
||||
font = Font::get(FONT_SIZE_SMALL);
|
||||
|
@ -42,9 +47,92 @@ void HelpStyle::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::s
|
|||
if (elem->has("textColor"))
|
||||
textColor = elem->get<unsigned int>("textColor");
|
||||
|
||||
if (elem->has("textColorDimmed"))
|
||||
textColorDimmed = elem->get<unsigned int>("textColorDimmed");
|
||||
|
||||
if (elem->has("iconColor"))
|
||||
iconColor = elem->get<unsigned int>("iconColor");
|
||||
|
||||
if (elem->has("iconColorDimmed"))
|
||||
iconColorDimmed = elem->get<unsigned int>("iconColorDimmed");
|
||||
|
||||
if (elem->has("fontPath") || elem->has("fontSize"))
|
||||
font = Font::getFromTheme(elem, ThemeFlags::ALL, font);
|
||||
|
||||
if (elem->has("entrySpacing"))
|
||||
entrySpacing = elem->get<float>("entrySpacing");
|
||||
|
||||
if (elem->has("iconTextSpacing"))
|
||||
iconTextSpacing = elem->get<float>("iconTextSpacing");
|
||||
|
||||
if (elem->has("textStyle"))
|
||||
textStyle = elem->get<std::string>("textStyle");
|
||||
|
||||
// Load custom button icons.
|
||||
|
||||
// General.
|
||||
if (elem->has("dpad_updown"))
|
||||
mCustomButtons.dpad_updown = elem->get<std::string>("dpad_updown");
|
||||
if (elem->has("dpad_leftright"))
|
||||
mCustomButtons.dpad_leftright = elem->get<std::string>("dpad_leftright");
|
||||
if (elem->has("dpad_all"))
|
||||
mCustomButtons.dpad_all = elem->get<std::string>("dpad_all");
|
||||
if (elem->has("thumbstick_click"))
|
||||
mCustomButtons.thumbstick_click = elem->get<std::string>("thumbstick_click");
|
||||
if (elem->has("button_l"))
|
||||
mCustomButtons.button_l = elem->get<std::string>("button_l");
|
||||
if (elem->has("button_r"))
|
||||
mCustomButtons.button_r = elem->get<std::string>("button_r");
|
||||
if (elem->has("button_lr"))
|
||||
mCustomButtons.button_lr = elem->get<std::string>("button_lr");
|
||||
|
||||
// SNES.
|
||||
if (elem->has("button_a_SNES"))
|
||||
mCustomButtons.button_a_SNES = elem->get<std::string>("button_a_SNES");
|
||||
if (elem->has("button_b_SNES"))
|
||||
mCustomButtons.button_b_SNES = elem->get<std::string>("button_b_SNES");
|
||||
if (elem->has("button_x_SNES"))
|
||||
mCustomButtons.button_x_SNES = elem->get<std::string>("button_x_SNES");
|
||||
if (elem->has("button_y_SNES"))
|
||||
mCustomButtons.button_y_SNES = elem->get<std::string>("button_y_SNES");
|
||||
if (elem->has("button_start_SNES"))
|
||||
mCustomButtons.button_start_SNES = elem->get<std::string>("button_start_SNES");
|
||||
if (elem->has("button_back_SNES"))
|
||||
mCustomButtons.button_back_SNES = elem->get<std::string>("button_back_SNES");
|
||||
|
||||
// PS.
|
||||
if (elem->has("button_a_PS"))
|
||||
mCustomButtons.button_a_PS = elem->get<std::string>("button_a_PS");
|
||||
if (elem->has("button_b_PS"))
|
||||
mCustomButtons.button_b_PS = elem->get<std::string>("button_b_PS");
|
||||
if (elem->has("button_x_PS"))
|
||||
mCustomButtons.button_x_PS = elem->get<std::string>("button_x_PS");
|
||||
if (elem->has("button_y_PS"))
|
||||
mCustomButtons.button_y_PS = elem->get<std::string>("button_y_PS");
|
||||
if (elem->has("button_start_PS4"))
|
||||
mCustomButtons.button_start_PS4 = elem->get<std::string>("button_start_PS4");
|
||||
if (elem->has("button_back_PS4"))
|
||||
mCustomButtons.button_back_PS4 = elem->get<std::string>("button_back_PS4");
|
||||
if (elem->has("button_start_PS5"))
|
||||
mCustomButtons.button_start_PS5 = elem->get<std::string>("button_start_PS5");
|
||||
if (elem->has("button_back_PS5"))
|
||||
mCustomButtons.button_back_PS5 = elem->get<std::string>("button_back_PS5");
|
||||
|
||||
// XBOX.
|
||||
if (elem->has("button_a_XBOX"))
|
||||
mCustomButtons.button_a_XBOX = elem->get<std::string>("button_a_XBOX");
|
||||
if (elem->has("button_b_XBOX"))
|
||||
mCustomButtons.button_b_XBOX = elem->get<std::string>("button_b_XBOX");
|
||||
if (elem->has("button_x_XBOX"))
|
||||
mCustomButtons.button_x_XBOX = elem->get<std::string>("button_x_XBOX");
|
||||
if (elem->has("button_y_XBOX"))
|
||||
mCustomButtons.button_y_XBOX = elem->get<std::string>("button_y_XBOX");
|
||||
if (elem->has("button_start_XBOX"))
|
||||
mCustomButtons.button_start_XBOX = elem->get<std::string>("button_start_XBOX");
|
||||
if (elem->has("button_back_XBOX"))
|
||||
mCustomButtons.button_back_XBOX = elem->get<std::string>("button_back_XBOX");
|
||||
if (elem->has("button_start_XBOX360"))
|
||||
mCustomButtons.button_start_XBOX360 = elem->get<std::string>("button_start_XBOX360");
|
||||
if (elem->has("button_back_XBOX360"))
|
||||
mCustomButtons.button_back_XBOX360 = elem->get<std::string>("button_back_XBOX360");
|
||||
}
|
||||
|
|
|
@ -21,9 +21,56 @@ class ThemeData;
|
|||
struct HelpStyle {
|
||||
glm::vec2 position;
|
||||
glm::vec2 origin;
|
||||
unsigned int iconColor;
|
||||
unsigned int textColor;
|
||||
unsigned int textColorDimmed;
|
||||
unsigned int iconColor;
|
||||
unsigned int iconColorDimmed;
|
||||
std::shared_ptr<Font> font;
|
||||
float entrySpacing;
|
||||
float iconTextSpacing;
|
||||
std::string textStyle;
|
||||
|
||||
struct CustomButtonIcons {
|
||||
|
||||
// General.
|
||||
std::string dpad_updown;
|
||||
std::string dpad_leftright;
|
||||
std::string dpad_all;
|
||||
std::string thumbstick_click;
|
||||
std::string button_l;
|
||||
std::string button_r;
|
||||
std::string button_lr;
|
||||
|
||||
// SNES.
|
||||
std::string button_a_SNES;
|
||||
std::string button_b_SNES;
|
||||
std::string button_x_SNES;
|
||||
std::string button_y_SNES;
|
||||
std::string button_start_SNES;
|
||||
std::string button_back_SNES;
|
||||
|
||||
// PS.
|
||||
std::string button_a_PS;
|
||||
std::string button_b_PS;
|
||||
std::string button_x_PS;
|
||||
std::string button_y_PS;
|
||||
std::string button_start_PS4;
|
||||
std::string button_back_PS4;
|
||||
std::string button_start_PS5;
|
||||
std::string button_back_PS5;
|
||||
|
||||
// XBOX.
|
||||
std::string button_a_XBOX;
|
||||
std::string button_b_XBOX;
|
||||
std::string button_x_XBOX;
|
||||
std::string button_y_XBOX;
|
||||
std::string button_start_XBOX;
|
||||
std::string button_back_XBOX;
|
||||
std::string button_start_XBOX360;
|
||||
std::string button_back_XBOX360;
|
||||
};
|
||||
|
||||
CustomButtonIcons mCustomButtons;
|
||||
|
||||
HelpStyle(); // Default values.
|
||||
void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view);
|
||||
|
|
|
@ -151,9 +151,15 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>> The
|
|||
{{"pos", NORMALIZED_PAIR},
|
||||
{"origin", NORMALIZED_PAIR},
|
||||
{"textColor", COLOR},
|
||||
{"textColorDimmed", COLOR},
|
||||
{"iconColor", COLOR},
|
||||
{"iconColorDimmed", COLOR},
|
||||
{"fontPath", PATH},
|
||||
{"fontSize", FLOAT}}},
|
||||
{"fontSize", FLOAT},
|
||||
{"entrySpacing", FLOAT},
|
||||
{"iconTextSpacing", FLOAT},
|
||||
{"textStyle", STRING},
|
||||
{"customButtonIcon", PATH}}},
|
||||
{"navigationsounds",
|
||||
{{"systembrowseSound", PATH},
|
||||
{"quicksysselectSound", PATH},
|
||||
|
@ -192,7 +198,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>> The
|
|||
{"zIndex", FLOAT}}}};
|
||||
|
||||
#define MINIMUM_THEME_FORMAT_VERSION 3
|
||||
#define CURRENT_THEME_FORMAT_VERSION 6
|
||||
#define CURRENT_THEME_FORMAT_VERSION 7
|
||||
|
||||
// Helper.
|
||||
unsigned int getHexColor(const std::string& str)
|
||||
|
@ -496,7 +502,20 @@ void ThemeData::parseElement(const pugi::xml_node& root,
|
|||
<< ((node.text().get() != path) ? "which resolves to \"" + path + "\"" :
|
||||
"");
|
||||
}
|
||||
element.properties[node.name()] = path;
|
||||
|
||||
// Special parsing instruction for customButtonIcon -> save node as it's button
|
||||
// attribute to prevent nodes overwriting each other.
|
||||
if (strcmp(node.name(), "customButtonIcon") == 0) {
|
||||
const auto btn = node.attribute("button").as_string("");
|
||||
if (strcmp(btn, "") == 0)
|
||||
LOG(LogError)
|
||||
<< "<customButtonIcon> element requires the `button` property.";
|
||||
else
|
||||
element.properties[btn] = path;
|
||||
}
|
||||
else
|
||||
element.properties[node.name()] = path;
|
||||
|
||||
break;
|
||||
}
|
||||
case COLOR: {
|
||||
|
|
|
@ -359,6 +359,11 @@ void Window::update(int deltaTime)
|
|||
mScreensaver->update(deltaTime);
|
||||
}
|
||||
|
||||
bool Window::isBackgroundDimmed()
|
||||
{
|
||||
return !mGuiStack.empty() && (mGuiStack.front() != mGuiStack.back() || mRenderLaunchScreen);
|
||||
}
|
||||
|
||||
void Window::render()
|
||||
{
|
||||
glm::mat4 trans{Renderer::getIdentity()};
|
||||
|
@ -366,7 +371,7 @@ void Window::render()
|
|||
mRenderedHelpPrompts = false;
|
||||
|
||||
// Draw only bottom and top of GuiStack (if they are different).
|
||||
if (mGuiStack.size()) {
|
||||
if (!mGuiStack.empty()) {
|
||||
auto& bottom = mGuiStack.front();
|
||||
auto& top = mGuiStack.back();
|
||||
|
||||
|
@ -408,7 +413,7 @@ void Window::render()
|
|||
unsigned char* processedTexture =
|
||||
new unsigned char[Renderer::getScreenWidth() * Renderer::getScreenHeight() * 4];
|
||||
|
||||
// Defocus the background using multiple passes of gaussian blur, with the number
|
||||
// De-focus the background using multiple passes of gaussian blur, with the number
|
||||
// of iterations relative to the screen resolution.
|
||||
Renderer::shaderParameters backgroundParameters;
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ public:
|
|||
void removeGui(GuiComponent* gui);
|
||||
GuiComponent* peekGui();
|
||||
int getGuiStackSize() { return static_cast<int>(mGuiStack.size()); }
|
||||
bool isBackgroundDimmed();
|
||||
|
||||
bool init();
|
||||
void deinit();
|
||||
|
|
|
@ -10,15 +10,13 @@
|
|||
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "Window.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "resources/TextureResource.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#define ICON_TEXT_SPACING 8.0f // Space between [icon] and [text] (px).
|
||||
#define ENTRY_SPACING 16.0f // Space between [text] and next [icon] (px).
|
||||
|
||||
static std::map<std::string, std::string> sIconPathMap{};
|
||||
|
||||
HelpComponent::HelpComponent(Window* window)
|
||||
|
@ -31,58 +29,144 @@ void HelpComponent::assignIcons()
|
|||
{
|
||||
std::string controllerType = Settings::getInstance()->getString("InputControllerType");
|
||||
|
||||
std::map<std::string, std::string> sIconPathMapOld(sIconPathMap);
|
||||
sIconPathMap.clear();
|
||||
|
||||
// These graphics files are common between all controller types.
|
||||
sIconPathMap["up/down"] = ":/help/dpad_updown.svg";
|
||||
sIconPathMap["left/right"] = ":/help/dpad_leftright.svg";
|
||||
sIconPathMap["up/down/left/right"] = ":/help/dpad_all.svg";
|
||||
sIconPathMap["thumbstickclick"] = ":/help/thumbstick_click.svg";
|
||||
sIconPathMap["l"] = ":/help/button_l.svg";
|
||||
sIconPathMap["r"] = ":/help/button_r.svg";
|
||||
sIconPathMap["lr"] = ":/help/button_lr.svg";
|
||||
sIconPathMap["up/down"] = mStyle.mCustomButtons.dpad_updown.empty() ?
|
||||
":/help/dpad_updown.svg" :
|
||||
mStyle.mCustomButtons.dpad_updown;
|
||||
sIconPathMap["left/right"] = mStyle.mCustomButtons.dpad_leftright.empty() ?
|
||||
":/help/dpad_leftright.svg" :
|
||||
mStyle.mCustomButtons.dpad_leftright;
|
||||
sIconPathMap["up/down/left/right"] = mStyle.mCustomButtons.dpad_all.empty() ?
|
||||
":/help/dpad_all.svg" :
|
||||
mStyle.mCustomButtons.dpad_all;
|
||||
sIconPathMap["thumbstickclick"] = mStyle.mCustomButtons.thumbstick_click.empty() ?
|
||||
":/help/thumbstick_click.svg" :
|
||||
mStyle.mCustomButtons.thumbstick_click;
|
||||
sIconPathMap["l"] = mStyle.mCustomButtons.button_l.empty() ? ":/help/button_l.svg" :
|
||||
mStyle.mCustomButtons.button_l;
|
||||
sIconPathMap["r"] = mStyle.mCustomButtons.button_r.empty() ? ":/help/button_r.svg" :
|
||||
mStyle.mCustomButtons.button_r;
|
||||
sIconPathMap["lr"] = mStyle.mCustomButtons.button_lr.empty() ? ":/help/button_lr.svg" :
|
||||
mStyle.mCustomButtons.button_lr;
|
||||
|
||||
// These graphics files are custom per controller type.
|
||||
if (controllerType == "snes") {
|
||||
sIconPathMap["a"] = ":/help/button_a_SNES.svg";
|
||||
sIconPathMap["b"] = ":/help/button_b_SNES.svg";
|
||||
sIconPathMap["x"] = ":/help/button_x_SNES.svg";
|
||||
sIconPathMap["y"] = ":/help/button_y_SNES.svg";
|
||||
sIconPathMap["start"] = ":/help/button_start_SNES.svg";
|
||||
sIconPathMap["back"] = ":/help/button_back_SNES.svg";
|
||||
sIconPathMap["a"] = mStyle.mCustomButtons.button_a_SNES.empty() ?
|
||||
":/help/button_a_SNES.svg" :
|
||||
mStyle.mCustomButtons.button_a_SNES;
|
||||
sIconPathMap["b"] = mStyle.mCustomButtons.button_b_SNES.empty() ?
|
||||
":/help/button_b_SNES.svg" :
|
||||
mStyle.mCustomButtons.button_b_SNES;
|
||||
sIconPathMap["x"] = mStyle.mCustomButtons.button_x_SNES.empty() ?
|
||||
":/help/button_x_SNES.svg" :
|
||||
mStyle.mCustomButtons.button_x_SNES;
|
||||
sIconPathMap["y"] = mStyle.mCustomButtons.button_y_SNES.empty() ?
|
||||
":/help/button_y_SNES.svg" :
|
||||
mStyle.mCustomButtons.button_y_SNES;
|
||||
sIconPathMap["start"] = mStyle.mCustomButtons.button_start_SNES.empty() ?
|
||||
":/help/button_start_SNES.svg" :
|
||||
mStyle.mCustomButtons.button_start_SNES;
|
||||
sIconPathMap["back"] = mStyle.mCustomButtons.button_back_SNES.empty() ?
|
||||
":/help/button_back_SNES.svg" :
|
||||
mStyle.mCustomButtons.button_back_SNES;
|
||||
}
|
||||
else if (controllerType == "ps4") {
|
||||
sIconPathMap["a"] = ":/help/button_a_PS.svg";
|
||||
sIconPathMap["b"] = ":/help/button_b_PS.svg";
|
||||
sIconPathMap["x"] = ":/help/button_x_PS.svg";
|
||||
sIconPathMap["y"] = ":/help/button_y_PS.svg";
|
||||
sIconPathMap["start"] = ":/help/button_start_PS4.svg";
|
||||
sIconPathMap["back"] = ":/help/button_back_PS4.svg";
|
||||
sIconPathMap["a"] = mStyle.mCustomButtons.button_a_PS.empty() ?
|
||||
":/help/button_a_PS.svg" :
|
||||
mStyle.mCustomButtons.button_a_PS;
|
||||
sIconPathMap["b"] = mStyle.mCustomButtons.button_b_PS.empty() ?
|
||||
":/help/button_b_PS.svg" :
|
||||
mStyle.mCustomButtons.button_b_PS;
|
||||
sIconPathMap["x"] = mStyle.mCustomButtons.button_x_PS.empty() ?
|
||||
":/help/button_x_PS.svg" :
|
||||
mStyle.mCustomButtons.button_x_PS;
|
||||
sIconPathMap["y"] = mStyle.mCustomButtons.button_y_PS.empty() ?
|
||||
":/help/button_y_PS.svg" :
|
||||
mStyle.mCustomButtons.button_y_PS;
|
||||
sIconPathMap["start"] = mStyle.mCustomButtons.button_start_PS4.empty() ?
|
||||
":/help/button_start_PS4.svg" :
|
||||
mStyle.mCustomButtons.button_start_PS4;
|
||||
sIconPathMap["back"] = mStyle.mCustomButtons.button_back_PS4.empty() ?
|
||||
":/help/button_back_PS4.svg" :
|
||||
mStyle.mCustomButtons.button_back_PS4;
|
||||
}
|
||||
else if (controllerType == "ps5") {
|
||||
sIconPathMap["a"] = ":/help/button_a_PS.svg";
|
||||
sIconPathMap["b"] = ":/help/button_b_PS.svg";
|
||||
sIconPathMap["x"] = ":/help/button_x_PS.svg";
|
||||
sIconPathMap["y"] = ":/help/button_y_PS.svg";
|
||||
sIconPathMap["start"] = ":/help/button_start_PS5.svg";
|
||||
sIconPathMap["back"] = ":/help/button_back_PS5.svg";
|
||||
sIconPathMap["a"] = mStyle.mCustomButtons.button_a_PS.empty() ?
|
||||
":/help/button_a_PS.svg" :
|
||||
mStyle.mCustomButtons.button_a_PS;
|
||||
sIconPathMap["b"] = mStyle.mCustomButtons.button_b_PS.empty() ?
|
||||
":/help/button_b_PS.svg" :
|
||||
mStyle.mCustomButtons.button_b_PS;
|
||||
sIconPathMap["x"] = mStyle.mCustomButtons.button_x_PS.empty() ?
|
||||
":/help/button_x_PS.svg" :
|
||||
mStyle.mCustomButtons.button_x_PS;
|
||||
sIconPathMap["y"] = mStyle.mCustomButtons.button_y_PS.empty() ?
|
||||
":/help/button_y_PS.svg" :
|
||||
mStyle.mCustomButtons.button_y_PS;
|
||||
sIconPathMap["start"] = mStyle.mCustomButtons.button_start_PS5.empty() ?
|
||||
":/help/button_start_PS5.svg" :
|
||||
mStyle.mCustomButtons.button_start_PS5;
|
||||
sIconPathMap["back"] = mStyle.mCustomButtons.button_back_PS5.empty() ?
|
||||
":/help/button_back_PS5.svg" :
|
||||
mStyle.mCustomButtons.button_back_PS5;
|
||||
}
|
||||
else if (controllerType == "xbox360") {
|
||||
sIconPathMap["a"] = ":/help/button_a_XBOX.svg";
|
||||
sIconPathMap["b"] = ":/help/button_b_XBOX.svg";
|
||||
sIconPathMap["x"] = ":/help/button_x_XBOX.svg";
|
||||
sIconPathMap["y"] = ":/help/button_y_XBOX.svg";
|
||||
sIconPathMap["start"] = ":/help/button_start_XBOX360.svg";
|
||||
sIconPathMap["back"] = ":/help/button_back_XBOX360.svg";
|
||||
|
||||
sIconPathMap["a"] = mStyle.mCustomButtons.button_a_XBOX.empty() ?
|
||||
":/help/button_a_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_a_XBOX;
|
||||
sIconPathMap["b"] = mStyle.mCustomButtons.button_b_XBOX.empty() ?
|
||||
":/help/button_b_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_b_XBOX;
|
||||
sIconPathMap["x"] = mStyle.mCustomButtons.button_x_XBOX.empty() ?
|
||||
":/help/button_x_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_x_XBOX;
|
||||
sIconPathMap["y"] = mStyle.mCustomButtons.button_y_XBOX.empty() ?
|
||||
":/help/button_y_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_y_XBOX;
|
||||
sIconPathMap["start"] = mStyle.mCustomButtons.button_start_XBOX360.empty() ?
|
||||
":/help/button_start_XBOX360.svg" :
|
||||
mStyle.mCustomButtons.button_start_XBOX360;
|
||||
sIconPathMap["back"] = mStyle.mCustomButtons.button_back_XBOX360.empty() ?
|
||||
":/help/button_back_XBOX360.svg" :
|
||||
mStyle.mCustomButtons.button_back_XBOX360;
|
||||
}
|
||||
else {
|
||||
// Xbox One and later.
|
||||
sIconPathMap["a"] = ":/help/button_a_XBOX.svg";
|
||||
sIconPathMap["b"] = ":/help/button_b_XBOX.svg";
|
||||
sIconPathMap["x"] = ":/help/button_x_XBOX.svg";
|
||||
sIconPathMap["y"] = ":/help/button_y_XBOX.svg";
|
||||
sIconPathMap["start"] = ":/help/button_start_XBOX.svg";
|
||||
sIconPathMap["back"] = ":/help/button_back_XBOX.svg";
|
||||
sIconPathMap["a"] = mStyle.mCustomButtons.button_a_XBOX.empty() ?
|
||||
":/help/button_a_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_a_XBOX;
|
||||
sIconPathMap["b"] = mStyle.mCustomButtons.button_b_XBOX.empty() ?
|
||||
":/help/button_b_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_b_XBOX;
|
||||
sIconPathMap["x"] = mStyle.mCustomButtons.button_x_XBOX.empty() ?
|
||||
":/help/button_x_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_x_XBOX;
|
||||
sIconPathMap["y"] = mStyle.mCustomButtons.button_y_XBOX.empty() ?
|
||||
":/help/button_y_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_y_XBOX;
|
||||
sIconPathMap["start"] = mStyle.mCustomButtons.button_start_XBOX.empty() ?
|
||||
":/help/button_start_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_start_XBOX;
|
||||
sIconPathMap["back"] = mStyle.mCustomButtons.button_back_XBOX.empty() ?
|
||||
":/help/button_back_XBOX.svg" :
|
||||
mStyle.mCustomButtons.button_back_XBOX;
|
||||
}
|
||||
|
||||
// Invalidate cache for icons that have changed.
|
||||
auto it = sIconPathMap.begin();
|
||||
while (it != sIconPathMap.end()) {
|
||||
if (sIconPathMapOld.find(it->first) != sIconPathMapOld.end()) {
|
||||
if (sIconPathMapOld[it->first] != sIconPathMap[it->first]) {
|
||||
if (mIconCache.find(it->first) != mIconCache.end()) {
|
||||
mIconCache.erase(mIconCache.find(it->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,6 +186,7 @@ void HelpComponent::setStyle(const HelpStyle& style)
|
|||
{
|
||||
mStyle = style;
|
||||
updateGrid();
|
||||
assignIcons();
|
||||
}
|
||||
|
||||
void HelpComponent::updateGrid()
|
||||
|
@ -124,19 +209,31 @@ void HelpComponent::updateGrid()
|
|||
float width = 0;
|
||||
const float height = std::round(font->getLetterHeight() * 1.25f);
|
||||
|
||||
// State variable indicating whether gui is dimmed.
|
||||
bool isDimmed = mWindow->isBackgroundDimmed();
|
||||
|
||||
for (auto it = mPrompts.cbegin(); it != mPrompts.cend(); it++) {
|
||||
auto icon = std::make_shared<ImageComponent>(mWindow);
|
||||
icon->setImage(getIconTexture(it->first.c_str()));
|
||||
icon->setColorShift(mStyle.iconColor);
|
||||
icon->setColorShift(isDimmed ? mStyle.iconColorDimmed : mStyle.iconColor);
|
||||
icon->setResize(0, height);
|
||||
icons.push_back(icon);
|
||||
|
||||
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(it->second),
|
||||
font, mStyle.textColor);
|
||||
// Apply text style and color from the theme to the label and add it to the label list.
|
||||
std::string lblInput = it->second;
|
||||
if (mStyle.textStyle == "lowercase")
|
||||
lblInput = Utils::String::toLower(lblInput);
|
||||
else if (mStyle.textStyle == "camelcase")
|
||||
lblInput = Utils::String::toCamelCase(lblInput);
|
||||
else
|
||||
lblInput = Utils::String::toUpper(lblInput);
|
||||
auto lbl = std::make_shared<TextComponent>(
|
||||
mWindow, lblInput, font, isDimmed ? mStyle.textColorDimmed : mStyle.textColor);
|
||||
labels.push_back(lbl);
|
||||
|
||||
width += icon->getSize().x + lbl->getSize().x +
|
||||
((ICON_TEXT_SPACING + ENTRY_SPACING) * Renderer::getScreenWidthModifier());
|
||||
width +=
|
||||
icon->getSize().x + lbl->getSize().x +
|
||||
((mStyle.iconTextSpacing + mStyle.entrySpacing) * Renderer::getScreenWidthModifier());
|
||||
}
|
||||
|
||||
mGrid->setSize(width, height);
|
||||
|
@ -144,8 +241,8 @@ void HelpComponent::updateGrid()
|
|||
for (unsigned int i = 0; i < icons.size(); i++) {
|
||||
const int col = i * 4;
|
||||
mGrid->setColWidthPerc(col, icons.at(i)->getSize().x / width);
|
||||
mGrid->setColWidthPerc(col + 1,
|
||||
(ICON_TEXT_SPACING * Renderer::getScreenWidthModifier()) / width);
|
||||
mGrid->setColWidthPerc(
|
||||
col + 1, (mStyle.iconTextSpacing * Renderer::getScreenWidthModifier()) / width);
|
||||
mGrid->setColWidthPerc(col + 2, labels.at(i)->getSize().x / width);
|
||||
|
||||
mGrid->setEntry(icons.at(i), glm::ivec2{col, 0}, false, false);
|
||||
|
@ -167,6 +264,7 @@ std::shared_ptr<TextureResource> HelpComponent::getIconTexture(const char* name)
|
|||
LOG(LogError) << "Unknown help icon \"" << name << "\"";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ResourceManager::getInstance()->fileExists(pathLookup->second)) {
|
||||
LOG(LogError) << "Couldn't load help icon \"" << name << "\" as the file \""
|
||||
<< pathLookup->second << "\" is missing";
|
||||
|
|
|
@ -541,6 +541,27 @@ namespace Utils
|
|||
return stringUpper;
|
||||
}
|
||||
|
||||
std::string toCamelCase(const std::string& stringArg)
|
||||
{
|
||||
std::string line = stringArg;
|
||||
bool active = true;
|
||||
|
||||
for (int i = 0; line[i] != '\0'; i++) {
|
||||
if (std::isalpha(line[i])) {
|
||||
if (active) {
|
||||
line[i] = Utils::String::toUpper(std::string(1, line[i]))[0];
|
||||
active = false;
|
||||
}
|
||||
else
|
||||
line[i] = Utils::String::toLower(std::string(1, line[i]))[0];
|
||||
}
|
||||
else if (line[i] == ' ')
|
||||
active = true;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
std::string trim(const std::string& stringArg)
|
||||
{
|
||||
const size_t strBegin = stringArg.find_first_not_of(" \t");
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Utils
|
|||
size_t moveCursor(const std::string& stringArg, const size_t cursor, const int amount);
|
||||
std::string toLower(const std::string& stringArg);
|
||||
std::string toUpper(const std::string& stringArg);
|
||||
std::string toCamelCase(const std::string& stringArg);
|
||||
std::string trim(const std::string& stringArg);
|
||||
std::string replace(const std::string& stringArg,
|
||||
const std::string& replace,
|
||||
|
|
Loading…
Reference in a new issue