mirror of https://github.com/OpenRCT2/OpenRCT2.git
start work on theme manager
This commit is contained in:
parent
de17eb7279
commit
0eb57e5fb5
|
@ -5,6 +5,7 @@ extern "C"
|
||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "Math.hpp"
|
||||||
#include "Memory.hpp"
|
#include "Memory.hpp"
|
||||||
#include "Path.hpp"
|
#include "Path.hpp"
|
||||||
#include "String.hpp"
|
#include "String.hpp"
|
||||||
|
@ -17,6 +18,29 @@ namespace Path
|
||||||
return safe_strcat_path(buffer, src, bufferSize);
|
return safe_strcat_path(buffer, src, bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utf8 * GetFileNameWithoutExtension(utf8 * buffer, size_t bufferSize, const utf8 * path)
|
||||||
|
{
|
||||||
|
const utf8 * lastDot = nullptr;
|
||||||
|
const utf8 * ch = path;
|
||||||
|
for (; ch != '\0'; ch++)
|
||||||
|
{
|
||||||
|
if (*ch == '.')
|
||||||
|
{
|
||||||
|
lastDot = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastDot == nullptr)
|
||||||
|
{
|
||||||
|
return String::Set(buffer, bufferSize, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t truncatedLength = Math::Min<size_t>(bufferSize - 1, lastDot - path);
|
||||||
|
Memory::Copy(buffer, path, truncatedLength);
|
||||||
|
buffer[truncatedLength] = '\0';
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
utf8 * GetAbsolute(utf8 *buffer, size_t bufferSize, const utf8 * relativePath)
|
utf8 * GetAbsolute(utf8 *buffer, size_t bufferSize, const utf8 * relativePath)
|
||||||
{
|
{
|
||||||
#if __WINDOWS__
|
#if __WINDOWS__
|
||||||
|
|
|
@ -8,5 +8,6 @@ extern "C"
|
||||||
namespace Path
|
namespace Path
|
||||||
{
|
{
|
||||||
utf8 * Append(utf8 * buffer, size_t bufferSize, const utf8 * src);
|
utf8 * Append(utf8 * buffer, size_t bufferSize, const utf8 * src);
|
||||||
utf8 * GetAbsolute(utf8 *buffer, size_t bufferSize, const utf8 * relativePath);
|
utf8 * GetFileNameWithoutExtension(utf8 * buffer, size_t bufferSize, const utf8 * path);
|
||||||
|
utf8 * GetAbsolute(utf8 * buffer, size_t bufferSize, const utf8 * relativePath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ extern "C"
|
||||||
#include "../core/List.hpp"
|
#include "../core/List.hpp"
|
||||||
#include "../core/Math.hpp"
|
#include "../core/Math.hpp"
|
||||||
#include "../core/Memory.hpp"
|
#include "../core/Memory.hpp"
|
||||||
|
#include "../core/Path.hpp"
|
||||||
#include "../core/String.hpp"
|
#include "../core/String.hpp"
|
||||||
#include "../core/Util.hpp"
|
#include "../core/Util.hpp"
|
||||||
|
|
||||||
|
@ -36,14 +37,14 @@ struct WindowTheme
|
||||||
/**
|
/**
|
||||||
* Represents the style for a particular type of window.
|
* Represents the style for a particular type of window.
|
||||||
*/
|
*/
|
||||||
struct UIThemeEntry
|
struct UIThemeWindowEntry
|
||||||
{
|
{
|
||||||
rct_windowclass WindowClass;
|
rct_windowclass WindowClass;
|
||||||
WindowTheme Theme;
|
WindowTheme Theme;
|
||||||
|
|
||||||
|
|
||||||
json_t * ToJson() const;
|
json_t * ToJson() const;
|
||||||
static UIThemeEntry FromJson(const WindowThemeDesc * wtDesc, const json_t * json);
|
static UIThemeWindowEntry FromJson(const WindowThemeDesc * wtDesc, const json_t * json);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,22 +53,24 @@ struct UIThemeEntry
|
||||||
class UITheme
|
class UITheme
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
utf8 * Name;
|
utf8 * Name;
|
||||||
List<UIThemeEntry> Entries;
|
List<UIThemeWindowEntry> Entries;
|
||||||
uint8 Flags;
|
uint8 Flags;
|
||||||
|
|
||||||
UITheme(const utf8 * name);
|
UITheme(const utf8 * name);
|
||||||
UITheme(const UITheme & name);
|
UITheme(const UITheme & name);
|
||||||
~UITheme();
|
~UITheme();
|
||||||
|
|
||||||
void SetEntry(const UIThemeEntry * entry);
|
const UIThemeWindowEntry * GetEntry(rct_windowclass windowClass) const;
|
||||||
void RemoveEntry(rct_windowclass windowClass);
|
void SetEntry(const UIThemeWindowEntry * entry);
|
||||||
|
void RemoveEntry(rct_windowclass windowClass);
|
||||||
|
|
||||||
json_t * ToJson() const;
|
json_t * ToJson() const;
|
||||||
bool WriteToFile(const utf8 * path) const;
|
bool WriteToFile(const utf8 * path) const;
|
||||||
|
|
||||||
static UITheme * FromJson(const json_t * json);
|
static UITheme * FromJson(const json_t * json);
|
||||||
static UITheme * FromFile(const utf8 * path);
|
static UITheme * FromFile(const utf8 * path);
|
||||||
static UITheme CreatePredefined(const utf8 * name, const UIThemeEntry * entries, uint8 flags);
|
static UITheme CreatePredefined(const utf8 * name, const UIThemeWindowEntry * entries, uint8 flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,7 +162,7 @@ WindowThemeDesc WindowThemeDescriptors[] =
|
||||||
|
|
||||||
#define COLOURS_RCT1(c0, c1, c2, c3, c4, c5) { { (c0), (c1), (c2), (c3), (c4), (c5) } }
|
#define COLOURS_RCT1(c0, c1, c2, c3, c4, c5) { { (c0), (c1), (c2), (c3), (c4), (c5) } }
|
||||||
|
|
||||||
UIThemeEntry PredefinedThemeRCT1_Entries[] =
|
UIThemeWindowEntry PredefinedThemeRCT1_Entries[] =
|
||||||
{
|
{
|
||||||
{ WC_TOP_TOOLBAR, COLOURS_RCT1(COLOUR_GREY, COLOUR_GREY, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK) },
|
{ 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_BOTTOM_TOOLBAR, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_YELLOW, COLOUR_BLACK, COLOUR_BLACK) },
|
||||||
|
@ -178,7 +181,7 @@ UIThemeEntry PredefinedThemeRCT1_Entries[] =
|
||||||
THEME_DEF_END
|
THEME_DEF_END
|
||||||
};
|
};
|
||||||
|
|
||||||
UIThemeEntry PredefinedThemeRCT2_Entries[] =
|
UIThemeWindowEntry PredefinedThemeRCT2_Entries[] =
|
||||||
{
|
{
|
||||||
THEME_DEF_END
|
THEME_DEF_END
|
||||||
};
|
};
|
||||||
|
@ -232,7 +235,7 @@ static void ThrowThemeLoadException()
|
||||||
|
|
||||||
#pragma region UIThemeEntry
|
#pragma region UIThemeEntry
|
||||||
|
|
||||||
json_t * UIThemeEntry::ToJson() const
|
json_t * UIThemeWindowEntry::ToJson() const
|
||||||
{
|
{
|
||||||
const WindowThemeDesc * wtDesc = GetWindowThemeDescriptor(WindowClass);
|
const WindowThemeDesc * wtDesc = GetWindowThemeDescriptor(WindowClass);
|
||||||
|
|
||||||
|
@ -248,7 +251,7 @@ json_t * UIThemeEntry::ToJson() const
|
||||||
return jsonEntry;
|
return jsonEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
UIThemeEntry UIThemeEntry::FromJson(const WindowThemeDesc * wtDesc, const json_t * json)
|
UIThemeWindowEntry UIThemeWindowEntry::FromJson(const WindowThemeDesc * wtDesc, const json_t * json)
|
||||||
{
|
{
|
||||||
json_t * jsonColours = json_object_get(json, "colours");
|
json_t * jsonColours = json_object_get(json, "colours");
|
||||||
if (jsonColours == nullptr)
|
if (jsonColours == nullptr)
|
||||||
|
@ -259,7 +262,7 @@ UIThemeEntry UIThemeEntry::FromJson(const WindowThemeDesc * wtDesc, const json_t
|
||||||
uint8 numColours = (uint8)json_array_size(jsonColours);
|
uint8 numColours = (uint8)json_array_size(jsonColours);
|
||||||
numColours = Math::Min(numColours, wtDesc->NumColours);
|
numColours = Math::Min(numColours, wtDesc->NumColours);
|
||||||
|
|
||||||
UIThemeEntry result;
|
UIThemeWindowEntry result;
|
||||||
result.WindowClass = wtDesc->WindowClass;
|
result.WindowClass = wtDesc->WindowClass;
|
||||||
result.Theme = wtDesc->DefaultTheme;
|
result.Theme = wtDesc->DefaultTheme;
|
||||||
|
|
||||||
|
@ -293,12 +296,25 @@ UITheme::~UITheme()
|
||||||
Memory::Free(Name);
|
Memory::Free(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITheme::SetEntry(const UIThemeEntry * newEntry)
|
const UIThemeWindowEntry * UITheme::GetEntry(rct_windowclass windowClass) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < Entries.GetCount(); i++)
|
||||||
|
{
|
||||||
|
const UIThemeWindowEntry * entry = &Entries[i];
|
||||||
|
if (entry->WindowClass == windowClass)
|
||||||
|
{
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITheme::SetEntry(const UIThemeWindowEntry * newEntry)
|
||||||
{
|
{
|
||||||
// Try to replace existing entry
|
// Try to replace existing entry
|
||||||
for (size_t i = 0; i < Entries.GetCount(); i++)
|
for (size_t i = 0; i < Entries.GetCount(); i++)
|
||||||
{
|
{
|
||||||
UIThemeEntry * entry = &Entries[i];
|
UIThemeWindowEntry * entry = &Entries[i];
|
||||||
if (entry->WindowClass == newEntry->WindowClass)
|
if (entry->WindowClass == newEntry->WindowClass)
|
||||||
{
|
{
|
||||||
*entry = *newEntry;
|
*entry = *newEntry;
|
||||||
|
@ -314,7 +330,7 @@ void UITheme::RemoveEntry(rct_windowclass windowClass)
|
||||||
// Remove existing entry
|
// Remove existing entry
|
||||||
for (size_t i = 0; i < Entries.GetCount(); i++)
|
for (size_t i = 0; i < Entries.GetCount(); i++)
|
||||||
{
|
{
|
||||||
UIThemeEntry * entry = &Entries[i];
|
UIThemeWindowEntry * entry = &Entries[i];
|
||||||
if (entry->WindowClass == windowClass)
|
if (entry->WindowClass == windowClass)
|
||||||
{
|
{
|
||||||
Entries.RemoveAt(i);
|
Entries.RemoveAt(i);
|
||||||
|
@ -327,7 +343,7 @@ json_t * UITheme::ToJson() const
|
||||||
{
|
{
|
||||||
// Create entries
|
// Create entries
|
||||||
json_t * jsonEntries = json_object();
|
json_t * jsonEntries = json_object();
|
||||||
for (const UIThemeEntry & entry : Entries)
|
for (const UIThemeWindowEntry & entry : Entries)
|
||||||
{
|
{
|
||||||
const WindowThemeDesc * wtDesc = GetWindowThemeDescriptor(entry.WindowClass);
|
const WindowThemeDesc * wtDesc = GetWindowThemeDescriptor(entry.WindowClass);
|
||||||
json_object_set_new(jsonEntries, wtDesc->WindowClassSZ, entry.ToJson());
|
json_object_set_new(jsonEntries, wtDesc->WindowClassSZ, entry.ToJson());
|
||||||
|
@ -407,7 +423,7 @@ UITheme * UITheme::FromJson(const json_t * json)
|
||||||
const WindowThemeDesc * wtDesc = GetWindowThemeDescriptor(jkey);
|
const WindowThemeDesc * wtDesc = GetWindowThemeDescriptor(jkey);
|
||||||
if (wtDesc == nullptr) continue;
|
if (wtDesc == nullptr) continue;
|
||||||
|
|
||||||
UIThemeEntry entry = UIThemeEntry::FromJson(wtDesc, jvalue);
|
UIThemeWindowEntry entry = UIThemeWindowEntry::FromJson(wtDesc, jvalue);
|
||||||
result->SetEntry(&entry);
|
result->SetEntry(&entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,19 +454,82 @@ UITheme * UITheme::FromFile(const utf8 * path)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
UITheme UITheme::CreatePredefined(const utf8 * name, const UIThemeEntry * entries, uint8 flags)
|
UITheme UITheme::CreatePredefined(const utf8 * name, const UIThemeWindowEntry * entries, uint8 flags)
|
||||||
{
|
{
|
||||||
auto theme = UITheme(name);
|
auto theme = UITheme(name);
|
||||||
theme.Flags = flags | UITHEME_FLAG_PREDEFINED;
|
theme.Flags = flags | UITHEME_FLAG_PREDEFINED;
|
||||||
|
|
||||||
size_t numEntries = 0;
|
size_t numEntries = 0;
|
||||||
for (const UIThemeEntry * entry = entries; entry->WindowClass != 255; entry++)
|
for (const UIThemeWindowEntry * entry = entries; entry->WindowClass != 255; entry++)
|
||||||
{
|
{
|
||||||
numEntries++;
|
numEntries++;
|
||||||
}
|
}
|
||||||
|
|
||||||
theme.Entries = List<UIThemeEntry>(entries, numEntries);
|
theme.Entries = List<UIThemeWindowEntry>(entries, numEntries);
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
namespace ThemeManager
|
||||||
|
{
|
||||||
|
const utf8 * CurrentThemePath;
|
||||||
|
UITheme * CurrentTheme;
|
||||||
|
|
||||||
|
struct AvailableTheme
|
||||||
|
{
|
||||||
|
utf8 Path[MAX_PATH];
|
||||||
|
utf8 Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
void GetAvailableThemes(List<AvailableTheme> * outThemes)
|
||||||
|
{
|
||||||
|
utf8 themesPattern[MAX_PATH];
|
||||||
|
platform_get_user_directory(themesPattern, "themes");
|
||||||
|
Path::Append(themesPattern, sizeof(themesPattern), "*.json");
|
||||||
|
|
||||||
|
utf8 path[MAX_PATH];
|
||||||
|
int handle = platform_enumerate_files_begin(themesPattern);
|
||||||
|
while (platform_enumerate_directories_next(handle, path))
|
||||||
|
{
|
||||||
|
AvailableTheme theme;
|
||||||
|
String::Set(theme.Path, sizeof(theme.Path), path);
|
||||||
|
Path::GetFileNameWithoutExtension(theme.Path, sizeof(theme.Path), path);
|
||||||
|
outThemes->Add(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
void colour_scheme_update(rct_window * window)
|
||||||
|
{
|
||||||
|
colour_scheme_update_by_class(window, window->classification);
|
||||||
|
}
|
||||||
|
|
||||||
|
void colour_scheme_update_by_class(rct_window * window, rct_windowclass classification)
|
||||||
|
{
|
||||||
|
const WindowTheme * windowTheme;
|
||||||
|
const UIThemeWindowEntry * entry = ThemeManager::CurrentTheme->GetEntry(classification);
|
||||||
|
if (entry != nullptr)
|
||||||
|
{
|
||||||
|
windowTheme = &entry->Theme;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const WindowThemeDesc * desc = GetWindowThemeDescriptor(classification);
|
||||||
|
windowTheme = &desc->DefaultTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool transparent = false;
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
window->colours[i] = windowTheme->Colours[i];
|
||||||
|
if (windowTheme->Colours[i] & COLOUR_FLAG_TRANSLUCENT) {
|
||||||
|
transparent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue