2016-05-04 19:24:41 +02:00
|
|
|
/*****************************************************************************
|
2020-07-21 15:04:34 +02:00
|
|
|
* Copyright (c) 2014-2020 OpenRCT2 developers
|
2016-05-04 19:24:41 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
2016-05-04 19:24:41 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
2016-05-04 19:24:41 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2017-01-12 14:00:04 +01:00
|
|
|
#pragma warning(disable : 4706) // assignment within conditional expression
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
#include "Theme.h"
|
|
|
|
|
|
|
|
#include "Window.h"
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2018-08-12 13:50:40 +02:00
|
|
|
#include <algorithm>
|
2018-06-22 23:20:47 +02:00
|
|
|
#include <jansson.h>
|
|
|
|
#include <memory>
|
|
|
|
#include <openrct2/Context.h>
|
|
|
|
#include <openrct2/PlatformEnvironment.h>
|
2018-06-02 12:31:14 +02:00
|
|
|
#include <openrct2/common.h>
|
|
|
|
#include <openrct2/config/Config.h>
|
|
|
|
#include <openrct2/core/File.h>
|
|
|
|
#include <openrct2/core/FileScanner.h>
|
|
|
|
#include <openrct2/core/Guard.hpp>
|
|
|
|
#include <openrct2/core/Json.hpp>
|
|
|
|
#include <openrct2/core/Path.hpp>
|
|
|
|
#include <openrct2/core/String.hpp>
|
|
|
|
#include <openrct2/drawing/Drawing.h>
|
2018-06-22 23:20:47 +02:00
|
|
|
#include <openrct2/interface/Colour.h>
|
2018-06-02 12:31:14 +02:00
|
|
|
#include <openrct2/localisation/Language.h>
|
|
|
|
#include <openrct2/localisation/StringIds.h>
|
2018-06-22 23:20:47 +02:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <vector>
|
2018-01-06 19:16:15 +01:00
|
|
|
|
|
|
|
using namespace OpenRCT2;
|
2016-01-26 01:05:40 +01:00
|
|
|
|
|
|
|
struct WindowThemeDesc;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents a window theming style such as the colour scheme.
|
|
|
|
*/
|
|
|
|
struct WindowTheme
|
|
|
|
{
|
|
|
|
colour_t Colours[6];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents the style for a particular type of window.
|
|
|
|
*/
|
2016-01-29 01:06:02 +01:00
|
|
|
struct UIThemeWindowEntry
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
|
|
|
rct_windowclass WindowClass;
|
2018-06-22 23:20:47 +02:00
|
|
|
WindowTheme Theme;
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* ToJson() const;
|
|
|
|
static UIThemeWindowEntry FromJson(const WindowThemeDesc* wtDesc, const json_t* json);
|
2016-01-26 01:05:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents a user interface theme. Contains window colour schemes and appearance features.
|
|
|
|
*/
|
2016-01-28 23:22:02 +01:00
|
|
|
class UITheme
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2016-01-28 23:22:02 +01:00
|
|
|
public:
|
2018-06-22 23:20:47 +02:00
|
|
|
std::string Name;
|
2016-09-13 19:26:44 +02:00
|
|
|
std::vector<UIThemeWindowEntry> Entries;
|
2018-06-22 23:20:47 +02:00
|
|
|
uint8_t Flags = 0;
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
explicit UITheme(const std::string& name)
|
2018-01-06 19:16:15 +01:00
|
|
|
: Name(name)
|
|
|
|
{
|
|
|
|
}
|
2016-01-28 23:22:02 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
const UIThemeWindowEntry* GetEntry(rct_windowclass windowClass) const;
|
|
|
|
void SetEntry(const UIThemeWindowEntry* entry);
|
|
|
|
void RemoveEntry(rct_windowclass windowClass);
|
2016-01-29 01:06:02 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* ToJson() const;
|
|
|
|
bool WriteToFile(const std::string& path) const;
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static UITheme* FromJson(const json_t* json);
|
|
|
|
static UITheme* FromFile(const std::string& path);
|
|
|
|
static UITheme CreatePredefined(const std::string& name, const UIThemeWindowEntry* entries, uint8_t flags);
|
2016-01-26 01:05:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents the theme descriptor for a specific window type including the default colour scheme.
|
|
|
|
*/
|
|
|
|
struct WindowThemeDesc
|
|
|
|
{
|
|
|
|
rct_windowclass WindowClass;
|
2018-06-22 23:20:47 +02:00
|
|
|
const utf8* WindowClassSZ;
|
|
|
|
rct_string_id WindowName;
|
|
|
|
uint8_t NumColours;
|
|
|
|
WindowTheme DefaultTheme;
|
2016-01-26 01:05:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#pragma region Window Theme Descriptors
|
|
|
|
|
2018-01-10 16:14:36 +01:00
|
|
|
// clang-format off
|
2016-01-26 01:05:40 +01:00
|
|
|
#define COLOURS_1(c0) 1, { { (c0), 0, 0, 0, 0, 0 } }
|
|
|
|
#define COLOURS_2(c0, c1) 2, { { (c0), (c1), 0, 0, 0, 0 } }
|
|
|
|
#define COLOURS_3(c0, c1, c2) 3, { { (c0), (c1), (c2), 0, 0, 0 } }
|
|
|
|
#define COLOURS_4(c0, c1, c2, c3) 4, { { (c0), (c1), (c2), (c3), 0, 0 } }
|
|
|
|
#define COLOURS_5(c0, c1, c2, c3, c4) 5, { { (c0), (c1), (c2), (c3), (c4), 0 } }
|
|
|
|
#define COLOURS_6(c0, c1, c2, c3, c4, c5) 6, { { (c0), (c1), (c2), (c3), (c4), (c5) } }
|
|
|
|
|
|
|
|
#define THEME_DEF_END { 0xFF, { 0, 0, 0, 0, 0, 0 } }
|
|
|
|
|
|
|
|
#define TWINDOW(window_class, window_name, window_string_id, theme) { window_class, window_name, window_string_id, theme }
|
|
|
|
|
|
|
|
#define THEME_WC(wc) wc, #wc
|
|
|
|
|
2018-01-11 14:50:31 +01:00
|
|
|
static constexpr const WindowThemeDesc WindowThemeDescriptors[] =
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-05-17 13:19:42 +02:00
|
|
|
// WindowClass, WindowClassSZ WindowName NumColours, DefaultTheme
|
|
|
|
{ THEME_WC(WC_TOP_TOOLBAR), STR_THEMES_WINDOW_TOP_TOOLBAR, COLOURS_4(COLOUR_LIGHT_BLUE, COLOUR_DARK_GREEN, COLOUR_DARK_BROWN, COLOUR_GREY ) },
|
|
|
|
{ THEME_WC(WC_BOTTOM_TOOLBAR), STR_THEMES_WINDOW_BOTTOM_TOOLBAR, COLOURS_4(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), COLOUR_BLACK, COLOUR_BRIGHT_GREEN ) },
|
|
|
|
{ THEME_WC(WC_RIDE), STR_THEMES_WINDOW_RIDE, COLOURS_3(COLOUR_GREY, COLOUR_BORDEAUX_RED, COLOUR_GREY ) },
|
|
|
|
{ THEME_WC(WC_RIDE_CONSTRUCTION), STR_THEMES_WINDOW_RIDE_CONSTRUCTION, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_RIDE_LIST), STR_THEMES_WINDOW_RIDE_LIST, COLOURS_3(COLOUR_GREY, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) },
|
|
|
|
{ THEME_WC(WC_SAVE_PROMPT), STR_THEMES_WINDOW_SAVE_PROMPT, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) },
|
|
|
|
{ THEME_WC(WC_CONSTRUCT_RIDE), STR_THEMES_WINDOW_CONSTRUCT_RIDE, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) },
|
|
|
|
{ THEME_WC(WC_DEMOLISH_RIDE_PROMPT), STR_THEMES_WINDOW_DEMOLISH_RIDE_PROMPT, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) },
|
|
|
|
{ THEME_WC(WC_SCENERY), STR_THEMES_WINDOW_SCENERY, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_GREEN, COLOUR_DARK_GREEN ) },
|
2020-02-01 22:38:54 +01:00
|
|
|
{ THEME_WC(WC_SCENERY_SCATTER), STR_THEMES_WINDOW_SCENERY_SCATTER, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_GREEN, COLOUR_DARK_GREEN ) },
|
2017-05-17 13:19:42 +02:00
|
|
|
{ THEME_WC(WC_OPTIONS), STR_THEMES_WINDOW_OPTIONS, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_FOOTPATH), STR_THEMES_WINDOW_FOOTPATH, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_LAND), STR_THEMES_WINDOW_LAND, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_WATER), STR_THEMES_WINDOW_WATER, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_PEEP), STR_THEMES_WINDOW_PEEP, COLOURS_3(COLOUR_GREY, COLOUR_OLIVE_GREEN, COLOUR_OLIVE_GREEN ) },
|
|
|
|
{ THEME_WC(WC_GUEST_LIST), STR_THEMES_WINDOW_GUEST_LIST, COLOURS_3(COLOUR_GREY, COLOUR_OLIVE_GREEN, COLOUR_OLIVE_GREEN ) },
|
|
|
|
{ THEME_WC(WC_STAFF_LIST), STR_THEMES_WINDOW_STAFF_LIST, COLOURS_3(COLOUR_GREY, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE ) },
|
|
|
|
{ THEME_WC(WC_FIRE_PROMPT), STR_THEMES_WINDOW_FIRE_PROMPT, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) },
|
|
|
|
{ THEME_WC(WC_PARK_INFORMATION), STR_THEMES_WINDOW_PARK_INFORMATION, COLOURS_3(COLOUR_GREY, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) },
|
|
|
|
{ THEME_WC(WC_FINANCES), STR_THEMES_WINDOW_FINANCES, COLOURS_3(COLOUR_GREY, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) },
|
|
|
|
{ THEME_WC(WC_TITLE_MENU), STR_THEMES_WINDOW_TITLE_MENU_BUTTONS, COLOURS_3(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN) ) },
|
|
|
|
{ THEME_WC(WC_TITLE_EXIT), STR_THEMES_WINDOW_TITLE_MENU_EXIT, COLOURS_3(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN) ) },
|
|
|
|
{ THEME_WC(WC_RECENT_NEWS), STR_THEMES_WINDOW_RECENT_NEWS, COLOURS_3(COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK ) },
|
|
|
|
{ THEME_WC(WC_SCENARIO_SELECT), STR_THEMES_WINDOW_TITLE_MENU_SCENARIO_SELECTION, COLOURS_3(COLOUR_GREY, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) },
|
|
|
|
{ THEME_WC(WC_TRACK_DESIGN_LIST), STR_THEMES_WINDOW_TRACK_DESIGN_LIST, COLOURS_3(COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) },
|
|
|
|
{ THEME_WC(WC_TRACK_DESIGN_PLACE), STR_THEMES_WINDOW_TRACK_DESIGN_PLACE, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_NEW_CAMPAIGN), STR_THEMES_WINDOW_NEW_CAMPAIGN, COLOURS_3(COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) },
|
|
|
|
{ THEME_WC(WC_KEYBOARD_SHORTCUT_LIST), STR_THEMES_WINDOW_KEYBOARD_SHORTCUT_LIST, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
2016-07-14 14:07:49 +02:00
|
|
|
{ THEME_WC(WC_CHANGE_KEYBOARD_SHORTCUT), STR_THEMES_WINDOW_CHANGE_KEYBOARD_SHORTCUT, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
2017-05-17 13:19:42 +02:00
|
|
|
{ THEME_WC(WC_MAP), STR_THEMES_WINDOW_MAP, COLOURS_2(COLOUR_DARK_GREEN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_BANNER), STR_THEMES_WINDOW_BANNER, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_EDITOR_OBJECT_SELECTION), STR_THEMES_WINDOW_EDITOR_OBJECT_SELECTION, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) },
|
|
|
|
{ THEME_WC(WC_EDITOR_INVENTION_LIST), STR_THEMES_WINDOW_EDITOR_INVENTION_LIST, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) },
|
|
|
|
{ THEME_WC(WC_EDITOR_SCENARIO_OPTIONS), STR_THEMES_WINDOW_EDITOR_SCENARIO_OPTIONS, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) },
|
2016-07-14 14:07:49 +02:00
|
|
|
{ THEME_WC(WC_EDTIOR_OBJECTIVE_OPTIONS), STR_THEMES_WINDOW_EDTIOR_OBJECTIVE_OPTIONS, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) },
|
2017-05-17 13:19:42 +02:00
|
|
|
{ THEME_WC(WC_MANAGE_TRACK_DESIGN), STR_THEMES_WINDOW_MANAGE_TRACK_DESIGN, COLOURS_3(COLOUR_GREY, COLOUR_GREY, COLOUR_GREY ) },
|
|
|
|
{ THEME_WC(WC_TRACK_DELETE_PROMPT), STR_THEMES_WINDOW_TRACK_DELETE_PROMPT, COLOURS_3(COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) },
|
|
|
|
{ THEME_WC(WC_INSTALL_TRACK), STR_THEMES_WINDOW_INSTALL_TRACK, COLOURS_3(COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) },
|
|
|
|
{ THEME_WC(WC_CLEAR_SCENERY), STR_THEMES_WINDOW_CLEAR_SCENERY, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_CHEATS), STR_CHEAT_TITLE, COLOURS_2(COLOUR_GREY, COLOUR_DARK_YELLOW ) },
|
|
|
|
{ THEME_WC(WC_RESEARCH), STR_THEMES_WINDOW_RESEARCH, COLOURS_3(COLOUR_GREY, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) },
|
|
|
|
{ THEME_WC(WC_VIEWPORT), STR_THEMES_WINDOW_VIEWPORT, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_MAPGEN), STR_THEMES_WINDOW_MAPGEN, COLOURS_3(COLOUR_DARK_GREEN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) },
|
|
|
|
{ THEME_WC(WC_LOADSAVE), STR_THEMES_WINDOW_LOADSAVE, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_LOADSAVE_OVERWRITE_PROMPT), STR_THEMES_WINDOW_LOADSAVE_OVERWRITE_PROMPT, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) },
|
|
|
|
{ THEME_WC(WC_TITLE_OPTIONS), STR_THEMES_WINDOW_TITLE_MENU_OPTIONS, COLOURS_3(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN) ) },
|
|
|
|
{ THEME_WC(WC_LAND_RIGHTS), STR_THEMES_WINDOW_LAND_RIGHTS, COLOURS_3(COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) },
|
|
|
|
{ THEME_WC(WC_THEMES), STR_THEMES_WINDOW_THEMES, COLOURS_3(COLOUR_GREY, COLOUR_DARK_GREEN, COLOUR_DARK_GREEN ) },
|
|
|
|
{ THEME_WC(WC_STAFF), STR_THEMES_WINDOW_STAFF, COLOURS_3(COLOUR_GREY, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE ) },
|
|
|
|
{ THEME_WC(WC_EDITOR_TRACK_BOTTOM_TOOLBAR), STR_THEMES_WINDOW_BOTTOM_TOOLBAR_TRACK_EDITOR, COLOURS_3(TRANSLUCENT(COLOUR_LIGHT_BLUE), TRANSLUCENT(COLOUR_LIGHT_BLUE), TRANSLUCENT(COLOUR_LIGHT_BLUE) ) },
|
|
|
|
{ THEME_WC(WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR), STR_THEMES_WINDOW_BOTTOM_TOOLBAR_SCENARIO_EDITOR, COLOURS_3(TRANSLUCENT(COLOUR_LIGHT_BROWN), TRANSLUCENT(COLOUR_LIGHT_BROWN), TRANSLUCENT(COLOUR_MOSS_GREEN) ) },
|
|
|
|
{ THEME_WC(WC_TITLE_EDITOR), STR_TITLE_EDITOR_TITLE, COLOURS_3(COLOUR_GREY, COLOUR_OLIVE_GREEN, COLOUR_OLIVE_GREEN ) },
|
|
|
|
{ THEME_WC(WC_TILE_INSPECTOR), STR_TILE_INSPECTOR_TITLE, COLOURS_2(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_VIEW_CLIPPING), STR_VIEW_CLIPPING_TITLE, COLOURS_1(COLOUR_DARK_GREEN ) },
|
|
|
|
{ THEME_WC(WC_CHANGELOG), STR_CHANGELOG_TITLE, COLOURS_2(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_MULTIPLAYER), STR_MULTIPLAYER, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_PLAYER), STR_THEMES_WINDOW_PLAYER, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_NETWORK_STATUS), STR_THEMES_WINDOW_NETWORK_STATUS, COLOURS_1(COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_SERVER_LIST), STR_SERVER_LIST, COLOURS_2(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) },
|
|
|
|
{ THEME_WC(WC_CHAT), STR_CHAT, COLOURS_1(TRANSLUCENT(COLOUR_GREY) ) },
|
2018-01-18 02:34:24 +01:00
|
|
|
{ THEME_WC(WC_CONSOLE), STR_CONSOLE, COLOURS_2(TRANSLUCENT(COLOUR_LIGHT_BLUE), COLOUR_WHITE ) },
|
2016-01-26 01:05:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Pre-defined Themes
|
|
|
|
|
|
|
|
#define COLOURS_RCT1(c0, c1, c2, c3, c4, c5) { { (c0), (c1), (c2), (c3), (c4), (c5) } }
|
|
|
|
|
2018-01-11 14:50:31 +01:00
|
|
|
static constexpr const UIThemeWindowEntry PredefinedThemeRCT1_Entries[] =
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-10-02 11:45:28 +02:00
|
|
|
{ WC_TOP_TOOLBAR, COLOURS_RCT1(COLOUR_GREY, COLOUR_GREY, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_BOTTOM_TOOLBAR, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_YELLOW, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_RIDE, COLOURS_RCT1(COLOUR_BORDEAUX_RED, COLOUR_GREY, COLOUR_SATURATED_GREEN, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_RIDE_LIST, COLOURS_RCT1(COLOUR_BORDEAUX_RED, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_CONSTRUCT_RIDE, COLOURS_RCT1(COLOUR_BORDEAUX_RED, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_PEEP, COLOURS_RCT1(COLOUR_LIGHT_BROWN, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_GUEST_LIST, COLOURS_RCT1(COLOUR_LIGHT_BROWN, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_STAFF_LIST, COLOURS_RCT1(COLOUR_DARK_GREEN, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_FINANCES, COLOURS_RCT1(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_TITLE_MENU, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_TITLE_EXIT, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_NEW_CAMPAIGN, COLOURS_RCT1(COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_TITLE_OPTIONS, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_STAFF, COLOURS_RCT1(COLOUR_DARK_GREEN, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_OPTIONS, COLOURS_RCT1(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_KEYBOARD_SHORTCUT_LIST, COLOURS_RCT1(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
{ WC_CHANGE_KEYBOARD_SHORTCUT, COLOURS_RCT1(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) },
|
|
|
|
|
2016-01-26 01:05:40 +01:00
|
|
|
THEME_DEF_END
|
|
|
|
};
|
|
|
|
|
2018-01-11 14:50:31 +01:00
|
|
|
static constexpr const UIThemeWindowEntry PredefinedThemeRCT2_Entries[] =
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
|
|
|
THEME_DEF_END
|
|
|
|
};
|
|
|
|
|
2016-01-28 23:22:02 +01:00
|
|
|
const UITheme PredefinedThemeRCT1 = UITheme::CreatePredefined(
|
2017-10-16 10:04:09 +02:00
|
|
|
"*RCT1", PredefinedThemeRCT1_Entries, UITHEME_FLAG_USE_LIGHTS_RIDE |
|
2016-01-28 23:22:02 +01:00
|
|
|
UITHEME_FLAG_USE_LIGHTS_PARK |
|
2017-08-16 22:27:20 +02:00
|
|
|
UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT |
|
|
|
|
UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR);
|
2016-01-28 23:22:02 +01:00
|
|
|
|
|
|
|
const UITheme PredefinedThemeRCT2 = UITheme::CreatePredefined(
|
2017-10-16 10:04:09 +02:00
|
|
|
"*RCT2", PredefinedThemeRCT2_Entries, 0);
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2017-10-16 10:04:09 +02:00
|
|
|
struct PredefinedTheme
|
|
|
|
{
|
|
|
|
const UITheme* Theme;
|
|
|
|
rct_string_id Name;
|
|
|
|
};
|
|
|
|
|
2018-01-11 14:50:31 +01:00
|
|
|
static constexpr const PredefinedTheme PredefinedThemes[] = {
|
2017-10-16 10:04:09 +02:00
|
|
|
{ &PredefinedThemeRCT1, STR_TITLE_SEQUENCE_RCT1 },
|
|
|
|
{ &PredefinedThemeRCT2, STR_TITLE_SEQUENCE_RCT2 }
|
2016-01-26 01:05:40 +01:00
|
|
|
};
|
2018-01-10 16:14:36 +01:00
|
|
|
// clang-format on
|
2016-01-26 01:05:40 +01:00
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static const WindowThemeDesc* GetWindowThemeDescriptor(rct_windowclass windowClass)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
for (const auto& desc : WindowThemeDescriptors)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-12-20 02:50:18 +01:00
|
|
|
if (desc.WindowClass == windowClass)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-12-20 02:50:18 +01:00
|
|
|
return &desc;
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static const WindowThemeDesc* GetWindowThemeDescriptor(const utf8* windowClassSZ)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
for (const auto& desc : WindowThemeDescriptors)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-12-20 02:50:18 +01:00
|
|
|
if (String::Equals(desc.WindowClassSZ, windowClassSZ))
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-12-20 02:50:18 +01:00
|
|
|
return &desc;
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ThrowThemeLoadException()
|
|
|
|
{
|
2018-01-02 20:23:22 +01:00
|
|
|
throw std::runtime_error("Invalid JSON UI theme entry.");
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma region UIThemeEntry
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* UIThemeWindowEntry::ToJson() const
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(WindowClass);
|
2017-01-13 12:35:26 +01:00
|
|
|
if (wtDesc == nullptr)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2016-11-13 20:17:49 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* jsonColours = json_array();
|
|
|
|
for (uint8_t i = 0; i < wtDesc->NumColours; i++)
|
|
|
|
{
|
2016-01-26 01:05:40 +01:00
|
|
|
colour_t colour = Theme.Colours[i];
|
|
|
|
json_array_append_new(jsonColours, json_integer(colour));
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* jsonEntry = json_object();
|
2016-01-26 01:05:40 +01:00
|
|
|
json_object_set_new(jsonEntry, "colours", jsonColours);
|
|
|
|
|
|
|
|
return jsonEntry;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
UIThemeWindowEntry UIThemeWindowEntry::FromJson(const WindowThemeDesc* wtDesc, const json_t* json)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* jsonColours = json_object_get(json, "colours");
|
2016-01-26 01:05:40 +01:00
|
|
|
if (jsonColours == nullptr)
|
|
|
|
{
|
|
|
|
ThrowThemeLoadException();
|
|
|
|
}
|
|
|
|
|
2020-03-28 20:36:51 +01:00
|
|
|
uint8_t numColours = static_cast<uint8_t>(json_array_size(jsonColours));
|
2018-06-20 17:11:35 +02:00
|
|
|
numColours = std::min(numColours, wtDesc->NumColours);
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
UIThemeWindowEntry result{};
|
2016-01-28 23:22:02 +01:00
|
|
|
result.WindowClass = wtDesc->WindowClass;
|
|
|
|
result.Theme = wtDesc->DefaultTheme;
|
2016-11-13 20:17:49 +01:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
for (uint8_t i = 0; i < numColours; i++)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2020-03-28 20:36:51 +01:00
|
|
|
result.Theme.Colours[i] = static_cast<colour_t>(json_integer_value(json_array_get(jsonColours, i)));
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region UITheme
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
const UIThemeWindowEntry* UITheme::GetEntry(rct_windowclass windowClass) const
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
for (const auto& entry : Entries)
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2017-12-06 00:12:36 +01:00
|
|
|
if (entry.WindowClass == windowClass)
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2017-12-06 00:12:36 +01:00
|
|
|
return &entry;
|
2016-01-29 01:06:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
void UITheme::SetEntry(const UIThemeWindowEntry* newEntry)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
|
|
|
// Try to replace existing entry
|
2018-06-22 23:20:47 +02:00
|
|
|
for (auto& entry : Entries)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-12-06 00:12:36 +01:00
|
|
|
if (entry.WindowClass == newEntry->WindowClass)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2017-12-06 00:12:36 +01:00
|
|
|
entry = *newEntry;
|
2016-01-26 01:05:40 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-13 19:26:44 +02:00
|
|
|
Entries.push_back(*newEntry);
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void UITheme::RemoveEntry(rct_windowclass windowClass)
|
|
|
|
{
|
|
|
|
// Remove existing entry
|
2016-09-13 19:26:44 +02:00
|
|
|
for (size_t i = 0; i < Entries.size(); i++)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
UIThemeWindowEntry* entry = &Entries[i];
|
2016-01-26 01:05:40 +01:00
|
|
|
if (entry->WindowClass == windowClass)
|
|
|
|
{
|
2016-09-13 19:26:44 +02:00
|
|
|
Entries.erase(Entries.begin() + i);
|
2016-01-26 01:05:40 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* UITheme::ToJson() const
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
|
|
|
// Create entries
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* jsonEntries = json_object();
|
|
|
|
for (const UIThemeWindowEntry& entry : Entries)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(entry.WindowClass);
|
2017-01-13 12:35:26 +01:00
|
|
|
if (wtDesc == nullptr)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2016-01-28 23:22:02 +01:00
|
|
|
json_object_set_new(jsonEntries, wtDesc->WindowClassSZ, entry.ToJson());
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create theme object
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* jsonTheme = json_object();
|
2018-01-06 19:16:15 +01:00
|
|
|
json_object_set_new(jsonTheme, "name", json_string(Name.c_str()));
|
2016-01-26 01:05:40 +01:00
|
|
|
json_object_set_new(jsonTheme, "entries", jsonEntries);
|
|
|
|
|
|
|
|
json_object_set_new(jsonTheme, "useLightsRide", json_boolean(Flags & UITHEME_FLAG_USE_LIGHTS_RIDE));
|
|
|
|
json_object_set_new(jsonTheme, "useLightsPark", json_boolean(Flags & UITHEME_FLAG_USE_LIGHTS_PARK));
|
2018-06-22 23:20:47 +02:00
|
|
|
json_object_set_new(
|
|
|
|
jsonTheme, "useAltScenarioSelectFont", json_boolean(Flags & UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT));
|
2017-08-16 22:27:20 +02:00
|
|
|
json_object_set_new(jsonTheme, "useFullBottomToolbar", json_boolean(Flags & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR));
|
2016-01-26 01:05:40 +01:00
|
|
|
|
|
|
|
return jsonTheme;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
bool UITheme::WriteToFile(const std::string& path) const
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* jsonTheme = ToJson();
|
|
|
|
bool result;
|
2016-01-26 01:05:40 +01:00
|
|
|
try
|
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
Json::WriteToFile(path.c_str(), jsonTheme, JSON_INDENT(4) | JSON_PRESERVE_ORDER);
|
2016-01-28 23:22:02 +01:00
|
|
|
result = true;
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
2018-06-22 23:20:47 +02:00
|
|
|
catch (const std::exception& ex)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
log_error("Unable to save %s: %s", path.c_str(), ex.what());
|
2016-01-28 23:22:02 +01:00
|
|
|
result = false;
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
2016-01-28 23:22:02 +01:00
|
|
|
|
|
|
|
json_decref(jsonTheme);
|
|
|
|
return result;
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
UITheme* UITheme::FromJson(const json_t* json)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const char* themeName = json_string_value(json_object_get(json, "name"));
|
2016-01-26 01:05:40 +01:00
|
|
|
if (themeName == nullptr)
|
|
|
|
{
|
|
|
|
ThrowThemeLoadException();
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* jsonEntries = json_object_get(json, "entries");
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
UITheme* result = nullptr;
|
2016-01-26 01:05:40 +01:00
|
|
|
try
|
|
|
|
{
|
2016-01-28 23:22:02 +01:00
|
|
|
result = new UITheme(themeName);
|
2016-01-26 01:05:40 +01:00
|
|
|
|
|
|
|
if (json_is_true(json_object_get(json, "useLightsRide")))
|
|
|
|
{
|
|
|
|
result->Flags |= UITHEME_FLAG_USE_LIGHTS_RIDE;
|
|
|
|
}
|
|
|
|
if (json_is_true(json_object_get(json, "useLightsPark")))
|
|
|
|
{
|
|
|
|
result->Flags |= UITHEME_FLAG_USE_LIGHTS_PARK;
|
|
|
|
}
|
|
|
|
if (json_is_true(json_object_get(json, "useAltScenarioSelectFont")))
|
|
|
|
{
|
|
|
|
result->Flags |= UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT;
|
|
|
|
}
|
2017-08-16 22:27:20 +02:00
|
|
|
if (json_is_true(json_object_get(json, "useFullBottomToolbar")))
|
|
|
|
{
|
|
|
|
result->Flags |= UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR;
|
|
|
|
}
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
const char* jkey;
|
|
|
|
json_t* jvalue;
|
2016-01-26 01:05:40 +01:00
|
|
|
json_object_foreach(jsonEntries, jkey, jvalue)
|
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(jkey);
|
|
|
|
if (wtDesc == nullptr)
|
|
|
|
continue;
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2016-01-29 01:06:02 +01:00
|
|
|
UIThemeWindowEntry entry = UIThemeWindowEntry::FromJson(wtDesc, jvalue);
|
2016-01-28 23:22:02 +01:00
|
|
|
result->SetEntry(&entry);
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2018-06-22 23:20:47 +02:00
|
|
|
catch (const std::exception&)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2016-01-28 23:22:02 +01:00
|
|
|
delete result;
|
2016-11-30 23:32:47 +01:00
|
|
|
throw;
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
UITheme* UITheme::FromFile(const std::string& path)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
json_t* json = nullptr;
|
|
|
|
UITheme* result = nullptr;
|
2016-01-26 01:05:40 +01:00
|
|
|
try
|
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
json = Json::ReadFromFile(path.c_str());
|
2016-01-28 23:22:02 +01:00
|
|
|
result = UITheme::FromJson(json);
|
2016-01-26 01:05:40 +01:00
|
|
|
}
|
2018-06-22 23:20:47 +02:00
|
|
|
catch (const std::exception&)
|
2016-01-26 01:05:40 +01:00
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
log_error("Unable to read theme: %s", path.c_str());
|
2016-01-26 01:05:40 +01:00
|
|
|
result = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
json_decref(json);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
UITheme UITheme::CreatePredefined(const std::string& name, const UIThemeWindowEntry* entries, uint8_t flags)
|
2016-01-28 23:22:02 +01:00
|
|
|
{
|
|
|
|
auto theme = UITheme(name);
|
|
|
|
theme.Flags = flags | UITHEME_FLAG_PREDEFINED;
|
2016-01-26 01:05:40 +01:00
|
|
|
|
2016-01-28 23:22:02 +01:00
|
|
|
size_t numEntries = 0;
|
2018-06-22 23:20:47 +02:00
|
|
|
for (const UIThemeWindowEntry* entry = entries; entry->WindowClass != 255; entry++)
|
2016-01-28 23:22:02 +01:00
|
|
|
{
|
|
|
|
numEntries++;
|
|
|
|
}
|
|
|
|
|
2016-09-13 19:26:44 +02:00
|
|
|
theme.Entries = std::vector<UIThemeWindowEntry>(entries, entries + numEntries);
|
2016-01-28 23:22:02 +01:00
|
|
|
return theme;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
2016-01-29 01:06:02 +01:00
|
|
|
|
|
|
|
namespace ThemeManager
|
|
|
|
{
|
|
|
|
struct AvailableTheme
|
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
std::string Path;
|
|
|
|
std::string Name;
|
2016-01-29 01:06:02 +01:00
|
|
|
};
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static std::string CurrentThemePath;
|
|
|
|
static UITheme* CurrentTheme;
|
2017-10-09 17:13:14 +02:00
|
|
|
static std::vector<AvailableTheme> AvailableThemes;
|
2018-06-22 23:20:47 +02:00
|
|
|
static size_t ActiveAvailableThemeIndex = SIZE_MAX;
|
|
|
|
static size_t NumPredefinedThemes = 0;
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
std::string GetThemeFileName(const std::string& name);
|
2016-03-08 19:03:07 +01:00
|
|
|
bool EnsureThemeDirectoryExists();
|
2018-01-06 19:16:15 +01:00
|
|
|
std::string GetThemePath();
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static void GetAvailableThemes(std::vector<AvailableTheme>* outThemes)
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2016-07-16 15:17:36 +02:00
|
|
|
Guard::ArgumentNotNull(outThemes, GUARD_LINE);
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2016-09-13 19:26:44 +02:00
|
|
|
outThemes->clear();
|
2016-01-29 20:39:31 +01:00
|
|
|
|
|
|
|
NumPredefinedThemes = 0;
|
2017-10-16 10:04:09 +02:00
|
|
|
for (auto predefinedTheme : PredefinedThemes)
|
2016-01-29 20:39:31 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
AvailableTheme theme{};
|
2018-01-06 19:16:15 +01:00
|
|
|
theme.Name = predefinedTheme.Theme->Name;
|
|
|
|
outThemes->push_back(std::move(theme));
|
2016-01-29 20:39:31 +01:00
|
|
|
|
|
|
|
NumPredefinedThemes++;
|
|
|
|
}
|
|
|
|
|
2018-01-06 19:16:15 +01:00
|
|
|
auto themesPattern = Path::Combine(GetThemePath(), "*.json");
|
|
|
|
auto scanner = std::unique_ptr<IFileScanner>(Path::ScanDirectory(themesPattern, true));
|
|
|
|
while (scanner->Next())
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
auto fileInfo = scanner->GetFileInfo();
|
|
|
|
auto name = Path::GetFileNameWithoutExtension(std::string(fileInfo->Name));
|
2016-11-13 20:17:49 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
AvailableTheme theme{};
|
2018-01-06 19:16:15 +01:00
|
|
|
theme.Name = name;
|
|
|
|
theme.Path = GetThemeFileName(theme.Name);
|
|
|
|
outThemes->push_back(std::move(theme));
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-01-06 19:16:15 +01:00
|
|
|
if (Path::Equals(CurrentThemePath, scanner->GetPath()))
|
|
|
|
{
|
|
|
|
ActiveAvailableThemeIndex = outThemes->size() - 1;
|
2016-01-29 20:39:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static void LoadTheme(UITheme* theme)
|
2016-01-29 20:39:31 +01:00
|
|
|
{
|
2016-01-30 00:18:28 +01:00
|
|
|
if (CurrentTheme == theme)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-29 20:39:31 +01:00
|
|
|
if (CurrentTheme != nullptr)
|
|
|
|
{
|
2016-01-30 00:18:28 +01:00
|
|
|
if (!(CurrentTheme->Flags & UITHEME_FLAG_PREDEFINED))
|
2016-01-29 20:39:31 +01:00
|
|
|
{
|
|
|
|
delete CurrentTheme;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CurrentTheme = theme;
|
2018-01-06 19:16:15 +01:00
|
|
|
CurrentThemePath.clear();
|
2016-01-29 20:39:31 +01:00
|
|
|
|
|
|
|
gfx_invalidate_screen();
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static void LoadTheme(const std::string& path)
|
2016-01-29 20:39:31 +01:00
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
auto theme = UITheme::FromFile(path);
|
2016-01-29 20:39:31 +01:00
|
|
|
if (theme == nullptr)
|
|
|
|
{
|
|
|
|
// Fall-back to default
|
2020-03-28 20:36:51 +01:00
|
|
|
theme = const_cast<UITheme*>(&PredefinedThemeRCT2);
|
2016-01-30 00:18:28 +01:00
|
|
|
LoadTheme(theme);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LoadTheme(theme);
|
2018-01-06 19:16:15 +01:00
|
|
|
CurrentThemePath = path;
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
static bool LoadThemeByConfigName(const utf8* name)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2016-09-13 19:26:44 +02:00
|
|
|
for (size_t i = 0; i < ThemeManager::AvailableThemes.size(); i++)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const auto& theme = ThemeManager::AvailableThemes[i];
|
2018-01-06 19:16:15 +01:00
|
|
|
if (String::Equals(name, theme.Name))
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
if (theme.Path.empty())
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2020-03-28 20:36:51 +01:00
|
|
|
LoadTheme(const_cast<UITheme*>(PredefinedThemes[i].Theme));
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
LoadTheme(theme.Path);
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
|
|
|
ActiveAvailableThemeIndex = i;
|
|
|
|
return true;
|
|
|
|
}
|
2016-01-29 01:06:02 +01:00
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
return false;
|
2016-01-29 20:39:31 +01:00
|
|
|
}
|
|
|
|
|
2016-07-13 00:46:51 +02:00
|
|
|
static void Initialise()
|
2016-01-29 20:39:31 +01:00
|
|
|
{
|
|
|
|
ThemeManager::GetAvailableThemes(&ThemeManager::AvailableThemes);
|
2020-03-28 20:36:51 +01:00
|
|
|
LoadTheme(const_cast<UITheme*>(&PredefinedThemeRCT2));
|
2016-01-29 20:39:31 +01:00
|
|
|
ActiveAvailableThemeIndex = 1;
|
2016-01-30 00:18:28 +01:00
|
|
|
|
|
|
|
bool configValid = false;
|
|
|
|
if (!String::IsNullOrEmpty(gConfigInterface.current_theme_preset))
|
|
|
|
{
|
2017-10-16 10:04:09 +02:00
|
|
|
if (LoadThemeByConfigName(gConfigInterface.current_theme_preset))
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
|
|
|
configValid = true;
|
|
|
|
}
|
|
|
|
}
|
2016-11-13 20:17:49 +01:00
|
|
|
|
2016-01-30 00:18:28 +01:00
|
|
|
if (!configValid)
|
|
|
|
{
|
2017-10-16 10:04:09 +02:00
|
|
|
String::DiscardDuplicate(&gConfigInterface.current_theme_preset, theme_manager_get_available_theme_config_name(1));
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
std::string GetThemeFileName(const std::string& name)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
auto themeDirectory = GetThemePath();
|
|
|
|
auto themePath = Path::Combine(themeDirectory, name + ".json");
|
|
|
|
return themePath;
|
2016-01-29 01:06:02 +01:00
|
|
|
}
|
2016-03-08 19:03:07 +01:00
|
|
|
|
|
|
|
bool EnsureThemeDirectoryExists()
|
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
auto path = GetThemePath();
|
|
|
|
Path::CreateDirectory(path);
|
|
|
|
return true;
|
|
|
|
}
|
2018-06-22 23:20:47 +02:00
|
|
|
catch (const std::exception&)
|
2018-01-06 19:16:15 +01:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-08 19:03:07 +01:00
|
|
|
}
|
|
|
|
|
2018-01-06 19:16:15 +01:00
|
|
|
std::string GetThemePath()
|
2016-03-08 19:03:07 +01:00
|
|
|
{
|
2018-01-06 19:16:15 +01:00
|
|
|
auto context = GetContext();
|
|
|
|
auto env = context->GetPlatformEnvironment();
|
|
|
|
return env->GetDirectoryPath(DIRBASE::USER, DIRID::THEME);
|
2016-03-08 19:03:07 +01:00
|
|
|
}
|
2018-05-04 22:40:09 +02:00
|
|
|
} // namespace ThemeManager
|
2016-01-29 01:06:02 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
void theme_manager_load_available_themes()
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::GetAvailableThemes(&ThemeManager::AvailableThemes);
|
|
|
|
}
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
size_t theme_manager_get_num_available_themes()
|
|
|
|
{
|
|
|
|
return ThemeManager::AvailableThemes.size();
|
|
|
|
}
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
const utf8* theme_manager_get_available_theme_path(size_t index)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
return ThemeManager::AvailableThemes[index].Path.c_str();
|
|
|
|
}
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
const utf8* theme_manager_get_available_theme_config_name(size_t index)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
return ThemeManager::AvailableThemes[index].Name.c_str();
|
|
|
|
}
|
2018-06-22 23:20:47 +02:00
|
|
|
const utf8* theme_manager_get_available_theme_name(size_t index)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
if (index < ThemeManager::NumPredefinedThemes)
|
|
|
|
return language_get_string(PredefinedThemes[index].Name);
|
|
|
|
return ThemeManager::AvailableThemes[index].Name.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t theme_manager_get_active_available_theme_index()
|
|
|
|
{
|
|
|
|
return ThemeManager::ActiveAvailableThemeIndex;
|
|
|
|
}
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
void theme_manager_set_active_available_theme(size_t index)
|
|
|
|
{
|
|
|
|
if (index < ThemeManager::NumPredefinedThemes)
|
2016-01-29 20:39:31 +01:00
|
|
|
{
|
2020-03-28 20:36:51 +01:00
|
|
|
ThemeManager::LoadTheme(const_cast<UITheme*>(PredefinedThemes[index].Theme));
|
2016-01-29 20:39:31 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
else
|
2016-01-29 20:39:31 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
auto path = ThemeManager::AvailableThemes[index].Path;
|
|
|
|
ThemeManager::LoadTheme(path);
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
// HACK Check if theme load failed and fell back to RCT2
|
|
|
|
if (ThemeManager::CurrentThemePath.empty())
|
|
|
|
{
|
|
|
|
index = 1;
|
2016-01-29 20:39:31 +01:00
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::ActiveAvailableThemeIndex = index;
|
|
|
|
String::DiscardDuplicate(&gConfigInterface.current_theme_preset, theme_manager_get_available_theme_config_name(index));
|
|
|
|
|
|
|
|
colour_scheme_update_all();
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
size_t theme_get_index_for_name(const utf8* name)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
size_t count = ThemeManager::AvailableThemes.size();
|
|
|
|
for (size_t i = 0; i < count; i++)
|
2017-10-16 10:04:09 +02:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const utf8* tn = theme_manager_get_available_theme_name(i);
|
2018-02-01 18:49:14 +01:00
|
|
|
if (String::Equals(tn, name, true))
|
2017-10-16 10:04:09 +02:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
return i;
|
2017-10-16 10:04:09 +02:00
|
|
|
}
|
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
return SIZE_MAX;
|
|
|
|
}
|
2017-10-16 10:04:09 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint8_t theme_get_colour(rct_windowclass wc, uint8_t index)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const UIThemeWindowEntry* entry = ThemeManager::CurrentTheme->GetEntry(wc);
|
2018-02-01 18:49:14 +01:00
|
|
|
if (entry == nullptr)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* desc = GetWindowThemeDescriptor(wc);
|
2018-02-01 18:49:14 +01:00
|
|
|
if (desc == nullptr)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
return 0;
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
return desc->DefaultTheme.Colours[index];
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
else
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
return entry->Theme.Colours[index];
|
|
|
|
}
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
void theme_set_colour(rct_windowclass wc, uint8_t index, colour_t colour)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
UIThemeWindowEntry entry{};
|
2018-02-01 18:49:14 +01:00
|
|
|
entry.WindowClass = wc;
|
|
|
|
|
2020-04-19 14:08:22 +02:00
|
|
|
auto currentEntry = const_cast<UIThemeWindowEntry*>(ThemeManager::CurrentTheme->GetEntry(wc));
|
2018-02-01 18:49:14 +01:00
|
|
|
if (currentEntry != nullptr)
|
|
|
|
{
|
|
|
|
entry.Theme = currentEntry->Theme;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* desc = GetWindowThemeDescriptor(wc);
|
2018-02-01 18:49:14 +01:00
|
|
|
if (desc == nullptr)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
return;
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
entry.Theme = desc->DefaultTheme;
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
entry.Theme.Colours[index] = colour;
|
|
|
|
ThemeManager::CurrentTheme->SetEntry(&entry);
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
theme_save();
|
|
|
|
}
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint8_t theme_get_flags()
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
return ThemeManager::CurrentTheme->Flags;
|
|
|
|
}
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
void theme_set_flags(uint8_t flags)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
ThemeManager::CurrentTheme->Flags = flags;
|
|
|
|
theme_save();
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
void theme_save()
|
|
|
|
{
|
|
|
|
ThemeManager::EnsureThemeDirectoryExists();
|
|
|
|
ThemeManager::CurrentTheme->WriteToFile(ThemeManager::CurrentThemePath);
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
void theme_rename(const utf8* name)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
const auto oldPath = ThemeManager::CurrentThemePath;
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::EnsureThemeDirectoryExists();
|
|
|
|
auto newPath = ThemeManager::GetThemeFileName(name);
|
|
|
|
File::Move(oldPath, newPath);
|
|
|
|
ThemeManager::CurrentThemePath = newPath;
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::CurrentTheme->Name = name;
|
|
|
|
ThemeManager::CurrentTheme->WriteToFile(ThemeManager::CurrentThemePath);
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
theme_manager_load_available_themes();
|
|
|
|
for (size_t i = 0; i < ThemeManager::AvailableThemes.size(); i++)
|
|
|
|
{
|
|
|
|
if (Path::Equals(newPath, ThemeManager::AvailableThemes[i].Path))
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::ActiveAvailableThemeIndex = i;
|
|
|
|
String::DiscardDuplicate(&gConfigInterface.current_theme_preset, theme_manager_get_available_theme_config_name(1));
|
|
|
|
break;
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
void theme_duplicate(const utf8* name)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
ThemeManager::EnsureThemeDirectoryExists();
|
|
|
|
auto newPath = ThemeManager::GetThemeFileName(name);
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
// Copy the theme, save it and then load it back in
|
2018-06-22 23:20:47 +02:00
|
|
|
UITheme* newTheme = new UITheme(*ThemeManager::CurrentTheme);
|
2018-02-01 18:49:14 +01:00
|
|
|
newTheme->Name = name;
|
|
|
|
newTheme->Flags &= ~UITHEME_FLAG_PREDEFINED;
|
|
|
|
newTheme->WriteToFile(newPath);
|
|
|
|
delete newTheme;
|
2016-02-03 19:39:08 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::LoadTheme(newPath);
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
theme_manager_load_available_themes();
|
|
|
|
for (size_t i = 0; i < ThemeManager::AvailableThemes.size(); i++)
|
|
|
|
{
|
|
|
|
if (Path::Equals(newPath, ThemeManager::AvailableThemes[i].Path))
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::ActiveAvailableThemeIndex = i;
|
|
|
|
String::DiscardDuplicate(&gConfigInterface.current_theme_preset, theme_manager_get_available_theme_config_name(i));
|
|
|
|
break;
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
void theme_delete()
|
|
|
|
{
|
|
|
|
File::Delete(ThemeManager::CurrentThemePath);
|
2020-03-28 20:36:51 +01:00
|
|
|
ThemeManager::LoadTheme(const_cast<UITheme*>(&PredefinedThemeRCT2));
|
2018-02-01 18:49:14 +01:00
|
|
|
ThemeManager::ActiveAvailableThemeIndex = 1;
|
|
|
|
String::DiscardDuplicate(&gConfigInterface.current_theme_preset, theme_manager_get_available_theme_config_name(1));
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
void theme_manager_initialise()
|
|
|
|
{
|
|
|
|
ThemeManager::Initialise();
|
|
|
|
}
|
2016-01-29 20:39:31 +01:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint8_t theme_desc_get_num_colours(rct_windowclass wc)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* desc = GetWindowThemeDescriptor(wc);
|
2018-02-01 18:49:14 +01:00
|
|
|
if (desc == nullptr)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
return 0;
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
return desc->NumColours;
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
rct_string_id theme_desc_get_name(rct_windowclass wc)
|
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* desc = GetWindowThemeDescriptor(wc);
|
2018-02-01 18:49:14 +01:00
|
|
|
if (desc == nullptr)
|
2016-01-30 00:18:28 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
return STR_EMPTY;
|
2016-01-30 00:18:28 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
return desc->WindowName;
|
|
|
|
}
|
2016-01-30 00:18:28 +01:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
void colour_scheme_update_all()
|
|
|
|
{
|
2019-06-27 22:28:07 +02:00
|
|
|
window_visit_each([](rct_window* w) { colour_scheme_update(w); });
|
2018-02-01 18:49:14 +01:00
|
|
|
}
|
2017-08-04 13:18:29 +02:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
void colour_scheme_update(rct_window* window)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
|
|
|
colour_scheme_update_by_class(window, window->classification);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
void colour_scheme_update_by_class(rct_window* window, rct_windowclass classification)
|
2018-02-01 18:49:14 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowTheme* windowTheme;
|
|
|
|
const UIThemeWindowEntry* entry = ThemeManager::CurrentTheme->GetEntry(classification);
|
2018-02-01 18:49:14 +01:00
|
|
|
if (entry != nullptr)
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
windowTheme = &entry->Theme;
|
2016-01-29 01:06:02 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
else
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2018-06-22 23:20:47 +02:00
|
|
|
const WindowThemeDesc* desc = GetWindowThemeDescriptor(classification);
|
2018-02-01 18:49:14 +01:00
|
|
|
|
|
|
|
// Some windows don't have a theme set (e.g. main window, title screen)
|
|
|
|
if (desc == nullptr)
|
2016-01-29 01:06:02 +01:00
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
return;
|
2016-01-29 01:06:02 +01:00
|
|
|
}
|
2017-05-17 13:19:42 +02:00
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
windowTheme = &desc->DefaultTheme;
|
|
|
|
}
|
2016-01-29 01:06:02 +01:00
|
|
|
|
2018-06-22 23:20:47 +02:00
|
|
|
for (int32_t i = 0; i < 6; i++)
|
|
|
|
{
|
2018-02-01 18:49:14 +01:00
|
|
|
window->colours[i] = windowTheme->Colours[i];
|
2016-01-29 01:06:02 +01:00
|
|
|
}
|
2018-02-01 18:49:14 +01:00
|
|
|
// Some windows need to be transparent even if the colours aren't.
|
|
|
|
// There doesn't seem to be any side-effects for all windows being transparent
|
|
|
|
window->flags |= WF_TRANSPARENT;
|
2016-01-29 01:06:02 +01:00
|
|
|
}
|