mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-24 00:03:11 +01:00
get game working with new theme manager
Theme editor currently unavailable.
This commit is contained in:
391
src/config.c
391
src/config.c
@@ -299,7 +299,6 @@ sound_configuration gConfigSound;
|
||||
twitch_configuration gConfigTwitch;
|
||||
network_configuration gConfigNetwork;
|
||||
notification_configuration gConfigNotifications;
|
||||
themes_configuration gConfigThemes;
|
||||
title_sequences_configuration gConfigTitleSequences;
|
||||
|
||||
static bool config_open(const utf8string path);
|
||||
@@ -1044,396 +1043,6 @@ bool config_shortcut_keys_save()
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#pragma region Themes
|
||||
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
const_utf8string property_name;
|
||||
uint8 type;
|
||||
value_union default_value;
|
||||
config_enum_definition *enum_definitions;
|
||||
} theme_property_definition;
|
||||
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
const_utf8string section_name;
|
||||
theme_property_definition *property_definitions;
|
||||
int property_definitions_count;
|
||||
} theme_section_definition;
|
||||
|
||||
|
||||
theme_property_definition _themeWindowDefinitions[] = {
|
||||
{ offsetof(theme_window, colours[0]), "colour_0", CONFIG_VALUE_TYPE_UINT8, 0, NULL },
|
||||
{ offsetof(theme_window, colours[1]), "colour_1", CONFIG_VALUE_TYPE_UINT8, 0, NULL },
|
||||
{ offsetof(theme_window, colours[2]), "colour_2", CONFIG_VALUE_TYPE_UINT8, 0, NULL },
|
||||
{ offsetof(theme_window, colours[3]), "colour_3", CONFIG_VALUE_TYPE_UINT8, 0, NULL },
|
||||
{ offsetof(theme_window, colours[4]), "colour_4", CONFIG_VALUE_TYPE_UINT8, 0, NULL },
|
||||
{ offsetof(theme_window, colours[5]), "colour_5", CONFIG_VALUE_TYPE_UINT8, 0, NULL },
|
||||
};
|
||||
|
||||
theme_property_definition _themeFeaturesDefinitions[] = {
|
||||
{ offsetof(theme_features, rct1_ride_lights), "rct1_ride_lights", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL },
|
||||
{ offsetof(theme_features, rct1_park_lights), "rct1_park_lights", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL },
|
||||
{ offsetof(theme_features, rct1_scenario_font), "rct1_scenario_font", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL },
|
||||
};
|
||||
|
||||
|
||||
theme_section_definition _themeSectionDefinitions[] = {
|
||||
// Special definition for theme windows
|
||||
{ 0, "", _themeWindowDefinitions, countof(_themeWindowDefinitions) },
|
||||
{ offsetof(theme_preset, features), "features", _themeFeaturesDefinitions, countof(_themeFeaturesDefinitions) },
|
||||
};
|
||||
|
||||
static bool themes_open(const_utf8string path);
|
||||
static bool themes_save(const_utf8string path, int preset);
|
||||
static void themes_read_properties(theme_preset *theme, theme_section_definition **currentSection, utf8string line);
|
||||
static void themes_set_property(theme_preset *theme, const theme_section_definition *section, const theme_property_definition *property, utf8string value, int valueSize);
|
||||
static theme_section_definition* themes_get_section_def(utf8string name, int size);
|
||||
static theme_property_definition *themes_get_property_def(theme_section_definition *section, utf8string name, int size);
|
||||
|
||||
void themes_set_default()
|
||||
{
|
||||
utf8 path[MAX_PATH];
|
||||
|
||||
platform_get_user_directory(path, "themes");
|
||||
platform_ensure_directory_exists(path);
|
||||
|
||||
gConfigThemes.num_presets = 2;
|
||||
gConfigThemes.presets = malloc(sizeof(theme_preset) * gConfigThemes.num_presets);
|
||||
|
||||
// Set RCT2 theme
|
||||
safe_strcpy(gConfigThemes.presets[0].name, language_get_string(2741), THEME_PRESET_NAME_SIZE);
|
||||
gConfigThemes.presets[0].windows = malloc(sizeof(theme_window) * gNumThemeWindows);
|
||||
|
||||
// Define the defaults for RCT2 here
|
||||
gConfigThemes.presets[0].features.rct1_ride_lights = false;
|
||||
gConfigThemes.presets[0].features.rct1_park_lights = false;
|
||||
gConfigThemes.presets[0].features.rct1_scenario_font = false;
|
||||
|
||||
|
||||
for (int i = 0; i < (int)gNumThemeWindows; i++) {
|
||||
gConfigThemes.presets[0].windows[i] = gThemeWindowDefinitions[i].window;
|
||||
}
|
||||
|
||||
// Set RCT1 theme
|
||||
safe_strcpy(gConfigThemes.presets[1].name, language_get_string(2740), THEME_PRESET_NAME_SIZE);
|
||||
gConfigThemes.presets[1].windows = malloc(sizeof(theme_window) * gNumThemeWindows);
|
||||
|
||||
// Define the defaults for RCT1 here
|
||||
gConfigThemes.presets[1].features.rct1_ride_lights = true;
|
||||
gConfigThemes.presets[1].features.rct1_park_lights = true;
|
||||
gConfigThemes.presets[1].features.rct1_scenario_font = true;
|
||||
|
||||
|
||||
for (int i = 0; i < (int)gNumThemeWindows; i++) {
|
||||
uint8 changed_colour = 0xFF;
|
||||
for (int k = 0; gThemeWindowsRCT1[k].classification != 0xFF; k++) {
|
||||
if (gThemeWindowsRCT1[k].classification == gThemeWindowDefinitions[i].classification) {
|
||||
changed_colour = (uint8)k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gConfigThemes.presets[1].windows[i] = (changed_colour != 0xFF ? gThemeWindowsRCT1[changed_colour].window : gThemeWindowDefinitions[i].window);
|
||||
}
|
||||
}
|
||||
|
||||
void themes_load_presets()
|
||||
{
|
||||
utf8 path[MAX_PATH];
|
||||
file_info file;
|
||||
int fileEnumHandle, i;
|
||||
|
||||
platform_get_user_directory(path, "themes");
|
||||
strcat(path, "*.ini");
|
||||
fileEnumHandle = platform_enumerate_files_begin(path);
|
||||
while (platform_enumerate_files_next(fileEnumHandle, &file)) {
|
||||
platform_get_user_directory(path, "themes");
|
||||
strcat(path, file.path);
|
||||
themes_open(path);
|
||||
}
|
||||
platform_enumerate_files_end(fileEnumHandle);
|
||||
|
||||
if (strcmp(gConfigInterface.current_theme_preset, "*RCT2") == 0) {
|
||||
theme_change_preset(0);
|
||||
}
|
||||
else if (strcmp(gConfigInterface.current_theme_preset, "*RCT1") == 0) {
|
||||
theme_change_preset(1);
|
||||
}
|
||||
else {
|
||||
for (i = 2; i < gConfigThemes.num_presets; i++) {
|
||||
if (strcmp(gConfigInterface.current_theme_preset, gConfigThemes.presets[i].name) == 0) {
|
||||
theme_change_preset(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == gConfigThemes.num_presets) {
|
||||
theme_change_preset(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool themes_save_preset(int preset)
|
||||
{
|
||||
utf8 path[MAX_PATH];
|
||||
|
||||
platform_get_user_directory(path, "themes");
|
||||
strcat(path, gConfigThemes.presets[preset].name);
|
||||
strcat(path, ".ini");
|
||||
if (themes_save(path, preset)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool themes_open(const_utf8string path)
|
||||
{
|
||||
SDL_RWops *file;
|
||||
utf8string lineBuffer;
|
||||
size_t lineBufferCapacity;
|
||||
size_t lineLength;
|
||||
int c, preset;
|
||||
theme_section_definition *currentSection;
|
||||
|
||||
file = SDL_RWFromFile(path, "rb");
|
||||
if (file == NULL)
|
||||
return false;
|
||||
|
||||
// Check if the colour scheme is already loaded
|
||||
// No nead to read the first two presets as they're hardcoded in
|
||||
for (preset = 2; preset < gConfigThemes.num_presets; preset++) {
|
||||
if (strcmp(path, gConfigThemes.presets[preset].name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Otherwise allocate one
|
||||
if (preset == gConfigThemes.num_presets) {
|
||||
gConfigThemes.num_presets++;
|
||||
gConfigThemes.presets = realloc(gConfigThemes.presets, sizeof(theme_preset) * gConfigThemes.num_presets);
|
||||
safe_strcpy(gConfigThemes.presets[preset].name, path_get_filename(path), THEME_PRESET_NAME_SIZE);
|
||||
path_remove_extension(gConfigThemes.presets[preset].name);
|
||||
gConfigThemes.presets[preset].windows = malloc(sizeof(theme_window) * gNumThemeWindows);
|
||||
gConfigThemes.presets[preset].features.rct1_ride_lights = false;
|
||||
gConfigThemes.presets[preset].features.rct1_park_lights = false;
|
||||
gConfigThemes.presets[preset].features.rct1_scenario_font = false;
|
||||
for (int i = 0; i < (int)gNumThemeWindows; i++) {
|
||||
gConfigThemes.presets[preset].windows[i] = gThemeWindowDefinitions[i].window;
|
||||
}
|
||||
}
|
||||
|
||||
currentSection = NULL;
|
||||
lineBufferCapacity = 64;
|
||||
lineBuffer = malloc(lineBufferCapacity);
|
||||
lineLength = 0;
|
||||
|
||||
// Skim UTF-8 byte order mark
|
||||
SDL_RWread(file, lineBuffer, 3, 1);
|
||||
if (!(lineBuffer[0] == (utf8)0xEF && lineBuffer[1] == (utf8)0xBB && lineBuffer[2] == (utf8)0xBF))
|
||||
SDL_RWseek(file, 0, SEEK_SET);
|
||||
|
||||
while ((c = rwopsreadc(file)) != EOF) {
|
||||
if (c == '\n' || c == '\r') {
|
||||
lineBuffer[lineLength++] = 0;
|
||||
themes_read_properties(&gConfigThemes.presets[preset], ¤tSection, (utf8string)lineBuffer);
|
||||
lineLength = 0;
|
||||
}
|
||||
else {
|
||||
lineBuffer[lineLength++] = c;
|
||||
}
|
||||
|
||||
if (lineLength >= lineBufferCapacity) {
|
||||
lineBufferCapacity *= 2;
|
||||
lineBuffer = realloc(lineBuffer, lineBufferCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
if (lineLength > 0) {
|
||||
lineBuffer[lineLength++] = 0;
|
||||
themes_read_properties(&gConfigThemes.presets[preset], ¤tSection, lineBuffer);
|
||||
}
|
||||
|
||||
free(lineBuffer);
|
||||
SDL_RWclose(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool themes_save(const_utf8string path, int preset)
|
||||
{
|
||||
SDL_RWops *file;
|
||||
int i, j;
|
||||
value_union *value;
|
||||
|
||||
file = SDL_RWFromFile(path, "wb");
|
||||
if (file == NULL) {
|
||||
log_error("Unable to write to theme file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the window definition, we'll do that after
|
||||
for (i = 1; i < countof(_themeSectionDefinitions); i++) {
|
||||
theme_section_definition *section = &_themeSectionDefinitions[i];
|
||||
|
||||
rwopswritec(file, '[');
|
||||
rwopswritestr(file, section->section_name);
|
||||
rwopswritec(file, ']');
|
||||
rwopswritenewline(file);
|
||||
|
||||
for (j = 0; j < section->property_definitions_count; j++) {
|
||||
theme_property_definition *property = §ion->property_definitions[j];
|
||||
|
||||
rwopswritestr(file, property->property_name);
|
||||
rwopswritestr(file, " = ");
|
||||
|
||||
value = (value_union*)((size_t)&gConfigThemes.presets[preset] + (size_t)section->offset + (size_t)property->offset);
|
||||
|
||||
if (property->enum_definitions != NULL)
|
||||
config_write_enum(file, property->type, value, property->enum_definitions);
|
||||
else
|
||||
config_save_property_value(file, property->type, value);
|
||||
rwopswritenewline(file);
|
||||
}
|
||||
rwopswritenewline(file);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)gNumThemeWindows; i++) {
|
||||
theme_section_definition *section = &_themeSectionDefinitions[0];
|
||||
|
||||
rwopswritec(file, '[');
|
||||
rwopswritestr(file, gThemeWindowDefinitions[i].section_name);
|
||||
rwopswritec(file, ']');
|
||||
rwopswritenewline(file);
|
||||
|
||||
for (j = 0; j < section->property_definitions_count; j++) {
|
||||
theme_property_definition *property = §ion->property_definitions[j];
|
||||
|
||||
rwopswritestr(file, property->property_name);
|
||||
rwopswritestr(file, " = ");
|
||||
|
||||
value = (value_union*)((size_t)gConfigThemes.presets[preset].windows + (size_t)(sizeof(theme_window) * i) + (size_t)property->offset);
|
||||
|
||||
if (property->enum_definitions != NULL)
|
||||
config_write_enum(file, property->type, value, property->enum_definitions);
|
||||
else
|
||||
config_save_property_value(file, property->type, value);
|
||||
rwopswritenewline(file);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_RWclose(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void themes_read_properties(theme_preset *theme, theme_section_definition **currentSection, utf8string line)
|
||||
{
|
||||
utf8 *ch = (utf8*)line;
|
||||
utf8_skip_whitespace(&ch);
|
||||
|
||||
if (*ch == '[') {
|
||||
const utf8 *sectionName;
|
||||
int sectionNameSize;
|
||||
if (config_get_section(ch, §ionName, §ionNameSize))
|
||||
*currentSection = themes_get_section_def((utf8string)sectionName, sectionNameSize);
|
||||
} else {
|
||||
if (*currentSection != NULL) {
|
||||
utf8 *propertyName, *value;
|
||||
int propertyNameSize, valueSize;
|
||||
if (config_get_property_name_value(ch, &propertyName, &propertyNameSize, &value, &valueSize)) {
|
||||
theme_property_definition *property;
|
||||
property = themes_get_property_def(*currentSection, propertyName, propertyNameSize);
|
||||
if (property != NULL)
|
||||
themes_set_property(theme, *currentSection, property, value, valueSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void themes_set_property(theme_preset *theme, const theme_section_definition *section, const theme_property_definition *property, utf8string value, int valueSize)
|
||||
{
|
||||
value_union *destValue = (value_union*)((size_t)theme + (size_t)section->offset + (size_t)property->offset);
|
||||
|
||||
// Get getting the address from the windows pointer instead
|
||||
if (section == &_themeSectionDefinitions[0])
|
||||
destValue = (value_union*)((size_t)theme->windows + (size_t)section->offset + (size_t)property->offset);
|
||||
|
||||
if (property->enum_definitions != NULL)
|
||||
if (config_read_enum(destValue, _configValueTypeSize[property->type], value, valueSize, property->enum_definitions))
|
||||
return;
|
||||
|
||||
switch (property->type) {
|
||||
case CONFIG_VALUE_TYPE_BOOLEAN:
|
||||
if (_strnicmp(value, "false", valueSize) == 0) destValue->value_boolean = false;
|
||||
else if (_strnicmp(value, "true", valueSize) == 0) destValue->value_boolean = true;
|
||||
else destValue->value_boolean = strtol(value, NULL, 0) != 0;
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_UINT8:
|
||||
destValue->value_uint8 = (uint8)strtol(value, NULL, 0);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_UINT16:
|
||||
destValue->value_uint16 = (uint16)strtol(value, NULL, 0);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_UINT32:
|
||||
destValue->value_uint32 = (uint32)strtol(value, NULL, 0);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_SINT8:
|
||||
destValue->value_sint8 = (sint8)strtol(value, NULL, 0);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_SINT16:
|
||||
destValue->value_sint16 = (sint16)strtol(value, NULL, 0);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_SINT32:
|
||||
destValue->value_sint32 = (sint32)strtol(value, NULL, 0);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_FLOAT:
|
||||
destValue->value_float = strtof(value, NULL);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_DOUBLE:
|
||||
destValue->value_double = strtod(value, NULL);
|
||||
break;
|
||||
case CONFIG_VALUE_TYPE_STRING:
|
||||
SafeFree(destValue->value_string);
|
||||
destValue->value_string = malloc(valueSize + 1);
|
||||
memcpy(destValue->value_string, value, valueSize);
|
||||
destValue->value_string[valueSize] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
static theme_section_definition* themes_get_section_def(utf8string name, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Skip the special definition
|
||||
for (i = 1; i < countof(_themeSectionDefinitions); i++) {
|
||||
const_utf8string sectionName = _themeSectionDefinitions[i].section_name;
|
||||
if (sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0)
|
||||
return &_themeSectionDefinitions[i];
|
||||
}
|
||||
// Check for window definitions
|
||||
for (i = 0; i < (int)gNumThemeWindows; i++) {
|
||||
const_utf8string sectionName = gThemeWindowDefinitions[i].section_name;
|
||||
if (sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0) {
|
||||
_themeSectionDefinitions[0].offset = (size_t)(sizeof(theme_window) * i);
|
||||
return &_themeSectionDefinitions[0];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static theme_property_definition *themes_get_property_def(theme_section_definition *section, utf8string name, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < section->property_definitions_count; i++) {
|
||||
const_utf8string propertyName = section->property_definitions[i].property_name;
|
||||
if (propertyName[size] == 0 && _strnicmp(propertyName, name, size) == 0)
|
||||
return §ion->property_definitions[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Title Sequences
|
||||
|
||||
static void title_sequence_open(const char *path, const char *customName);
|
||||
|
||||
Reference in New Issue
Block a user