Refactor Theme to use new JSON library

This commit is contained in:
Simon Jarrett 2020-08-12 23:27:02 +01:00
parent 12dfa74eef
commit 57a57b0c02
1 changed files with 69 additions and 64 deletions

View File

@ -14,7 +14,6 @@
#include "Window.h" #include "Window.h"
#include <algorithm> #include <algorithm>
#include <jansson.h>
#include <memory> #include <memory>
#include <openrct2/Context.h> #include <openrct2/Context.h>
#include <openrct2/PlatformEnvironment.h> #include <openrct2/PlatformEnvironment.h>
@ -53,8 +52,11 @@ struct UIThemeWindowEntry
rct_windowclass WindowClass; rct_windowclass WindowClass;
WindowTheme Theme; WindowTheme Theme;
json_t* ToJson() const; json_t ToJson() const;
static UIThemeWindowEntry FromJson(const WindowThemeDesc* wtDesc, const json_t* json); /**
* @note json is deliberately left non-const: json_t behaviour changes when const
*/
static UIThemeWindowEntry FromJson(const WindowThemeDesc* wtDesc, json_t& json);
}; };
/** /**
@ -76,10 +78,13 @@ public:
void SetEntry(const UIThemeWindowEntry* entry); void SetEntry(const UIThemeWindowEntry* entry);
void RemoveEntry(rct_windowclass windowClass); void RemoveEntry(rct_windowclass windowClass);
json_t* ToJson() const; json_t ToJson() const;
bool WriteToFile(const std::string& path) const; bool WriteToFile(const std::string& path) const;
static UITheme* FromJson(const json_t* json); /**
* @note json is deliberately left non-const: json_t behaviour changes when const
*/
static UITheme* FromJson(json_t& json);
static UITheme* FromFile(const std::string& path); static UITheme* FromFile(const std::string& path);
static UITheme CreatePredefined(const std::string& name, const UIThemeWindowEntry* entries, uint8_t flags); static UITheme CreatePredefined(const std::string& name, const UIThemeWindowEntry* entries, uint8_t flags);
}; };
@ -266,7 +271,7 @@ static void ThrowThemeLoadException()
#pragma region UIThemeEntry #pragma region UIThemeEntry
json_t* UIThemeWindowEntry::ToJson() const json_t UIThemeWindowEntry::ToJson() const
{ {
const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(WindowClass); const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(WindowClass);
if (wtDesc == nullptr) if (wtDesc == nullptr)
@ -274,37 +279,41 @@ json_t* UIThemeWindowEntry::ToJson() const
return nullptr; return nullptr;
} }
json_t* jsonColours = json_array(); json_t jsonColours = json_t::array();
for (uint8_t i = 0; i < wtDesc->NumColours; i++) for (uint8_t i = 0; i < wtDesc->NumColours; i++)
{ {
colour_t colour = Theme.Colours[i]; colour_t colour = Theme.Colours[i];
json_array_append_new(jsonColours, json_integer(colour)); jsonColours.push_back(colour);
} }
json_t* jsonEntry = json_object(); json_t jsonEntry = {
json_object_set_new(jsonEntry, "colours", jsonColours); { "colours", jsonColours },
};
return jsonEntry; return jsonEntry;
} }
UIThemeWindowEntry UIThemeWindowEntry::FromJson(const WindowThemeDesc* wtDesc, const json_t* json) UIThemeWindowEntry UIThemeWindowEntry::FromJson(const WindowThemeDesc* wtDesc, json_t& jsonData)
{ {
json_t* jsonColours = json_object_get(json, "colours"); Guard::Assert(jsonData.is_object(), "UIThemeWindowEntry::FromJson expects parameter jsonData to be object");
if (jsonColours == nullptr)
auto jsonColours = Json::AsArray(jsonData["colours"]);
if (jsonColours.empty())
{ {
ThrowThemeLoadException(); ThrowThemeLoadException();
} }
uint8_t numColours = static_cast<uint8_t>(json_array_size(jsonColours));
numColours = std::min(numColours, wtDesc->NumColours);
UIThemeWindowEntry result{}; UIThemeWindowEntry result{};
result.WindowClass = wtDesc->WindowClass; result.WindowClass = wtDesc->WindowClass;
result.Theme = wtDesc->DefaultTheme; result.Theme = wtDesc->DefaultTheme;
for (uint8_t i = 0; i < numColours; i++) // result.Theme.Colours only has 6 values
size_t colourCount = std::min(jsonColours.size(), static_cast<size_t>(wtDesc->NumColours));
for (size_t i = 0; i < colourCount; i++)
{ {
result.Theme.Colours[i] = static_cast<colour_t>(json_integer_value(json_array_get(jsonColours, i))); result.Theme.Colours[i] = Json::GetNumber<colour_t>(jsonColours[i]);
} }
return result; return result;
@ -355,10 +364,10 @@ void UITheme::RemoveEntry(rct_windowclass windowClass)
} }
} }
json_t* UITheme::ToJson() const json_t UITheme::ToJson() const
{ {
// Create entries // Create entries
json_t* jsonEntries = json_object(); json_t jsonEntries;
for (const UIThemeWindowEntry& entry : Entries) for (const UIThemeWindowEntry& entry : Entries)
{ {
const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(entry.WindowClass); const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(entry.WindowClass);
@ -366,30 +375,29 @@ json_t* UITheme::ToJson() const
{ {
return nullptr; return nullptr;
} }
json_object_set_new(jsonEntries, wtDesc->WindowClassSZ, entry.ToJson()); jsonEntries[wtDesc->WindowClassSZ] = entry.ToJson();
} }
// Create theme object // Create theme object
json_t* jsonTheme = json_object(); json_t jsonTheme = {
json_object_set_new(jsonTheme, "name", json_string(Name.c_str())); { "name", Name },
json_object_set_new(jsonTheme, "entries", jsonEntries); { "entries", jsonEntries },
{ "useLightsRide", (Flags & UITHEME_FLAG_USE_LIGHTS_RIDE) != 0 },
json_object_set_new(jsonTheme, "useLightsRide", json_boolean(Flags & UITHEME_FLAG_USE_LIGHTS_RIDE)); { "useLightsPark", (Flags & UITHEME_FLAG_USE_LIGHTS_PARK) != 0 },
json_object_set_new(jsonTheme, "useLightsPark", json_boolean(Flags & UITHEME_FLAG_USE_LIGHTS_PARK)); { "useAltScenarioSelectFont", (Flags & UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT) != 0 },
json_object_set_new( { "useFullBottomToolbar", (Flags & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR) != 0 },
jsonTheme, "useAltScenarioSelectFont", json_boolean(Flags & UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT)); };
json_object_set_new(jsonTheme, "useFullBottomToolbar", json_boolean(Flags & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR));
return jsonTheme; return jsonTheme;
} }
bool UITheme::WriteToFile(const std::string& path) const bool UITheme::WriteToFile(const std::string& path) const
{ {
json_t* jsonTheme = ToJson(); auto jsonTheme = ToJson();
bool result; bool result;
try try
{ {
Json::WriteToFile(path.c_str(), jsonTheme, JSON_INDENT(4) | JSON_PRESERVE_ORDER); Json::WriteToFile(path.c_str(), jsonTheme);
result = true; result = true;
} }
catch (const std::exception& ex) catch (const std::exception& ex)
@ -398,52 +406,51 @@ bool UITheme::WriteToFile(const std::string& path) const
result = false; result = false;
} }
json_decref(jsonTheme);
return result; return result;
} }
UITheme* UITheme::FromJson(const json_t* json) UITheme* UITheme::FromJson(json_t& jsonObj)
{ {
const char* themeName = json_string_value(json_object_get(json, "name")); Guard::Assert(jsonObj.is_object(), "UITheme::FromJson expects parameter jsonObj to be object");
if (themeName == nullptr)
const std::string themeName = Json::GetString(jsonObj["name"]);
if (themeName.empty())
{ {
ThrowThemeLoadException(); ThrowThemeLoadException();
} }
json_t* jsonEntries = json_object_get(json, "entries"); json_t jsonEntries = jsonObj["entries"];
UITheme* result = nullptr; UITheme* result = nullptr;
try try
{ {
result = new UITheme(themeName); result = new UITheme(themeName);
if (json_is_true(json_object_get(json, "useLightsRide"))) result->Flags = Json::GetFlags<uint8_t>(
{ jsonObj,
result->Flags |= UITHEME_FLAG_USE_LIGHTS_RIDE; {
} { "useLightsRide", UITHEME_FLAG_USE_LIGHTS_RIDE },
if (json_is_true(json_object_get(json, "useLightsPark"))) { "useLightsPark", UITHEME_FLAG_USE_LIGHTS_PARK },
{ { "useAltScenarioSelectFont", UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT },
result->Flags |= UITHEME_FLAG_USE_LIGHTS_PARK; { "useFullBottomToolbar", UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR },
} });
if (json_is_true(json_object_get(json, "useAltScenarioSelectFont")))
{
result->Flags |= UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT;
}
if (json_is_true(json_object_get(json, "useFullBottomToolbar")))
{
result->Flags |= UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR;
}
const char* jkey; if (jsonEntries.is_object())
json_t* jvalue;
json_object_foreach(jsonEntries, jkey, jvalue)
{ {
const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(jkey); for (auto& [jsonKey, jsonValue] : jsonEntries.items())
if (wtDesc == nullptr) {
continue; if (jsonValue.is_object())
{
const WindowThemeDesc* wtDesc = GetWindowThemeDescriptor(jsonKey.data());
if (wtDesc == nullptr)
{
continue;
}
UIThemeWindowEntry entry = UIThemeWindowEntry::FromJson(wtDesc, jvalue); UIThemeWindowEntry entry = UIThemeWindowEntry::FromJson(wtDesc, jsonValue);
result->SetEntry(&entry); result->SetEntry(&entry);
}
}
} }
return result; return result;
@ -457,8 +464,8 @@ UITheme* UITheme::FromJson(const json_t* json)
UITheme* UITheme::FromFile(const std::string& path) UITheme* UITheme::FromFile(const std::string& path)
{ {
json_t* json = nullptr;
UITheme* result = nullptr; UITheme* result = nullptr;
json_t json;
try try
{ {
json = Json::ReadFromFile(path.c_str()); json = Json::ReadFromFile(path.c_str());
@ -469,8 +476,6 @@ UITheme* UITheme::FromFile(const std::string& path)
log_error("Unable to read theme: %s", path.c_str()); log_error("Unable to read theme: %s", path.c_str());
result = nullptr; result = nullptr;
} }
json_decref(json);
return result; return result;
} }