From 91b3d697c506473deb47d70a31de5d5a7a063483 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 23 May 2021 10:47:12 +0200 Subject: [PATCH 01/14] Codechange: make SettingDesc an instance in the setting table to allow for sub classes --- src/settings.cpp | 92 ++++++++++++++++++++--------------- src/settings_internal.h | 7 +-- src/table/settings.h.preamble | 12 ++--- 3 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 15d90f312b..2c7d3aefe8 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -100,7 +100,7 @@ static bool IsSignedVarMemType(VarType vt); const SettingDesc *GetSettingDescription(uint index) { if (index >= _settings.size()) return nullptr; - return &_settings.begin()[index]; + return _settings.begin()[index].get(); } /** @@ -111,7 +111,7 @@ const SettingDesc *GetSettingDescription(uint index) static const SettingDesc *GetCompanySettingDescription(uint index) { if (index >= _company_settings.size()) return nullptr; - return &_company_settings.begin()[index]; + return _company_settings.begin()[index].get(); } /** @@ -563,11 +563,11 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co IniGroup *group_def = ini->GetGroup(grpname); for (auto &sd : settings_table) { - const SettingDesc *sdb = &sd; - const SaveLoad *sld = &sd.save; + const SettingDesc *sdb = sd.get(); + const SaveLoad *sld = &sd->save; if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; - if (sd.startup != only_startup) continue; + if (sd->startup != only_startup) continue; /* For settings.xx.yy load the settings from [xx] yy = ? */ std::string s{ sdb->name }; @@ -600,11 +600,11 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co case SDT_NUMX: case SDT_ONEOFMANY: case SDT_MANYOFMANY: - Write_ValidateSetting(ptr, &sd, (int32)(size_t)p); + Write_ValidateSetting(ptr, sd.get(), (int32)(size_t)p); break; case SDT_STDSTRING: - Write_ValidateStdString(ptr, &sd, (const char *)p); + Write_ValidateStdString(ptr, sd.get(), (const char *)p); break; case SDT_INTLIST: { @@ -615,8 +615,8 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co /* Use default */ LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); - } else if (sd.proc_cnvt != nullptr) { - sd.proc_cnvt((const char*)p); + } else if (sd->proc_cnvt != nullptr) { + sd->proc_cnvt((const char*)p); } break; } @@ -645,8 +645,8 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co void *ptr; for (auto &sd : settings_table) { - const SettingDesc *sdb = &sd; - const SaveLoad *sld = &sd.save; + const SettingDesc *sdb = sd.get(); + const SaveLoad *sld = &sd->save; /* If the setting is not saved to the configuration * file, just continue with the next setting */ @@ -1964,6 +1964,22 @@ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 return CommandCost(); } +/** + * Get the index of the given setting in the setting table. + * @param settings The settings to look through. + * @param setting The setting to look for. + * @return The index, or UINT32_MAX when it has not been found. + */ +static uint GetSettingIndex(const SettingTable &settings, const SettingDesc *setting) +{ + uint index = 0; + for (auto &sd : settings) { + if (sd.get() == setting) return index; + index++; + } + return UINT32_MAX; +} + /** * Get the index of the setting with this description. * @param sd the setting to get the index for. @@ -1972,7 +1988,7 @@ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 uint GetSettingIndex(const SettingDesc *sd) { assert(sd != nullptr && (sd->flags & SGF_PER_COMPANY) == 0); - return sd - _settings.begin(); + return GetSettingIndex(_settings, sd); } /** @@ -1983,7 +1999,7 @@ uint GetSettingIndex(const SettingDesc *sd) static uint GetCompanySettingIndex(const SettingDesc *sd) { assert(sd != nullptr && (sd->flags & SGF_PER_COMPANY) != 0); - return sd - _company_settings.begin(); + return GetSettingIndex(_company_settings, sd); } /** @@ -2048,8 +2064,8 @@ void SetDefaultCompanySettings(CompanyID cid) { Company *c = Company::Get(cid); for (auto &sd : _company_settings) { - void *var = GetVariableAddress(&c->settings, &sd.save); - Write_ValidateSetting(var, &sd, (int32)(size_t)sd.def); + void *var = GetVariableAddress(&c->settings, &sd->save); + Write_ValidateSetting(var, sd.get(), (int32)(size_t)sd->def); } } @@ -2060,10 +2076,10 @@ void SyncCompanySettings() { uint i = 0; for (auto &sd : _company_settings) { - const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd.save); - const void *new_var = GetVariableAddress(&_settings_client.company, &sd.save); - uint32 old_value = (uint32)ReadValue(old_var, sd.save.conv); - uint32 new_value = (uint32)ReadValue(new_var, sd.save.conv); + const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); + const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save); + uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv); + uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv); if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, nullptr, nullptr, _local_company); i++; } @@ -2113,25 +2129,25 @@ const SettingDesc *GetSettingFromName(const char *name) { /* First check all full names */ for (auto &sd : _settings) { - if (!SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to)) continue; - if (strcmp(sd.name, name) == 0) return &sd; + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + if (strcmp(sd->name, name) == 0) return sd.get(); } /* Then check the shortcut variant of the name. */ for (auto &sd : _settings) { - if (!SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to)) continue; - const char *short_name = strchr(sd.name, '.'); + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + const char *short_name = strchr(sd->name, '.'); if (short_name != nullptr) { short_name++; - if (strcmp(short_name, name) == 0) return &sd; + if (strcmp(short_name, name) == 0) return sd.get(); } } if (strncmp(name, "company.", 8) == 0) name += 8; /* And finally the company-based settings */ for (auto &sd : _company_settings) { - if (!SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to)) continue; - if (strcmp(sd.name, name) == 0) return &sd; + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + if (strcmp(sd->name, name) == 0) return sd.get(); } return nullptr; @@ -2221,19 +2237,19 @@ void IConsoleListSettings(const char *prefilter) IConsolePrintF(CC_WARNING, "All settings with their current value:"); for (auto &sd : _settings) { - if (!SlIsObjectCurrentlyValid(sd.save.version_from, sd.save.version_to)) continue; - if (prefilter != nullptr && strstr(sd.name, prefilter) == nullptr) continue; + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + if (prefilter != nullptr && strstr(sd->name, prefilter) == nullptr) continue; char value[80]; - const void *ptr = GetVariableAddress(&GetGameSettings(), &sd.save); + const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save); - if (sd.cmd == SDT_BOOLX) { + if (sd->cmd == SDT_BOOLX) { seprintf(value, lastof(value), (*(const bool *)ptr != 0) ? "on" : "off"); - } else if (sd.cmd == SDT_STDSTRING) { + } else if (sd->cmd == SDT_STDSTRING) { seprintf(value, lastof(value), "%s", reinterpret_cast(ptr)->c_str()); } else { - seprintf(value, lastof(value), sd.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd.save.conv)); + seprintf(value, lastof(value), sd->min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); } - IConsolePrintF(CC_DEFAULT, "%s = %s", sd.name, value); + IConsolePrintF(CC_DEFAULT, "%s = %s", sd->name, value); } IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value"); @@ -2248,11 +2264,11 @@ void IConsoleListSettings(const char *prefilter) static void LoadSettings(const SettingTable &settings, void *object) { for (auto &osd : settings) { - const SaveLoad *sld = &osd.save; + const SaveLoad *sld = &osd->save; void *ptr = GetVariableAddress(object, sld); if (!SlObjectMember(ptr, sld)) continue; - if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, &osd, ReadValue(ptr, sld->conv)); + if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, osd.get(), ReadValue(ptr, sld->conv)); } } @@ -2268,13 +2284,13 @@ static void SaveSettings(const SettingTable &settings, void *object) * SlCalcLength() because we have a different format. So do this manually */ size_t length = 0; for (auto &sd : settings) { - length += SlCalcObjMemberLength(object, &sd.save); + length += SlCalcObjMemberLength(object, &sd->save); } SlSetLength(length); for (auto &sd : settings) { - void *ptr = GetVariableAddress(object, &sd.save); - SlObjectMember(ptr, &sd.save); + void *ptr = GetVariableAddress(object, &sd->save); + SlObjectMember(ptr, &sd->save); } } diff --git a/src/settings_internal.h b/src/settings_internal.h index fca85de0c7..4aebe6b79c 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -82,7 +82,7 @@ typedef bool OnChange(int32 var); ///< callback prototype on data modi typedef size_t OnConvert(const char *value); ///< callback prototype for conversion error /** Properties of config file settings. */ -struct SettingDescBase { +struct SettingDesc { const char *name; ///< name of the setting. Used in configuration file and for console const void *def; ///< default value given when none is present SettingDescType cmd; ///< various flags for the variable @@ -98,16 +98,13 @@ struct SettingDescBase { OnConvert *proc_cnvt; ///< callback procedure when loading value mechanism fails SettingCategory cat; ///< assigned categories of the setting bool startup; ///< setting has to be loaded directly at startup? -}; - -struct SettingDesc : SettingDescBase { SaveLoad save; ///< Internal structure (going to savegame, parts to config) bool IsEditable(bool do_command = false) const; SettingType GetType() const; }; -typedef std::initializer_list SettingTable; +typedef std::initializer_list> SettingTable; const SettingDesc *GetSettingFromName(const char *name); bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame = false); diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index f9bb279020..dbd302a1c8 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -54,13 +54,13 @@ static size_t ConvertLandscape(const char *value); * on the appropriate macro. */ -#define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup)\ - {name, (const void*)(size_t)(def), cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup} +#define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup, saveload)\ + std::unique_ptr(new SettingDesc{name, (const void*)(size_t)(def), cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup, saveload}) /* Macros for various objects to go in the configuration file. * This section is for global variables */ #define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, nullptr, cat, startup), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to, extra)} + NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, nullptr, cat, startup, SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to, extra)) #define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) @@ -81,12 +81,12 @@ static size_t ConvertLandscape(const char *value); SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, from, to, cat, extra, startup) #define SDTG_NULL(length, from, to)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false}, SLEG_NULL(length, from, to)} + NSD_GENERAL("", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, SLEG_NULL(length, from, to)) /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ #define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat, extra, startup)\ - {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat, startup), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to, extra)} + NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat, startup, SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to, extra)) #define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) @@ -107,7 +107,7 @@ static size_t ConvertLandscape(const char *value); SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) #define SDT_NULL(length, from, to)\ - {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false}, SLE_CONDNULL(length, from, to)} + NSD_GENERAL("", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, SLE_CONDNULL(length, from, to)) #define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ From d8125fa46e090f25f3fffbc0202bb971b914a3b4 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 22 May 2021 19:00:43 +0200 Subject: [PATCH 02/14] Codechange: make sub classes of SettingDesc for the different types of settings --- src/settings_internal.h | 42 ++++++++++++++++++++++- src/table/currency_settings.ini | 2 +- src/table/gameopt_settings.ini | 19 ++++------- src/table/misc_settings.ini | 12 +++---- src/table/settings.h.preamble | 60 ++++++++++++++------------------- src/table/settings.ini | 6 ++-- 6 files changed, 84 insertions(+), 57 deletions(-) diff --git a/src/settings_internal.h b/src/settings_internal.h index 4aebe6b79c..1accc47ed8 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -16,7 +16,7 @@ * Convention/Type of settings. This is then further specified if necessary * with the SLE_ (SLE_VAR/SLE_FILE) enums in saveload.h * @see VarTypes - * @see SettingDescBase + * @see SettingDesc */ enum SettingDescType : byte { SDT_NUMX = 0, ///< any number-type @@ -25,6 +25,7 @@ enum SettingDescType : byte { SDT_MANYOFMANY = 3, ///< bitmasked number where MULTIPLE bits may be set SDT_INTLIST = 4, ///< list of integers separated by a comma ',' SDT_STDSTRING = 6, ///< \c std::string + SDT_NULL = 7, ///< an old setting that has been removed but could still be in savegames }; enum SettingGuiFlag : uint16 { @@ -83,6 +84,13 @@ typedef size_t OnConvert(const char *value); ///< callback prototype for convers /** Properties of config file settings. */ struct SettingDesc { + SettingDesc(SaveLoad save, const char *name, const void *def, SettingDescType cmd, SettingGuiFlag flags, + int32 min, uint32 max, int32 interval, const char *many, StringID str, StringID str_help, + StringID str_val, OnChange *proc, OnConvert *proc_cnvt, SettingCategory cat, bool startup) : + name(name), def(def), cmd(cmd), flags(flags), min(min), max(max), interval(interval), many(many), str(str), + str_help(str_help), str_val(str_val), proc(proc), proc_cnvt(proc_cnvt), cat(cat), startup(startup), save(save) {} + virtual ~SettingDesc() {} + const char *name; ///< name of the setting. Used in configuration file and for console const void *def; ///< default value given when none is present SettingDescType cmd; ///< various flags for the variable @@ -104,6 +112,38 @@ struct SettingDesc { SettingType GetType() const; }; +/** Integer type, including boolean, settings. Only these are shown in the settings UI. */ +struct IntSettingDesc : SettingDesc { + IntSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, int32 def, + int32 min, uint32 max, int32 interval, StringID str, StringID str_help, StringID str_val, + SettingCategory cat, OnChange *proc, const char *many = nullptr, OnConvert *many_cnvt = nullptr) : + SettingDesc(save, name, (void*)(size_t)def, cmd, flags, min, max, interval, many, str, str_help, str_val, + proc, many_cnvt, cat, startup) {} + virtual ~IntSettingDesc() {} +}; + +/** String settings. */ +struct StringSettingDesc : SettingDesc { + StringSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def, + uint32 max_length, OnChange proc) : + SettingDesc(save, name, def, cmd, flags, 0, max_length, 0, nullptr, 0, 0, 0, proc, nullptr, SC_NONE, startup) {} + virtual ~StringSettingDesc() {} +}; + +/** List/array settings. */ +struct ListSettingDesc : SettingDesc { + ListSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def) : + SettingDesc(save, name, def, cmd, flags, 0, 0, 0, nullptr, 0, 0, 0, proc, nullptr, SC_NONE, startup) {} + virtual ~ListSettingDesc() {} +}; + +/** Placeholder for settings that have been removed, but might still linger in the savegame. */ +struct NullSettingDesc : SettingDesc { + NullSettingDesc(SaveLoad save) : + SettingDesc(save, "", nullptr, SDT_NULL, SGF_NONE, 0, 0, 0, nullptr, 0, 0, 0, nullptr, nullptr, SC_NONE, false) {} + virtual ~NullSettingDesc() {} +}; + typedef std::initializer_list> SettingTable; const SettingDesc *GetSettingFromName(const char *name); diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini index 613f9bfa55..76eecc1043 100644 --- a/src/table/currency_settings.ini +++ b/src/table/currency_settings.ini @@ -10,7 +10,7 @@ static const SettingTable _currency_settings{ }; [templates] SDT_VAR = SDT_VAR ($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDT_SSTR = SDT_SSTR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDT_SSTR = SDT_SSTR($base, $var, $type, $flags, $guiflags, $def, $proc, $from, $to, $cat, $extra, $startup), [validation] SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size"); diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index 39caa45c95..1e60770f21 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -36,9 +36,9 @@ static const SettingTable _gameopt_settings{ [post-amble] }; [templates] -SDTG_GENERAL = SDTG_GENERAL($name, $sdt_cmd, $sle_cmd, $type, $flags, $guiflags, $var, $length, $def, $min, $max, $interval, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDT_NULL = SDT_NULL($length, $from, $to), +SDTG_LIST = SDTG_LIST($name, $type, $flags, $guiflags, $var, $def, $length, $from, $to, $cat, $extra, $startup), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDT_NULL = SDT_NULL( $length, $from, $to), SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat, $extra, $startup), @@ -68,7 +68,7 @@ startup = false -[SDTG_GENERAL] +[SDTG_LIST] name = ""diff_custom"" sdt_cmd = SDT_INTLIST sle_cmd = SL_ARR @@ -76,13 +76,10 @@ type = SLE_FILE_I16 | SLE_VAR_U16 flags = SLF_NOT_IN_CONFIG var = _old_diff_custom length = 17 -def = 0 -min = 0 -max = 0 -full = nullptr +def = nullptr to = SLV_4 -[SDTG_GENERAL] +[SDTG_LIST] name = ""diff_custom"" sdt_cmd = SDT_INTLIST sle_cmd = SL_ARR @@ -90,9 +87,7 @@ type = SLE_UINT16 flags = SLF_NOT_IN_CONFIG var = _old_diff_custom length = 18 -def = 0 -min = 0 -max = 0 +def = nullptr full = nullptr from = SLV_4 diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 4e1c3482ec..a3efbc65e8 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -20,12 +20,12 @@ static const SettingTable _misc_settings{ [post-amble] }; [templates] -SDTG_LIST = SDTG_LIST($name, $type, $length, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTG_SSTR = SDTG_SSTR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDTG_LIST = SDTG_LIST($name, $type, $flags, $guiflags, $var, $def, $length, $from, $to, $cat, $extra, $startup), +SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDTG_SSTR = SDTG_SSTR($name, $type, $flags, $guiflags, $var, $def, 0, $proc, $from, $to, $cat, $extra, $startup), +SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), [validation] SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size"); diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index dbd302a1c8..6b4dc5e39f 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -54,74 +54,66 @@ static size_t ConvertLandscape(const char *value); * on the appropriate macro. */ -#define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup, saveload)\ - std::unique_ptr(new SettingDesc{name, (const void*)(size_t)(def), cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat, startup, saveload}) +#define NSD(type, ...) std::unique_ptr(new type##SettingDesc(__VA_ARGS__)) /* Macros for various objects to go in the configuration file. * This section is for global variables */ -#define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, nullptr, cat, startup, SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to, extra)) - #define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) + NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_NUMX, startup, def, min, max, interval, str, strhelp, strval, cat, proc) #define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) + NSD(Int, SLEG_GENERAL(SL_VAR, var, SLE_BOOL | flags, 1, from, to, extra), name, guiflags, SDT_BOOLX, startup, def, 0, 1, 0, str, strhelp, strval, cat, proc) -#define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) +#define SDTG_LIST(name, type, flags, guiflags, var, def, length, from, to, cat, extra, startup)\ + NSD(List, SLEG_GENERAL(SL_ARR, var, type | flags, length, from, to, extra), name, guiflags, SDT_INTLIST, startup, def) -#define SDTG_SSTR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(name, SDT_STDSTRING, SL_STDSTR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) +#define SDTG_SSTR(name, type, flags, guiflags, var, def, max_length, proc, from, to, cat, extra, startup)\ + NSD(String, SLEG_GENERAL(SL_STDSTR, var, type | flags, sizeof(var), from, to, extra), name, guiflags, SDT_STDSTRING, startup, def, max_length, proc) #define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat, extra, startup) + NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_ONEOFMANY, startup, def, 0, max, 0, str, strhelp, strval, cat, proc, full) #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, from, to, cat, extra, startup) + NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_MANYOFMANY, startup, def, 0, 0, 0, str, strhelp, strval, cat, proc, full) #define SDTG_NULL(length, from, to)\ - NSD_GENERAL("", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, SLEG_NULL(length, from, to)) + NSD(Null, SLEG_NULL(length, from, to)) /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ -#define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat, extra, startup)\ - NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat, startup, SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to, extra)) - #define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) + NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_NUMX, startup, def, min, max, interval, str, strhelp, strval, cat, proc) #define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) + NSD(Int, SLE_GENERAL(SL_VAR, base, var, SLE_BOOL | flags, 1, from, to, extra), #var, guiflags, SDT_BOOLX, startup, def, 0, 1, 0, str, strhelp, strval, cat, proc) -#define SDT_LIST(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) +#define SDT_LIST(base, var, type, flags, guiflags, def, from, to, cat, extra, startup)\ + NSD(List, SLE_GENERAL(SL_ARR, base, var, type | flags, lengthof(((base*)8)->var), from, to, extra), #var, guiflags, SDT_INTLIST, startup, def) -#define SDT_SSTR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDT_GENERAL(#var, SDT_STDSTRING, SL_STDSTR, type, flags, guiflags, base, var, sizeof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) +#define SDT_SSTR(base, var, type, flags, guiflags, def, proc, from, to, cat, extra, startup)\ + NSD(String, SLE_GENERAL(SL_STDSTR, base, var, type | flags, sizeof(((base*)8)->var), from, to, extra), #var, guiflags, SDT_STDSTRING, startup, def, 0, proc) #define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat, extra, startup)\ - SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat, extra, startup) + NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_ONEOFMANY, startup, def, 0, max, 0, str, strhelp, strval, cat, proc, full, load) #define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat, extra, startup)\ - SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) + NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_MANYOFMANY, startup, def, 0, 0, 0, str, strhelp, strval, cat, proc, full, nullptr) #define SDT_NULL(length, from, to)\ - NSD_GENERAL("", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE, false, SLE_CONDNULL(length, from, to)) + NSD(Null, SLE_CONDNULL(length, from, to)) #define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) + SDTG_VAR(#var, type, flags, guiflags, _settings_client.var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup) #define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) + SDTG_BOOL(#var, flags, guiflags, _settings_client.var, def, str, strhelp, strval, proc, from, to, cat, extra, startup) -#define SDTC_LIST(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) +#define SDTC_LIST(var, type, flags, guiflags, def, from, to, cat, extra, startup)\ + SDTG_LIST(#var, type, flags, guiflags, _settings_client.var, def, lengthof(_settings_client.var), from, to, cat, extra, startup) -#define SDTC_SSTR(var, type, flags, guiflags, def, max_length, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(#var, SDT_STDSTRING, SL_STDSTR, type, flags, guiflags, _settings_client.var, sizeof(_settings_client.var), def, 0, max_length, 0, nullptr, str, strhelp, strval, proc, from, to, cat, extra, startup) +#define SDTC_SSTR(var, type, flags, guiflags, def, max_length, proc, from, to, cat, extra, startup)\ + SDTG_SSTR(#var, type, flags, guiflags, _settings_client.var, def, max_length, proc, from, to, cat, extra, startup)\ #define SDTC_OMANY(var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat, extra, startup) - + SDTG_OMANY(#var, type, flags, guiflags, _settings_client.var, def, max, full, str, strhelp, strval, proc, from, to, cat, extra, startup) diff --git a/src/table/settings.ini b/src/table/settings.ini index ed07dfb118..4f105b5f66 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -67,13 +67,13 @@ SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDTC_BOOL = SDTC_BOOL( $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $from, $to, $cat, $extra, $startup), SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDTC_SSTR = SDTC_SSTR( $var, $type, $flags, $guiflags, $def, $length, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDTC_SSTR = SDTC_SSTR( $var, $type, $flags, $guiflags, $def, $length, $proc, $from, $to, $cat, $extra, $startup), SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat, $extra, $startup), -SDT_SSTR = SDT_SSTR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), +SDT_SSTR = SDT_SSTR($base, $var, $type, $flags, $guiflags, $def, $proc, $from, $to, $cat, $extra, $startup), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDT_NULL = SDT_NULL($length, $from, $to), From c3cd4a683d34191ff9619ef962060abc1acc5fe3 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 22 May 2021 13:39:41 +0200 Subject: [PATCH 03/14] Codechange: make formatting of values into strings a method of SettingDesc --- src/settings.cpp | 94 +++++++++++++++++++++-------------------- src/settings_internal.h | 17 ++++++++ 2 files changed, 65 insertions(+), 46 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 2c7d3aefe8..2964bad640 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -285,13 +285,13 @@ static bool LoadIntList(const char *str, void *array, int nelems, VarType type) * @param nelems the number of elements the array holds. * @param type the type of elements the array holds (eg INT8, UINT16, etc.) */ -static void MakeIntList(char *buf, const char *last, const void *array, int nelems, VarType type) +void ListSettingDesc::FormatValue(char *buf, const char *last, const void *object) const { + const byte *p = static_cast(GetVariableAddress(object, &this->save)); int i, v = 0; - const byte *p = (const byte *)array; - for (i = 0; i != nelems; i++) { - switch (GetVarMemType(type)) { + for (i = 0; i != this->save.length; i++) { + switch (GetVarMemType(this->save.conv)) { case SLE_VAR_BL: case SLE_VAR_I8: v = *(const int8 *)p; p += 1; break; case SLE_VAR_U8: v = *(const uint8 *)p; p += 1; break; @@ -301,9 +301,9 @@ static void MakeIntList(char *buf, const char *last, const void *array, int nele case SLE_VAR_U32: v = *(const uint32 *)p; p += 4; break; default: NOT_REACHED(); } - if (IsSignedVarMemType(type)) { + if (IsSignedVarMemType(this->save.conv)) { buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v); - } else if (type & SLF_HEX) { + } else if (this->save.conv & SLF_HEX) { buf += seprintf(buf, last, (i == 0) ? "0x%X" : ",0x%X", v); } else { buf += seprintf(buf, last, (i == 0) ? "%u" : ",%u", v); @@ -548,6 +548,16 @@ static void Write_ValidateStdString(void *ptr, const SettingDesc *sd, const char } } +/** + * Read the string from the the actual setting. + * @param object The object the setting is to be saved in. + * @return The value of the saved string. + */ +const std::string &StringSettingDesc::Read(const void *object) const +{ + return *reinterpret_cast(GetVariableAddress(object, &this->save)); +} + /** * Load values from a group of an IniFile structure into the internal representation * @param ini pointer to IniFile structure that holds administrative information @@ -665,11 +675,11 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co } item = group->GetItem(s, true); - ptr = GetVariableAddress(object, sld); if (item->value.has_value()) { /* check if the value is the same as the old value */ const void *p = StringToVal(sdb, item->value->c_str()); + ptr = GetVariableAddress(object, sld); /* The main type of a variable/setting is in bytes 8-15 * The subtype (what kind of numbers do we have there) is in 0-7 */ @@ -707,51 +717,43 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co } /* Value has changed, get the new value and put it into a buffer */ - switch (sdb->cmd) { - case SDT_BOOLX: - case SDT_NUMX: - case SDT_ONEOFMANY: - case SDT_MANYOFMANY: { - uint32 i = (uint32)ReadValue(ptr, sld->conv); - - switch (sdb->cmd) { - case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break; - case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : (sld->conv & SLF_HEX) ? "%X" : "%u", i); break; - case SDT_ONEOFMANY: MakeOneOfMany(buf, lastof(buf), sdb->many, i); break; - case SDT_MANYOFMANY: MakeManyOfMany(buf, lastof(buf), sdb->many, i); break; - default: NOT_REACHED(); - } - break; - } - - case SDT_STDSTRING: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STR: strecpy(buf, reinterpret_cast(ptr)->c_str(), lastof(buf)); break; - - case SLE_VAR_STRQ: - if (reinterpret_cast(ptr)->empty()) { - buf[0] = '\0'; - } else { - seprintf(buf, lastof(buf), "\"%s\"", reinterpret_cast(ptr)->c_str()); - } - break; - - default: NOT_REACHED(); - } - break; - - case SDT_INTLIST: - MakeIntList(buf, lastof(buf), ptr, sld->length, sld->conv); - break; - - default: NOT_REACHED(); - } + sdb->FormatValue(buf, lastof(buf), object); /* The value is different, that means we have to write it to the ini */ item->value.emplace(buf); } } +void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object) const +{ + uint32 i = (uint32)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + switch (this->cmd) { + case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", last); break; + case SDT_NUMX: seprintf(buf, last, IsSignedVarMemType(this->save.conv) ? "%d" : (this->save.conv & SLF_HEX) ? "%X" : "%u", i); break; + case SDT_ONEOFMANY: MakeOneOfMany(buf, last, this->many, i); break; + case SDT_MANYOFMANY: MakeManyOfMany(buf, last, this->many, i); break; + default: NOT_REACHED(); + } +} + +void StringSettingDesc::FormatValue(char *buf, const char *last, const void *object) const +{ + const std::string &str = this->Read(object); + switch (GetVarMemType(this->save. conv)) { + case SLE_VAR_STR: strecpy(buf, str.c_str(), last); break; + + case SLE_VAR_STRQ: + if (str.empty()) { + buf[0] = '\0'; + } else { + seprintf(buf, last, "\"%s\"", str.c_str()); + } + break; + + default: NOT_REACHED(); + } +} + /** * Loads all items from a 'grpname' section into a list * The list parameter can be a nullptr pointer, in this case nothing will be diff --git a/src/settings_internal.h b/src/settings_internal.h index 1accc47ed8..ee8b59be18 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -110,6 +110,14 @@ struct SettingDesc { bool IsEditable(bool do_command = false) const; SettingType GetType() const; + + /** + * Format the value of the setting associated with this object. + * @param buf The before of the buffer to format into. + * @param last The end of the buffer to format into. + * @param object The object the setting is in. + */ + virtual void FormatValue(char *buf, const char *last, const void *object) const = 0; }; /** Integer type, including boolean, settings. Only these are shown in the settings UI. */ @@ -120,6 +128,8 @@ struct IntSettingDesc : SettingDesc { SettingDesc(save, name, (void*)(size_t)def, cmd, flags, min, max, interval, many, str, str_help, str_val, proc, many_cnvt, cat, startup) {} virtual ~IntSettingDesc() {} + + void FormatValue(char *buf, const char *last, const void *object) const override; }; /** String settings. */ @@ -128,6 +138,9 @@ struct StringSettingDesc : SettingDesc { uint32 max_length, OnChange proc) : SettingDesc(save, name, def, cmd, flags, 0, max_length, 0, nullptr, 0, 0, 0, proc, nullptr, SC_NONE, startup) {} virtual ~StringSettingDesc() {} + + void FormatValue(char *buf, const char *last, const void *object) const override; + const std::string &Read(const void *object) const; }; /** List/array settings. */ @@ -135,6 +148,8 @@ struct ListSettingDesc : SettingDesc { ListSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def) : SettingDesc(save, name, def, cmd, flags, 0, 0, 0, nullptr, 0, 0, 0, proc, nullptr, SC_NONE, startup) {} virtual ~ListSettingDesc() {} + + void FormatValue(char *buf, const char *last, const void *object) const override; }; /** Placeholder for settings that have been removed, but might still linger in the savegame. */ @@ -142,6 +157,8 @@ struct NullSettingDesc : SettingDesc { NullSettingDesc(SaveLoad save) : SettingDesc(save, "", nullptr, SDT_NULL, SGF_NONE, 0, 0, 0, nullptr, 0, 0, 0, nullptr, nullptr, SC_NONE, false) {} virtual ~NullSettingDesc() {} + + void FormatValue(char *buf, const char *last, const void *object) const override { NOT_REACHED(); } }; typedef std::initializer_list> SettingTable; From 024e584904bc9ee4ac63a8c84fa37a065974fcdc Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 22 May 2021 13:46:39 +0200 Subject: [PATCH 04/14] Cleanup: use (config) formatting for console settings functions --- src/settings.cpp | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 2964bad640..f5d4a96605 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2204,26 +2204,20 @@ void IConsoleSetSetting(const char *name, int value) */ void IConsoleGetSetting(const char *name, bool force_newgame) { - char value[20]; const SettingDesc *sd = GetSettingFromName(name); - const void *ptr; - if (sd == nullptr) { IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); return; } - ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); + const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game; if (sd->cmd == SDT_STDSTRING) { + const void *ptr = GetVariableAddress(object, &sd->save); IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, reinterpret_cast(ptr)->c_str()); } else { - if (sd->cmd == SDT_BOOLX) { - seprintf(value, lastof(value), (*(const bool*)ptr != 0) ? "on" : "off"); - } else { - seprintf(value, lastof(value), sd->min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); - } - + char value[20]; + sd->FormatValue(value, lastof(value), object); IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %u)", name, value, (sd->flags & SGF_0ISDISABLED) ? "(0) " : "", sd->min, sd->max); } @@ -2242,15 +2236,7 @@ void IConsoleListSettings(const char *prefilter) if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; if (prefilter != nullptr && strstr(sd->name, prefilter) == nullptr) continue; char value[80]; - const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save); - - if (sd->cmd == SDT_BOOLX) { - seprintf(value, lastof(value), (*(const bool *)ptr != 0) ? "on" : "off"); - } else if (sd->cmd == SDT_STDSTRING) { - seprintf(value, lastof(value), "%s", reinterpret_cast(ptr)->c_str()); - } else { - seprintf(value, lastof(value), sd->min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); - } + sd->FormatValue(value, lastof(value), &GetGameSettings()); IConsolePrintF(CC_DEFAULT, "%s = %s", sd->name, value); } From be28c95b30eb433de5e7b9831657af551ef236f9 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 22 May 2021 20:44:09 +0200 Subject: [PATCH 05/14] Codechange: make Write_ValidateSetting a function of IntSettingDesc --- src/settings.cpp | 185 +++++++++++++++++++--------------------- src/settings_internal.h | 5 ++ 2 files changed, 94 insertions(+), 96 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index f5d4a96605..8bdfced960 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -446,33 +446,22 @@ static const void *StringToVal(const SettingDesc *desc, const char *orig_str) } /** - * Set the value of a setting and if needed clamp the value to - * the preset minimum and maximum. - * @param ptr the variable itself - * @param sd pointer to the 'information'-database of the variable - * @param val signed long version of the new value - * @pre SettingDesc is of type SDT_BOOLX, SDT_NUMX, - * SDT_ONEOFMANY or SDT_MANYOFMANY. Other types are not supported as of now + * Set the value of a setting and if needed clamp the value to the preset minimum and maximum. + * @param object The object the setting is to be saved in. + * @param val Signed version of the new value. */ -static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) +void IntSettingDesc::Write_ValidateSetting(const void *object, int32 val) const { - const SettingDesc *sdb = sd; - - if (sdb->cmd != SDT_BOOLX && - sdb->cmd != SDT_NUMX && - sdb->cmd != SDT_ONEOFMANY && - sdb->cmd != SDT_MANYOFMANY) { - return; - } + void *ptr = GetVariableAddress(object, &this->save); /* We cannot know the maximum value of a bitset variable, so just have faith */ - if (sdb->cmd != SDT_MANYOFMANY) { + if (this->cmd != SDT_MANYOFMANY) { /* We need to take special care of the uint32 type as we receive from the function * a signed integer. While here also bail out on 64-bit settings as those are not * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed * 32-bit variable * TODO: Support 64-bit settings/variables */ - switch (GetVarMemType(sd->save.conv)) { + switch (GetVarMemType(this->save.conv)) { case SLE_VAR_NULL: return; case SLE_VAR_BL: case SLE_VAR_I8: @@ -481,13 +470,13 @@ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) case SLE_VAR_U16: case SLE_VAR_I32: { /* Override the minimum value. No value below sdb->min, except special value 0 */ - if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) { - if (!(sdb->flags & SGF_MULTISTRING)) { + if (!(this->flags & SGF_0ISDISABLED) || val != 0) { + if (!(this->flags & SGF_MULTISTRING)) { /* Clamp value-type setting to its valid range */ - val = Clamp(val, sdb->min, sdb->max); - } else if (val < sdb->min || val > (int32)sdb->max) { + val = Clamp(val, this->min, this->max); + } else if (val < this->min || val > (int32)this->max) { /* Reset invalid discrete setting (where different values change gameplay) to its default value */ - val = (int32)(size_t)sdb->def; + val = (int32)(size_t)this->def; } } break; @@ -495,13 +484,13 @@ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) case SLE_VAR_U32: { /* Override the minimum value. No value below sdb->min, except special value 0 */ uint32 uval = (uint32)val; - if (!(sdb->flags & SGF_0ISDISABLED) || uval != 0) { - if (!(sdb->flags & SGF_MULTISTRING)) { + if (!(this->flags & SGF_0ISDISABLED) || uval != 0) { + if (!(this->flags & SGF_MULTISTRING)) { /* Clamp value-type setting to its valid range */ - uval = ClampU(uval, sdb->min, sdb->max); - } else if (uval < (uint)sdb->min || uval > sdb->max) { + uval = ClampU(uval, this->min, this->max); + } else if (uval < (uint)this->min || uval > this->max) { /* Reset invalid discrete setting to its default value */ - uval = (uint32)(size_t)sdb->def; + uval = (uint32)(size_t)this->def; } } WriteValue(ptr, SLE_VAR_U32, (int64)uval); @@ -513,7 +502,7 @@ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) } } - WriteValue(ptr, sd->save.conv, (int64)val); + WriteValue(ptr, this->save.conv, (int64)val); } /** @@ -610,7 +599,7 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co case SDT_NUMX: case SDT_ONEOFMANY: case SDT_MANYOFMANY: - Write_ValidateSetting(ptr, sd.get(), (int32)(size_t)p); + sd->AsIntSetting()->Write_ValidateSetting(object, (int32)(size_t)p); break; case SDT_STDSTRING: @@ -846,6 +835,24 @@ SettingType SettingDesc::GetType() const return (this->save.conv & SLF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME; } +/** + * Check whether this setting is an integer type setting. + * @return True when the underlying type is an integer. + */ +bool SettingDesc::IsIntSetting() const { + return this->cmd == SDT_BOOLX || this->cmd == SDT_NUMX || this->cmd == SDT_ONEOFMANY || this->cmd == SDT_MANYOFMANY; +} + +/** + * Get the setting description of this setting as an integer setting. + * @return The integer setting description. + */ +const IntSettingDesc *SettingDesc::AsIntSetting() const +{ + assert(this->IsIntSetting()); + return static_cast(this); +} + /* Begin - Callback Functions for the various settings. */ /** Reposition the main toolbar as the setting changed. */ @@ -1451,8 +1458,8 @@ static void HandleOldDiffCustom(bool savegame) const SettingDesc *sd = GetSettingDescription(i); /* Skip deprecated options */ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - void *var = GetVariableAddress(savegame ? &_settings_game : &_settings_newgame, &sd->save); - Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i])); + int32 value = (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i]); + sd->AsIntSetting()->Write_ValidateSetting(savegame ? &_settings_game : &_settings_newgame, value); } } @@ -1879,6 +1886,40 @@ void DeleteGRFPresetFromConfig(const char *config_name) delete ini; } +/** + * Handle changing a value. This performs validation of the input value and + * calls the appropriate callbacks, and saves it when the value is changed. + * @param object The object the setting is in. + * @param newval The new value for the setting. + */ +void IntSettingDesc::ChangeValue(const void *object, int32 newval) const +{ + void *var = GetVariableAddress(object, &this->save); + + int32 oldval = (int32)ReadValue(var, this->save.conv); + + this->Write_ValidateSetting(object, newval); + newval = (int32)ReadValue(var, this->save.conv); + + if (oldval == newval) return; + + if (this->proc != nullptr && !this->proc(newval)) { + /* The change was not allowed, so revert. */ + WriteValue(var, this->save.conv, (int64)oldval); + return; + } + + if (this->flags & SGF_NO_NETWORK) { + GamelogStartAction(GLAT_SETTING); + GamelogSetting(this->name, oldval, newval); + GamelogStopAction(); + } + + SetWindowClassesDirty(WC_GAME_OPTIONS); + + if (_save_config) SaveToConfig(); +} + /** * Network-safe changing of settings (server-only). * @param tile unused @@ -1896,34 +1937,12 @@ CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (sd == nullptr) return CMD_ERROR; if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR; + if (!sd->IsIntSetting()) return CMD_ERROR; if (!sd->IsEditable(true)) return CMD_ERROR; if (flags & DC_EXEC) { - void *var = GetVariableAddress(&GetGameSettings(), &sd->save); - - int32 oldval = (int32)ReadValue(var, sd->save.conv); - int32 newval = (int32)p2; - - Write_ValidateSetting(var, sd, newval); - newval = (int32)ReadValue(var, sd->save.conv); - - if (oldval == newval) return CommandCost(); - - if (sd->proc != nullptr && !sd->proc(newval)) { - WriteValue(var, sd->save.conv, (int64)oldval); - return CommandCost(); - } - - if (sd->flags & SGF_NO_NETWORK) { - GamelogStartAction(GLAT_SETTING); - GamelogSetting(sd->name, oldval, newval); - GamelogStopAction(); - } - - SetWindowClassesDirty(WC_GAME_OPTIONS); - - if (_save_config) SaveToConfig(); + sd->AsIntSetting()->ChangeValue(&GetGameSettings(), p2); } return CommandCost(); @@ -1943,24 +1962,10 @@ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 { const SettingDesc *sd = GetCompanySettingDescription(p1); if (sd == nullptr) return CMD_ERROR; + if (!sd->IsIntSetting()) return CMD_ERROR; if (flags & DC_EXEC) { - void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); - - int32 oldval = (int32)ReadValue(var, sd->save.conv); - int32 newval = (int32)p2; - - Write_ValidateSetting(var, sd, newval); - newval = (int32)ReadValue(var, sd->save.conv); - - if (oldval == newval) return CommandCost(); - - if (sd->proc != nullptr && !sd->proc(newval)) { - WriteValue(var, sd->save.conv, (int64)oldval); - return CommandCost(); - } - - SetWindowClassesDirty(WC_GAME_OPTIONS); + sd->AsIntSetting()->ChangeValue(&Company::Get(_current_company)->settings, p2); } return CommandCost(); @@ -2013,14 +2018,13 @@ static uint GetCompanySettingIndex(const SettingDesc *sd) */ bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame) { - if ((sd->flags & SGF_PER_COMPANY) != 0) { + const IntSettingDesc *setting = sd->AsIntSetting(); + if ((setting->flags & SGF_PER_COMPANY) != 0) { if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { - return DoCommandP(0, GetCompanySettingIndex(sd), value, CMD_CHANGE_COMPANY_SETTING); + return DoCommandP(0, GetCompanySettingIndex(setting), value, CMD_CHANGE_COMPANY_SETTING); } - void *var = GetVariableAddress(&_settings_client.company, &sd->save); - Write_ValidateSetting(var, sd, value); - if (sd->proc != nullptr) sd->proc((int32)ReadValue(var, sd->save.conv)); + setting->ChangeValue(&_settings_client.company, value); return true; } @@ -2028,33 +2032,22 @@ bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame) * (if any) to change. Also *hack*hack* we update the _newgame version * of settings because changing a company-based setting in a game also * changes its defaults. At least that is the convention we have chosen */ - if (sd->save.conv & SLF_NO_NETWORK_SYNC) { - void *var = GetVariableAddress(&GetGameSettings(), &sd->save); - Write_ValidateSetting(var, sd, value); - + if (setting->save.conv & SLF_NO_NETWORK_SYNC) { if (_game_mode != GM_MENU) { - void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); - Write_ValidateSetting(var2, sd, value); + setting->ChangeValue(&_settings_newgame, value); } - if (sd->proc != nullptr) sd->proc((int32)ReadValue(var, sd->save.conv)); - - SetWindowClassesDirty(WC_GAME_OPTIONS); - - if (_save_config) SaveToConfig(); + setting->ChangeValue(&GetGameSettings(), value); return true; } if (force_newgame) { - void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); - Write_ValidateSetting(var2, sd, value); - - if (_save_config) SaveToConfig(); + setting->ChangeValue(&_settings_newgame, value); return true; } /* send non-company-based settings over the network */ if (!_networking || (_networking && _network_server)) { - return DoCommandP(0, GetSettingIndex(sd), value, CMD_CHANGE_SETTING); + return DoCommandP(0, GetSettingIndex(setting), value, CMD_CHANGE_SETTING); } return false; } @@ -2066,8 +2059,8 @@ void SetDefaultCompanySettings(CompanyID cid) { Company *c = Company::Get(cid); for (auto &sd : _company_settings) { - void *var = GetVariableAddress(&c->settings, &sd->save); - Write_ValidateSetting(var, sd.get(), (int32)(size_t)sd->def); + const IntSettingDesc *int_setting = sd->AsIntSetting(); + int_setting->Write_ValidateSetting(&c->settings, (int32)(size_t)int_setting->def); } } @@ -2256,7 +2249,7 @@ static void LoadSettings(const SettingTable &settings, void *object) void *ptr = GetVariableAddress(object, sld); if (!SlObjectMember(ptr, sld)) continue; - if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, osd.get(), ReadValue(ptr, sld->conv)); + if (osd->IsIntSetting()) osd->AsIntSetting()->Write_ValidateSetting(object, ReadValue(ptr, sld->conv)); } } diff --git a/src/settings_internal.h b/src/settings_internal.h index ee8b59be18..7b37ac2676 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -110,6 +110,8 @@ struct SettingDesc { bool IsEditable(bool do_command = false) const; SettingType GetType() const; + bool IsIntSetting() const; + const struct IntSettingDesc *AsIntSetting() const; /** * Format the value of the setting associated with this object. @@ -129,6 +131,9 @@ struct IntSettingDesc : SettingDesc { proc, many_cnvt, cat, startup) {} virtual ~IntSettingDesc() {} + void ChangeValue(const void *object, int32 newvalue) const; + void Write_ValidateSetting(const void *object, int32 value) const; + void FormatValue(char *buf, const char *last, const void *object) const override; }; From 1f8ff0e4f9895538a98f2a22b2f6b6e62310aae9 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 22 May 2021 20:52:24 +0200 Subject: [PATCH 06/14] Codechange: make Write_ValidateSetting a function of StringSettingDesc --- src/settings.cpp | 60 ++++++++++++++++++++++++++++++----------- src/settings_internal.h | 5 ++++ 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 8bdfced960..cedfdf5af0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -507,26 +507,25 @@ void IntSettingDesc::Write_ValidateSetting(const void *object, int32 val) const /** * Set the string value of a setting. - * @param ptr Pointer to the std::string. - * @param sd Pointer to the information for the conversions and limitations to apply. - * @param p The string to save. + * @param object The object the setting is to be saved in. + * @param str The string to save. */ -static void Write_ValidateStdString(void *ptr, const SettingDesc *sd, const char *p) +void StringSettingDesc::Write_ValidateSetting(const void *object, const char *str) const { - std::string *dst = reinterpret_cast(ptr); + std::string *dst = reinterpret_cast(GetVariableAddress(object, &this->save)); - switch (GetVarMemType(sd->save.conv)) { + switch (GetVarMemType(this->save.conv)) { case SLE_VAR_STR: case SLE_VAR_STRQ: - if (p != nullptr) { - if (sd->max != 0 && strlen(p) >= sd->max) { + if (str != nullptr) { + if (this->max != 0 && strlen(str) >= this->max) { /* In case a maximum length is imposed by the setting, the length * includes the '\0' termination for network transfer purposes. * Also ensure the string is valid after chopping of some bytes. */ - std::string str(p, sd->max - 1); - dst->assign(str_validate(str, SVS_NONE)); + std::string stdstr(str, this->max - 1); + dst->assign(str_validate(stdstr, SVS_NONE)); } else { - dst->assign(p); + dst->assign(str); } } else { dst->clear(); @@ -603,7 +602,7 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co break; case SDT_STDSTRING: - Write_ValidateStdString(ptr, sd.get(), (const char *)p); + sd->AsStringSetting()->Write_ValidateSetting(object, (const char *)p); break; case SDT_INTLIST: { @@ -843,6 +842,14 @@ bool SettingDesc::IsIntSetting() const { return this->cmd == SDT_BOOLX || this->cmd == SDT_NUMX || this->cmd == SDT_ONEOFMANY || this->cmd == SDT_MANYOFMANY; } +/** + * Check whether this setting is an string type setting. + * @return True when the underlying type is a string. + */ +bool SettingDesc::IsStringSetting() const { + return this->cmd == SDT_STDSTRING; +} + /** * Get the setting description of this setting as an integer setting. * @return The integer setting description. @@ -853,6 +860,16 @@ const IntSettingDesc *SettingDesc::AsIntSetting() const return static_cast(this); } +/** + * Get the setting description of this setting as a string setting. + * @return The string setting description. + */ +const StringSettingDesc *SettingDesc::AsStringSetting() const +{ + assert(this->IsStringSetting()); + return static_cast(this); +} + /* Begin - Callback Functions for the various settings. */ /** Reposition the main toolbar as the setting changed. */ @@ -2105,12 +2122,23 @@ bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgam value = nullptr; } - void *ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); - Write_ValidateStdString(ptr, sd, value); - if (sd->proc != nullptr) sd->proc(0); + const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game; + sd->AsStringSetting()->ChangeValue(object, value); + return true; +} + +/** + * Handle changing a string value. This performs validation of the input value + * and calls the appropriate callbacks, and saves it when the value is changed. + * @param object The object the setting is in. + * @param newval The new value for the setting. + */ +void StringSettingDesc::ChangeValue(const void *object, const char *newval) const +{ + this->Write_ValidateSetting(object, newval); + if (this->proc != nullptr) this->proc(0); if (_save_config) SaveToConfig(); - return true; } /** diff --git a/src/settings_internal.h b/src/settings_internal.h index 7b37ac2676..33910e066b 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -111,7 +111,9 @@ struct SettingDesc { bool IsEditable(bool do_command = false) const; SettingType GetType() const; bool IsIntSetting() const; + bool IsStringSetting() const; const struct IntSettingDesc *AsIntSetting() const; + const struct StringSettingDesc *AsStringSetting() const; /** * Format the value of the setting associated with this object. @@ -144,6 +146,9 @@ struct StringSettingDesc : SettingDesc { SettingDesc(save, name, def, cmd, flags, 0, max_length, 0, nullptr, 0, 0, 0, proc, nullptr, SC_NONE, startup) {} virtual ~StringSettingDesc() {} + void ChangeValue(const void *object, const char *newval) const; + void Write_ValidateSetting(const void *object, const char *str) const; + void FormatValue(char *buf, const char *last, const void *object) const override; const std::string &Read(const void *object) const; }; From f6723b53dabfb7d0610fb1a482ea34a933b5fae7 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 22 May 2021 20:57:41 +0200 Subject: [PATCH 07/14] Codechange: make parsing of IniItems overridable functions of SettingDesc --- src/settings.cpp | 176 +++++++++++++++++----------------------- src/settings_internal.h | 28 +++++++ 2 files changed, 104 insertions(+), 100 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index cedfdf5af0..a99b196b4c 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -374,75 +374,70 @@ static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 } /** - * Convert a string representation (external) of a setting to the internal rep. - * @param desc SettingDesc struct that holds all information about the variable - * @param orig_str input string that will be parsed based on the type of desc - * @return return the parsed value of the setting + * Convert a string representation (external) of an integer-like setting to an integer. + * @param str Input string that will be parsed based on the type of desc. + * @return The value from the parse string, or the default value of the setting. */ -static const void *StringToVal(const SettingDesc *desc, const char *orig_str) +size_t IntSettingDesc::ParseValue(const char *str) const { - const char *str = orig_str == nullptr ? "" : orig_str; - - switch (desc->cmd) { + switch (this->cmd) { case SDT_NUMX: { char *end; size_t val = strtoul(str, &end, 0); if (end == str) { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); + msg.SetDParamStr(1, this->name); _settings_error_list.push_back(msg); - return desc->def; + break; } if (*end != '\0') { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS); - msg.SetDParamStr(0, desc->name); + msg.SetDParamStr(0, this->name); _settings_error_list.push_back(msg); } - return (void*)val; + return val; } case SDT_ONEOFMANY: { - size_t r = LookupOneOfMany(desc->many, str); + size_t r = LookupOneOfMany(this->many, str); /* if the first attempt of conversion from string to the appropriate value fails, * look if we have defined a converter from old value to new value. */ - if (r == (size_t)-1 && desc->proc_cnvt != nullptr) r = desc->proc_cnvt(str); - if (r != (size_t)-1) return (void*)r; // and here goes converted value + if (r == (size_t)-1 && this->proc_cnvt != nullptr) r = this->proc_cnvt(str); + if (r != (size_t)-1) return r; // and here goes converted value ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); + msg.SetDParamStr(1, this->name); _settings_error_list.push_back(msg); - return desc->def; + break; } case SDT_MANYOFMANY: { - size_t r = LookupManyOfMany(desc->many, str); - if (r != (size_t)-1) return (void*)r; + size_t r = LookupManyOfMany(this->many, str); + if (r != (size_t)-1) return r; ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); + msg.SetDParamStr(1, this->name); _settings_error_list.push_back(msg); - return desc->def; + break; } case SDT_BOOLX: { - if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return (void*)true; - if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return (void*)false; + if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true; + if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false; ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); - msg.SetDParamStr(1, desc->name); + msg.SetDParamStr(1, this->name); _settings_error_list.push_back(msg); - return desc->def; + break; } - case SDT_STDSTRING: return orig_str; - case SDT_INTLIST: return str; - default: break; + default: NOT_REACHED(); } - return nullptr; + return (size_t)this->def; } /** @@ -590,36 +585,33 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co if (sc != std::string::npos) item = ini->GetGroup(s.substr(0, sc))->GetItem(s.substr(sc + 1), false); } - const void *p = (item == nullptr) ? sdb->def : StringToVal(sdb, item->value.has_value() ? item->value->c_str() : nullptr); - void *ptr = GetVariableAddress(object, sld); + sdb->ParseValue(item, object); + } +} - switch (sdb->cmd) { - case SDT_BOOLX: // All four are various types of (integer) numbers - case SDT_NUMX: - case SDT_ONEOFMANY: - case SDT_MANYOFMANY: - sd->AsIntSetting()->Write_ValidateSetting(object, (int32)(size_t)p); - break; +void IntSettingDesc::ParseValue(const IniItem *item, void *object) const +{ + size_t val = (item == nullptr) ? (size_t)this->def : this->ParseValue(item->value.has_value() ? item->value->c_str() : ""); + this->Write_ValidateSetting(object, (int32)val); +} - case SDT_STDSTRING: - sd->AsStringSetting()->Write_ValidateSetting(object, (const char *)p); - break; +void StringSettingDesc::ParseValue(const IniItem *item, void *object) const +{ + const char *str = (item == nullptr) ? (const char *)this->def : item->value.has_value() ? item->value->c_str() : nullptr; + this->Write_ValidateSetting(object, str); +} - case SDT_INTLIST: { - if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) { - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); - msg.SetDParamStr(0, sdb->name); - _settings_error_list.push_back(msg); +void ListSettingDesc::ParseValue(const IniItem *item, void *object) const +{ + const char *str = (item == nullptr) ? (const char *)this->def : item->value.has_value() ? item->value->c_str() : nullptr; + void *ptr = GetVariableAddress(object, &this->save); + if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); + msg.SetDParamStr(0, this->name); + _settings_error_list.push_back(msg); - /* Use default */ - LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); - } else if (sd->proc_cnvt != nullptr) { - sd->proc_cnvt((const char*)p); - } - break; - } - default: NOT_REACHED(); - } + /* Use default */ + LoadIntList((const char*)this->def, ptr, this->save.length, GetVarMemType(this->save.conv)); } } @@ -640,7 +632,6 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co IniGroup *group_def = nullptr, *group; IniItem *item; char buf[512]; - void *ptr; for (auto &sd : settings_table) { const SettingDesc *sdb = sd.get(); @@ -664,51 +655,13 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co item = group->GetItem(s, true); - if (item->value.has_value()) { - /* check if the value is the same as the old value */ - const void *p = StringToVal(sdb, item->value->c_str()); - ptr = GetVariableAddress(object, sld); + if (!item->value.has_value() || !sdb->IsSameValue(item, object)) { + /* Value has changed, get the new value and put it into a buffer */ + sdb->FormatValue(buf, lastof(buf), object); - /* The main type of a variable/setting is in bytes 8-15 - * The subtype (what kind of numbers do we have there) is in 0-7 */ - switch (sdb->cmd) { - case SDT_BOOLX: - case SDT_NUMX: - case SDT_ONEOFMANY: - case SDT_MANYOFMANY: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_BL: - if (*(bool*)ptr == (p != nullptr)) continue; - break; - - case SLE_VAR_I8: - case SLE_VAR_U8: - if (*(byte*)ptr == (byte)(size_t)p) continue; - break; - - case SLE_VAR_I16: - case SLE_VAR_U16: - if (*(uint16*)ptr == (uint16)(size_t)p) continue; - break; - - case SLE_VAR_I32: - case SLE_VAR_U32: - if (*(uint32*)ptr == (uint32)(size_t)p) continue; - break; - - default: NOT_REACHED(); - } - break; - - default: break; // Assume the other types are always changed - } + /* The value is different, that means we have to write it to the ini */ + item->value.emplace(buf); } - - /* Value has changed, get the new value and put it into a buffer */ - sdb->FormatValue(buf, lastof(buf), object); - - /* The value is different, that means we have to write it to the ini */ - item->value.emplace(buf); } } @@ -724,10 +677,17 @@ void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object } } +bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const +{ + int64 item_value = this->ParseValue(item->value->c_str()); + int64 object_value = ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + return item_value == object_value; +} + void StringSettingDesc::FormatValue(char *buf, const char *last, const void *object) const { const std::string &str = this->Read(object); - switch (GetVarMemType(this->save. conv)) { + switch (GetVarMemType(this->save.conv)) { case SLE_VAR_STR: strecpy(buf, str.c_str(), last); break; case SLE_VAR_STRQ: @@ -742,6 +702,22 @@ void StringSettingDesc::FormatValue(char *buf, const char *last, const void *obj } } +bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const +{ + /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs, + * so those values are always different in the parsed ini item than they should be. */ + if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false; + + const std::string &str = this->Read(object); + return item->value->compare(str) == 0; +} + +bool ListSettingDesc::IsSameValue(const IniItem *item, void *object) const +{ + /* Checking for equality is way more expensive than just writing the value. */ + return false; +} + /** * Loads all items from a 'grpname' section into a list * The list parameter can be a nullptr pointer, in this case nothing will be diff --git a/src/settings_internal.h b/src/settings_internal.h index 33910e066b..0914f2803f 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -79,6 +79,7 @@ enum SettingType { ST_ALL, ///< Used in setting filter to match all types. }; +struct IniItem; typedef bool OnChange(int32 var); ///< callback prototype on data modification typedef size_t OnConvert(const char *value); ///< callback prototype for conversion error @@ -122,6 +123,24 @@ struct SettingDesc { * @param object The object the setting is in. */ virtual void FormatValue(char *buf, const char *last, const void *object) const = 0; + + /** + * Parse/read the value from the Ini item into the setting associated with this object. + * @param item The Ini item with the content of this setting. + * @param object The object the setting is in. + */ + virtual void ParseValue(const IniItem *item, void *object) const = 0; + + /** + * Check whether the value in the Ini item is the same as is saved in this setting in the object. + * It might be that determining whether the value is the same is way more expensive than just + * writing the value. In those cases this function may unconditionally return false even though + * the value might be the same as in the Ini item. + * @param item The Ini item with the content of this setting. + * @param object The object the setting is in. + * @return True if the value is definitely the same (might be false when the same). + */ + virtual bool IsSameValue(const IniItem *item, void *object) const = 0; }; /** Integer type, including boolean, settings. Only these are shown in the settings UI. */ @@ -136,7 +155,10 @@ struct IntSettingDesc : SettingDesc { void ChangeValue(const void *object, int32 newvalue) const; void Write_ValidateSetting(const void *object, int32 value) const; + size_t ParseValue(const char *str) const; void FormatValue(char *buf, const char *last, const void *object) const override; + void ParseValue(const IniItem *item, void *object) const override; + bool IsSameValue(const IniItem *item, void *object) const override; }; /** String settings. */ @@ -150,6 +172,8 @@ struct StringSettingDesc : SettingDesc { void Write_ValidateSetting(const void *object, const char *str) const; void FormatValue(char *buf, const char *last, const void *object) const override; + void ParseValue(const IniItem *item, void *object) const override; + bool IsSameValue(const IniItem *item, void *object) const override; const std::string &Read(const void *object) const; }; @@ -160,6 +184,8 @@ struct ListSettingDesc : SettingDesc { virtual ~ListSettingDesc() {} void FormatValue(char *buf, const char *last, const void *object) const override; + void ParseValue(const IniItem *item, void *object) const override; + bool IsSameValue(const IniItem *item, void *object) const override; }; /** Placeholder for settings that have been removed, but might still linger in the savegame. */ @@ -169,6 +195,8 @@ struct NullSettingDesc : SettingDesc { virtual ~NullSettingDesc() {} void FormatValue(char *buf, const char *last, const void *object) const override { NOT_REACHED(); } + void ParseValue(const IniItem *item, void *object) const override { NOT_REACHED(); } + bool IsSameValue(const IniItem *item, void *object) const override { NOT_REACHED(); } }; typedef std::initializer_list> SettingTable; From f58611298e17e925f98e9e36d1297f47650d4067 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 23 May 2021 11:37:56 +0200 Subject: [PATCH 08/14] Codechange: use IntSettingDesc in the settings GUI --- src/settings_gui.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index f4570624d7..ef1024278f 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -74,7 +74,7 @@ static const StringID _font_zoom_dropdown[] = { static Dimension _circle_size; ///< Dimension of the circle +/- icon. This is here as not all users are within the class of the settings window. -static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd); +static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const IntSettingDesc *sd); /** * Get index of the current screen resolution. @@ -824,8 +824,8 @@ protected: /** Standard setting */ struct SettingEntry : BaseSettingEntry { - const char *name; ///< Name of the setting - const SettingDesc *setting; ///< Setting description of the setting + const char *name; ///< Name of the setting + const IntSettingDesc *setting; ///< Setting description of the setting SettingEntry(const char *name); @@ -1029,8 +1029,7 @@ SettingEntry::SettingEntry(const char *name) void SettingEntry::Init(byte level) { BaseSettingEntry::Init(level); - this->setting = GetSettingFromName(this->name); - assert(this->setting != nullptr); + this->setting = GetSettingFromName(this->name)->AsIntSetting(); } /* Sets the given setting entry to its default value */ @@ -1078,7 +1077,7 @@ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const if (mode == RM_ALL) return true; GameSettings *settings_ptr = &GetGameSettings(); - const SettingDesc *sd = this->setting; + const IntSettingDesc *sd = this->setting; if (mode == RM_BASIC) return (this->setting->cat & SC_BASIC_LIST) != 0; if (mode == RM_ADVANCED) return (this->setting->cat & SC_ADVANCED_LIST) != 0; @@ -1122,7 +1121,7 @@ bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) bool visible = true; - const SettingDesc *sd = this->setting; + const IntSettingDesc *sd = this->setting; if (!force_visible && !filter.string.IsEmpty()) { /* Process the search text filter for this item. */ filter.string.ResetState(); @@ -1149,7 +1148,7 @@ bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) return visible; } -static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd) +static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const IntSettingDesc *sd) { if ((sd->flags & SGF_PER_COMPANY) != 0) { if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { @@ -1194,7 +1193,7 @@ void SettingEntry::SetValueDParams(uint first_param, int32 value) const */ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const { - const SettingDesc *sd = this->setting; + const IntSettingDesc *sd = this->setting; const void *var = ResolveVariableAddress(settings_ptr, sd); int state = this->flags & SEF_BUTTONS_MASK; @@ -2075,7 +2074,7 @@ struct GameSettingsWindow : Window { case WID_GS_HELP_TEXT: if (this->last_clicked != nullptr) { - const SettingDesc *sd = this->last_clicked->setting; + const IntSettingDesc *sd = this->last_clicked->setting; int y = r.top; switch (sd->GetType()) { @@ -2179,7 +2178,7 @@ struct GameSettingsWindow : Window { SettingEntry *pe = dynamic_cast(clicked_entry); assert(pe != nullptr); - const SettingDesc *sd = pe->setting; + const IntSettingDesc *sd = pe->setting; /* return if action is only active in network, or only settable by server */ if (!sd->IsEditable()) { @@ -2314,7 +2313,7 @@ struct GameSettingsWindow : Window { if (str == nullptr) return; assert(this->valuewindow_entry != nullptr); - const SettingDesc *sd = this->valuewindow_entry->setting; + const IntSettingDesc *sd = this->valuewindow_entry->setting; int32 value; if (!StrEmpty(str)) { @@ -2361,7 +2360,7 @@ struct GameSettingsWindow : Window { if (widget < 0) { /* Deal with drop down boxes on the panel. */ assert(this->valuedropdown_entry != nullptr); - const SettingDesc *sd = this->valuedropdown_entry->setting; + const IntSettingDesc *sd = this->valuedropdown_entry->setting; assert(sd->flags & SGF_MULTISTRING); SetSettingValue(sd, index); From 0d6597a9e6255193c306537aa0061b5a89b7c658 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sat, 22 May 2021 21:09:30 +0200 Subject: [PATCH 09/14] Codechange: move bits of SettingDesc down to the appropriate sub classes And by doing so remove the hack where ints were put into pointers so "def" could either be an int or a string --- src/settings.cpp | 27 ++++++++++----------- src/settings_gui.cpp | 10 ++++---- src/settings_internal.h | 52 ++++++++++++++++++++++------------------- 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index a99b196b4c..df064499a9 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -403,7 +403,7 @@ size_t IntSettingDesc::ParseValue(const char *str) const size_t r = LookupOneOfMany(this->many, str); /* if the first attempt of conversion from string to the appropriate value fails, * look if we have defined a converter from old value to new value. */ - if (r == (size_t)-1 && this->proc_cnvt != nullptr) r = this->proc_cnvt(str); + if (r == (size_t)-1 && this->many_cnvt != nullptr) r = this->many_cnvt(str); if (r != (size_t)-1) return r; // and here goes converted value ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); @@ -437,7 +437,7 @@ size_t IntSettingDesc::ParseValue(const char *str) const default: NOT_REACHED(); } - return (size_t)this->def; + return this->def; } /** @@ -471,7 +471,7 @@ void IntSettingDesc::Write_ValidateSetting(const void *object, int32 val) const val = Clamp(val, this->min, this->max); } else if (val < this->min || val > (int32)this->max) { /* Reset invalid discrete setting (where different values change gameplay) to its default value */ - val = (int32)(size_t)this->def; + val = this->def; } } break; @@ -485,7 +485,7 @@ void IntSettingDesc::Write_ValidateSetting(const void *object, int32 val) const uval = ClampU(uval, this->min, this->max); } else if (uval < (uint)this->min || uval > this->max) { /* Reset invalid discrete setting to its default value */ - uval = (uint32)(size_t)this->def; + uval = (uint32)this->def; } } WriteValue(ptr, SLE_VAR_U32, (int64)uval); @@ -513,11 +513,11 @@ void StringSettingDesc::Write_ValidateSetting(const void *object, const char *st case SLE_VAR_STR: case SLE_VAR_STRQ: if (str != nullptr) { - if (this->max != 0 && strlen(str) >= this->max) { + if (this->max_length != 0 && strlen(str) >= this->max_length) { /* In case a maximum length is imposed by the setting, the length * includes the '\0' termination for network transfer purposes. * Also ensure the string is valid after chopping of some bytes. */ - std::string stdstr(str, this->max - 1); + std::string stdstr(str, this->max_length - 1); dst->assign(str_validate(stdstr, SVS_NONE)); } else { dst->assign(str); @@ -591,19 +591,19 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co void IntSettingDesc::ParseValue(const IniItem *item, void *object) const { - size_t val = (item == nullptr) ? (size_t)this->def : this->ParseValue(item->value.has_value() ? item->value->c_str() : ""); + size_t val = (item == nullptr) ? this->def : this->ParseValue(item->value.has_value() ? item->value->c_str() : ""); this->Write_ValidateSetting(object, (int32)val); } void StringSettingDesc::ParseValue(const IniItem *item, void *object) const { - const char *str = (item == nullptr) ? (const char *)this->def : item->value.has_value() ? item->value->c_str() : nullptr; + const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr; this->Write_ValidateSetting(object, str); } void ListSettingDesc::ParseValue(const IniItem *item, void *object) const { - const char *str = (item == nullptr) ? (const char *)this->def : item->value.has_value() ? item->value->c_str() : nullptr; + const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr; void *ptr = GetVariableAddress(object, &this->save); if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); @@ -611,7 +611,7 @@ void ListSettingDesc::ParseValue(const IniItem *item, void *object) const _settings_error_list.push_back(msg); /* Use default */ - LoadIntList((const char*)this->def, ptr, this->save.length, GetVarMemType(this->save.conv)); + LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv)); } } @@ -2053,7 +2053,7 @@ void SetDefaultCompanySettings(CompanyID cid) Company *c = Company::Get(cid); for (auto &sd : _company_settings) { const IntSettingDesc *int_setting = sd->AsIntSetting(); - int_setting->Write_ValidateSetting(&c->settings, (int32)(size_t)int_setting->def); + int_setting->Write_ValidateSetting(&c->settings, int_setting->def); } } @@ -2212,11 +2212,12 @@ void IConsoleGetSetting(const char *name, bool force_newgame) if (sd->cmd == SDT_STDSTRING) { const void *ptr = GetVariableAddress(object, &sd->save); IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, reinterpret_cast(ptr)->c_str()); - } else { + } else if (sd->IsIntSetting()) { char value[20]; sd->FormatValue(value, lastof(value), object); + const IntSettingDesc *int_setting = sd->AsIntSetting(); IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %u)", - name, value, (sd->flags & SGF_0ISDISABLED) ? "(0) " : "", sd->min, sd->max); + name, value, (sd->flags & SGF_0ISDISABLED) ? "(0) " : "", int_setting->min, int_setting->max); } } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index ef1024278f..18beb690a8 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1035,8 +1035,7 @@ void SettingEntry::Init(byte level) /* Sets the given setting entry to its default value */ void SettingEntry::ResetAll() { - int32 default_value = ReadValue(&this->setting->def, this->setting->save.conv); - SetSettingValue(this->setting, default_value); + SetSettingValue(this->setting, this->setting->def); } /** @@ -1092,7 +1091,7 @@ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const /* This entry shall only be visible, if the value deviates from its default value. */ /* Read the default value. */ - filter_value = ReadValue(&sd->def, sd->save.conv); + filter_value = sd->def; } else { assert(mode == RM_CHANGED_AGAINST_NEW); /* This entry shall only be visible, if the value deviates from @@ -2086,8 +2085,7 @@ struct GameSettingsWindow : Window { DrawString(r.left, r.right, y, STR_CONFIG_SETTING_TYPE); y += FONT_HEIGHT_NORMAL; - int32 default_value = ReadValue(&sd->def, sd->save.conv); - this->last_clicked->SetValueDParams(0, default_value); + this->last_clicked->SetValueDParams(0, sd->def); DrawString(r.left, r.right, y, STR_CONFIG_SETTING_DEFAULT_VALUE); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; @@ -2324,7 +2322,7 @@ struct GameSettingsWindow : Window { value = (int32)ClampToI32(llvalue); } else { - value = (int32)(size_t)sd->def; + value = sd->def; } SetSettingValue(this->valuewindow_entry->setting, value); diff --git a/src/settings_internal.h b/src/settings_internal.h index 0914f2803f..be1dfbd936 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -85,27 +85,13 @@ typedef size_t OnConvert(const char *value); ///< callback prototype for convers /** Properties of config file settings. */ struct SettingDesc { - SettingDesc(SaveLoad save, const char *name, const void *def, SettingDescType cmd, SettingGuiFlag flags, - int32 min, uint32 max, int32 interval, const char *many, StringID str, StringID str_help, - StringID str_val, OnChange *proc, OnConvert *proc_cnvt, SettingCategory cat, bool startup) : - name(name), def(def), cmd(cmd), flags(flags), min(min), max(max), interval(interval), many(many), str(str), - str_help(str_help), str_val(str_val), proc(proc), proc_cnvt(proc_cnvt), cat(cat), startup(startup), save(save) {} + SettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup) : + name(name), flags(flags), cmd(cmd), startup(startup), save(save) {} virtual ~SettingDesc() {} const char *name; ///< name of the setting. Used in configuration file and for console - const void *def; ///< default value given when none is present - SettingDescType cmd; ///< various flags for the variable SettingGuiFlag flags; ///< handles how a setting would show up in the GUI (text/currency, etc.) - int32 min; ///< minimum values - uint32 max; ///< maximum values - int32 interval; ///< the interval to use between settings in the 'settings' window. If interval is '0' the interval is dynamically determined - const char *many; ///< ONE/MANY_OF_MANY: string of possible values for this type - StringID str; ///< (translated) string with descriptive text; gui and console - StringID str_help; ///< (Translated) string with help text; gui only. - StringID str_val; ///< (Translated) first string describing the value. - OnChange *proc; ///< callback procedure for when the value is changed - OnConvert *proc_cnvt; ///< callback procedure when loading value mechanism fails - SettingCategory cat; ///< assigned categories of the setting + SettingDescType cmd; ///< various flags for the variable bool startup; ///< setting has to be loaded directly at startup? SaveLoad save; ///< Internal structure (going to savegame, parts to config) @@ -146,12 +132,24 @@ struct SettingDesc { /** Integer type, including boolean, settings. Only these are shown in the settings UI. */ struct IntSettingDesc : SettingDesc { IntSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, int32 def, - int32 min, uint32 max, int32 interval, StringID str, StringID str_help, StringID str_val, - SettingCategory cat, OnChange *proc, const char *many = nullptr, OnConvert *many_cnvt = nullptr) : - SettingDesc(save, name, (void*)(size_t)def, cmd, flags, min, max, interval, many, str, str_help, str_val, - proc, many_cnvt, cat, startup) {} + int32 min, uint32 max, int32 interval, StringID str, StringID str_help, StringID str_val, + SettingCategory cat, OnChange *proc, const char *many = nullptr, OnConvert *many_cnvt = nullptr) : + SettingDesc(save, name, flags, cmd, startup), def(def), min(min), max(max), interval(interval), + str(str), str_help(str_help), str_val(str_val), cat(cat), proc(proc), many(many), many_cnvt(many_cnvt) {} virtual ~IntSettingDesc() {} + int32 def; ///< default value given when none is present + int32 min; ///< minimum values + uint32 max; ///< maximum values + int32 interval; ///< the interval to use between settings in the 'settings' window. If interval is '0' the interval is dynamically determined + StringID str; ///< (translated) string with descriptive text; gui and console + StringID str_help; ///< (Translated) string with help text; gui only. + StringID str_val; ///< (Translated) first string describing the value. + SettingCategory cat; ///< assigned categories of the setting + OnChange *proc; ///< callback procedure for when the value is changed + const char *many; ///< ONE/MANY_OF_MANY: string of possible values for this type + OnConvert *many_cnvt; ///< callback procedure when loading value mechanism fails + void ChangeValue(const void *object, int32 newvalue) const; void Write_ValidateSetting(const void *object, int32 value) const; @@ -165,9 +163,13 @@ struct IntSettingDesc : SettingDesc { struct StringSettingDesc : SettingDesc { StringSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def, uint32 max_length, OnChange proc) : - SettingDesc(save, name, def, cmd, flags, 0, max_length, 0, nullptr, 0, 0, 0, proc, nullptr, SC_NONE, startup) {} + SettingDesc(save, name, flags, cmd, startup), def(def), max_length(max_length), proc(proc) {} virtual ~StringSettingDesc() {} + const char *def; ///< default value given when none is present + uint32 max_length; ///< maximum length of the string, 0 means no maximum length + OnChange *proc; ///< callback procedure for when the value is changed + void ChangeValue(const void *object, const char *newval) const; void Write_ValidateSetting(const void *object, const char *str) const; @@ -180,9 +182,11 @@ struct StringSettingDesc : SettingDesc { /** List/array settings. */ struct ListSettingDesc : SettingDesc { ListSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def) : - SettingDesc(save, name, def, cmd, flags, 0, 0, 0, nullptr, 0, 0, 0, proc, nullptr, SC_NONE, startup) {} + SettingDesc(save, name, flags, cmd, startup), def(def) {} virtual ~ListSettingDesc() {} + const char *def; ///< default value given when none is present + void FormatValue(char *buf, const char *last, const void *object) const override; void ParseValue(const IniItem *item, void *object) const override; bool IsSameValue(const IniItem *item, void *object) const override; @@ -191,7 +195,7 @@ struct ListSettingDesc : SettingDesc { /** Placeholder for settings that have been removed, but might still linger in the savegame. */ struct NullSettingDesc : SettingDesc { NullSettingDesc(SaveLoad save) : - SettingDesc(save, "", nullptr, SDT_NULL, SGF_NONE, 0, 0, 0, nullptr, 0, 0, 0, nullptr, nullptr, SC_NONE, false) {} + SettingDesc(save, "", SGF_NONE, SDT_NULL, false) {} virtual ~NullSettingDesc() {} void FormatValue(char *buf, const char *last, const void *object) const override { NOT_REACHED(); } From 72ec81325b201931525e5c5f79abc6eb1de8d7a8 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 23 May 2021 11:55:22 +0200 Subject: [PATCH 10/14] Cleanup: remove unneeded temporary variables and casts --- src/network/network_gui.cpp | 4 ++-- src/settings.cpp | 39 +++++++++++++++---------------------- src/settings_internal.h | 4 ++-- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index e37843db84..3c61cf77aa 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -2199,7 +2199,7 @@ public: case WID_CL_SERVER_NAME_EDIT: { if (!_network_server) break; - SetSettingValue(GetSettingFromName("network.server_name"), StrEmpty(str) ? "Unnamed Server" : str); + SetSettingValue(GetSettingFromName("network.server_name")->AsStringSetting(), StrEmpty(str) ? "Unnamed Server" : str); this->InvalidateData(); break; } @@ -2208,7 +2208,7 @@ public: std::string client_name(str); if (!NetworkValidateClientName(client_name)) break; - SetSettingValue(GetSettingFromName("network.client_name"), client_name.c_str()); + SetSettingValue(GetSettingFromName("network.client_name")->AsStringSetting(), client_name.c_str()); this->InvalidateData(); break; } diff --git a/src/settings.cpp b/src/settings.cpp index df064499a9..3a71c6d2ec 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -556,14 +556,11 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co IniGroup *group_def = ini->GetGroup(grpname); for (auto &sd : settings_table) { - const SettingDesc *sdb = sd.get(); - const SaveLoad *sld = &sd->save; - - if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; if (sd->startup != only_startup) continue; /* For settings.xx.yy load the settings from [xx] yy = ? */ - std::string s{ sdb->name }; + std::string s{ sd->name }; auto sc = s.find('.'); if (sc != std::string::npos) { group = ini->GetGroup(s.substr(0, sc)); @@ -585,7 +582,7 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co if (sc != std::string::npos) item = ini->GetGroup(s.substr(0, sc))->GetItem(s.substr(sc + 1), false); } - sdb->ParseValue(item, object); + sd->ParseValue(item, object); } } @@ -634,16 +631,13 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co char buf[512]; for (auto &sd : settings_table) { - const SettingDesc *sdb = sd.get(); - const SaveLoad *sld = &sd->save; - /* If the setting is not saved to the configuration * file, just continue with the next setting */ - if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; - if (sld->conv & SLF_NOT_IN_CONFIG) continue; + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + if (sd->save.conv & SLF_NOT_IN_CONFIG) continue; /* XXX - wtf is this?? (group override?) */ - std::string s{ sdb->name }; + std::string s{ sd->name }; auto sc = s.find('.'); if (sc != std::string::npos) { group = ini->GetGroup(s.substr(0, sc)); @@ -655,9 +649,9 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co item = group->GetItem(s, true); - if (!item->value.has_value() || !sdb->IsSameValue(item, object)) { + if (!item->value.has_value() || !sd->IsSameValue(item, object)) { /* Value has changed, get the new value and put it into a buffer */ - sdb->FormatValue(buf, lastof(buf), object); + sd->FormatValue(buf, lastof(buf), object); /* The value is different, that means we have to write it to the ini */ item->value.emplace(buf); @@ -2009,7 +2003,7 @@ static uint GetCompanySettingIndex(const SettingDesc *sd) * @param value new value of the setting * @param force_newgame force the newgame settings */ -bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame) +bool SetSettingValue(const IntSettingDesc *sd, int32 value, bool force_newgame) { const IntSettingDesc *setting = sd->AsIntSetting(); if ((setting->flags & SGF_PER_COMPANY) != 0) { @@ -2090,7 +2084,7 @@ uint GetCompanySettingIndex(const char *name) * @param force_newgame force the newgame settings * @note Strings WILL NOT be synced over the network */ -bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgame) +bool SetSettingValue(const StringSettingDesc *sd, const char *value, bool force_newgame) { assert(sd->save.conv & SLF_NO_NETWORK_SYNC); @@ -2165,7 +2159,7 @@ void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) bool success; if (sd->cmd == SDT_STDSTRING) { - success = SetSettingValue(sd, value, force_newgame); + success = SetSettingValue(sd->AsStringSetting(), value, force_newgame); } else { uint32 val; extern bool GetArgumentInteger(uint32 *value, const char *arg); @@ -2175,7 +2169,7 @@ void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) return; } - success = SetSettingValue(sd, val, force_newgame); + success = SetSettingValue(sd->AsIntSetting(), val, force_newgame); } if (!success) { @@ -2191,7 +2185,7 @@ void IConsoleSetSetting(const char *name, int value) { const SettingDesc *sd = GetSettingFromName(name); assert(sd != nullptr); - SetSettingValue(sd, value); + SetSettingValue(sd->AsIntSetting(), value); } /** @@ -2250,11 +2244,10 @@ void IConsoleListSettings(const char *prefilter) static void LoadSettings(const SettingTable &settings, void *object) { for (auto &osd : settings) { - const SaveLoad *sld = &osd->save; - void *ptr = GetVariableAddress(object, sld); + void *ptr = GetVariableAddress(object, &osd->save); - if (!SlObjectMember(ptr, sld)) continue; - if (osd->IsIntSetting()) osd->AsIntSetting()->Write_ValidateSetting(object, ReadValue(ptr, sld->conv)); + if (!SlObjectMember(ptr, &osd->save)) continue; + if (osd->IsIntSetting()) osd->AsIntSetting()->Write_ValidateSetting(object, ReadValue(ptr, osd->save.conv)); } } diff --git a/src/settings_internal.h b/src/settings_internal.h index be1dfbd936..5e653ec656 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -206,8 +206,8 @@ struct NullSettingDesc : SettingDesc { typedef std::initializer_list> SettingTable; const SettingDesc *GetSettingFromName(const char *name); -bool SetSettingValue(const SettingDesc *sd, int32 value, bool force_newgame = false); -bool SetSettingValue(const SettingDesc *sd, const char *value, bool force_newgame = false); +bool SetSettingValue(const IntSettingDesc *sd, int32 value, bool force_newgame = false); +bool SetSettingValue(const StringSettingDesc *sd, const char *value, bool force_newgame = false); uint GetSettingIndex(const SettingDesc *sd); #endif /* SETTINGS_INTERNAL_H */ From 860003458fc17f02e44b50f98ef570aff824142a Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 23 May 2021 18:20:49 +0200 Subject: [PATCH 11/14] Codechange: make BoolSettingDesc its own sub class --- src/settings.cpp | 30 ++++++++++++++++++------------ src/settings_internal.h | 15 +++++++++++++-- src/table/settings.h.preamble | 4 ++-- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 3a71c6d2ec..f26e566867 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -423,23 +423,24 @@ size_t IntSettingDesc::ParseValue(const char *str) const break; } - case SDT_BOOLX: { - if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true; - if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false; - - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, this->name); - _settings_error_list.push_back(msg); - break; - } - default: NOT_REACHED(); } return this->def; } +size_t BoolSettingDesc::ParseValue(const char *str) const +{ + if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true; + if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false; + + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, this->name); + _settings_error_list.push_back(msg); + return this->def; +} + /** * Set the value of a setting and if needed clamp the value to the preset minimum and maximum. * @param object The object the setting is to be saved in. @@ -663,7 +664,6 @@ void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object { uint32 i = (uint32)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); switch (this->cmd) { - case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", last); break; case SDT_NUMX: seprintf(buf, last, IsSignedVarMemType(this->save.conv) ? "%d" : (this->save.conv & SLF_HEX) ? "%X" : "%u", i); break; case SDT_ONEOFMANY: MakeOneOfMany(buf, last, this->many, i); break; case SDT_MANYOFMANY: MakeManyOfMany(buf, last, this->many, i); break; @@ -671,6 +671,12 @@ void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object } } +void BoolSettingDesc::FormatValue(char *buf, const char *last, const void *object) const +{ + bool val = ReadValue(GetVariableAddress(object, &this->save), this->save.conv) != 0; + strecpy(buf, val ? "true" : "false", last); +} + bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const { int64 item_value = this->ParseValue(item->value->c_str()); diff --git a/src/settings_internal.h b/src/settings_internal.h index 5e653ec656..1174a1f63a 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -129,7 +129,7 @@ struct SettingDesc { virtual bool IsSameValue(const IniItem *item, void *object) const = 0; }; -/** Integer type, including boolean, settings. Only these are shown in the settings UI. */ +/** Base integer type, including boolean, settings. Only these are shown in the settings UI. */ struct IntSettingDesc : SettingDesc { IntSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, int32 def, int32 min, uint32 max, int32 interval, StringID str, StringID str_help, StringID str_val, @@ -153,12 +153,23 @@ struct IntSettingDesc : SettingDesc { void ChangeValue(const void *object, int32 newvalue) const; void Write_ValidateSetting(const void *object, int32 value) const; - size_t ParseValue(const char *str) const; + virtual size_t ParseValue(const char *str) const; void FormatValue(char *buf, const char *last, const void *object) const override; void ParseValue(const IniItem *item, void *object) const override; bool IsSameValue(const IniItem *item, void *object) const override; }; +/** Boolean setting. */ +struct BoolSettingDesc : IntSettingDesc { + BoolSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, bool def, + StringID str, StringID str_help, StringID str_val, SettingCategory cat, OnChange *proc) : + IntSettingDesc(save, name, flags, cmd, startup, def, 0, 1, 0, str, str_help, str_val, cat, proc) {} + virtual ~BoolSettingDesc() {} + + size_t ParseValue(const char *str) const override; + void FormatValue(char *buf, const char *last, const void *object) const override; +}; + /** String settings. */ struct StringSettingDesc : SettingDesc { StringSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def, diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index 6b4dc5e39f..c6788f707e 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -62,7 +62,7 @@ static size_t ConvertLandscape(const char *value); NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_NUMX, startup, def, min, max, interval, str, strhelp, strval, cat, proc) #define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Int, SLEG_GENERAL(SL_VAR, var, SLE_BOOL | flags, 1, from, to, extra), name, guiflags, SDT_BOOLX, startup, def, 0, 1, 0, str, strhelp, strval, cat, proc) + NSD(Bool, SLEG_GENERAL(SL_VAR, var, SLE_BOOL | flags, 1, from, to, extra), name, guiflags, SDT_BOOLX, startup, def, str, strhelp, strval, cat, proc) #define SDTG_LIST(name, type, flags, guiflags, var, def, length, from, to, cat, extra, startup)\ NSD(List, SLEG_GENERAL(SL_ARR, var, type | flags, length, from, to, extra), name, guiflags, SDT_INTLIST, startup, def) @@ -85,7 +85,7 @@ static size_t ConvertLandscape(const char *value); NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_NUMX, startup, def, min, max, interval, str, strhelp, strval, cat, proc) #define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Int, SLE_GENERAL(SL_VAR, base, var, SLE_BOOL | flags, 1, from, to, extra), #var, guiflags, SDT_BOOLX, startup, def, 0, 1, 0, str, strhelp, strval, cat, proc) + NSD(Bool, SLE_GENERAL(SL_VAR, base, var, SLE_BOOL | flags, 1, from, to, extra), #var, guiflags, SDT_BOOLX, startup, def, str, strhelp, strval, cat, proc) #define SDT_LIST(base, var, type, flags, guiflags, def, from, to, cat, extra, startup)\ NSD(List, SLE_GENERAL(SL_ARR, base, var, type | flags, lengthof(((base*)8)->var), from, to, extra), #var, guiflags, SDT_INTLIST, startup, def) From e666a962b1f0f8eeb3bab2232ce77556ddab974a Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 23 May 2021 19:16:56 +0200 Subject: [PATCH 12/14] Codechange: let OneOfMany and ManyOfMany be their own classes as well --- src/settings.cpp | 192 ++++++++++++--------------------- src/settings_internal.h | 41 ++++++- src/table/gameopt_settings.ini | 20 ++-- src/table/misc_settings.ini | 5 +- src/table/settings.h.preamble | 8 +- 5 files changed, 123 insertions(+), 143 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index f26e566867..24950e779e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -127,31 +127,23 @@ static const char * const _list_group_names[] = { /** * Find the index value of a ONEofMANY type in a string separated by | + * @param str the current value of the setting for which a value needs found + * @param len length of the string * @param many full domain of values the ONEofMANY setting can have - * @param one the current value of the setting for which a value needs found - * @param onelen force calculation of the *one parameter * @return the integer index of the full-list, or -1 if not found */ -static size_t LookupOneOfMany(const char *many, const char *one, size_t onelen = 0) +size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const std::vector &many) { - const char *s; - size_t idx; - - if (onelen == 0) onelen = strlen(one); - /* check if it's an integer */ - if (*one >= '0' && *one <= '9') return strtoul(one, nullptr, 0); + if (isdigit(*str)) return strtoul(str, nullptr, 0); - idx = 0; - for (;;) { - /* find end of item */ - s = many; - while (*s != '|' && *s != 0) s++; - if ((size_t)(s - many) == onelen && !memcmp(one, many, onelen)) return idx; - if (*s == 0) return (size_t)-1; - many = s + 1; + size_t idx = 0; + for (auto one : many) { + if (one.size() == len && strncmp(one.c_str(), str, len) == 0) return idx; idx++; } + + return (size_t)-1; } /** @@ -161,7 +153,7 @@ static size_t LookupOneOfMany(const char *many, const char *one, size_t onelen = * of separated by a whitespace,tab or | character * @return the 'fully' set integer, or -1 if a set is not found */ -static size_t LookupManyOfMany(const char *many, const char *str) +static size_t LookupManyOfMany(const std::vector &many, const char *str) { const char *s; size_t r; @@ -175,7 +167,7 @@ static size_t LookupManyOfMany(const char *many, const char *str) s = str; while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++; - r = LookupOneOfMany(many, str, s - str); + r = OneOfManySettingDesc::ParseSingleValue(str, s - str, many); if (r == (size_t)-1) return r; SetBit(res, (uint8)r); // value found, set it @@ -311,66 +303,30 @@ void ListSettingDesc::FormatValue(char *buf, const char *last, const void *objec } } -/** - * Convert a ONEofMANY structure to a string representation. - * @param buf output buffer where the string-representation will be stored - * @param last last item to write to in the output buffer - * @param many the full-domain string of possible values - * @param id the value of the variable and whose string-representation must be found - */ -static void MakeOneOfMany(char *buf, const char *last, const char *many, int id) +char *OneOfManySettingDesc::FormatSingleValue(char *buf, const char *last, uint id) const { - int orig_id = id; - - /* Look for the id'th element */ - while (--id >= 0) { - for (; *many != '|'; many++) { - if (*many == '\0') { // not found - seprintf(buf, last, "%d", orig_id); - return; - } - } - many++; // pass the |-character + if (id >= this->many.size()) { + return buf + seprintf(buf, last, "%d", id); } - - /* copy string until next item (|) or the end of the list if this is the last one */ - while (*many != '\0' && *many != '|' && buf < last) *buf++ = *many++; - *buf = '\0'; + return strecpy(buf, this->many[id].c_str(), last); } -/** - * Convert a MANYofMANY structure to a string representation. - * @param buf output buffer where the string-representation will be stored - * @param last last item to write to in the output buffer - * @param many the full-domain string of possible values - * @param x the value of the variable and whose string-representation must - * be found in the bitmasked many string - */ -static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 x) +void OneOfManySettingDesc::FormatValue(char *buf, const char *last, const void *object) const { - const char *start; - int i = 0; - bool init = true; + uint id = (uint)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + this->FormatSingleValue(buf, last, id); +} - for (; x != 0; x >>= 1, i++) { - start = many; - while (*many != 0 && *many != '|') many++; // advance to the next element - - if (HasBit(x, 0)) { // item found, copy it - if (!init) buf += seprintf(buf, last, "|"); - init = false; - if (start == many) { - buf += seprintf(buf, last, "%d", i); - } else { - memcpy(buf, start, many - start); - buf += many - start; - } - } - - if (*many == '|') many++; +void ManyOfManySettingDesc::FormatValue(char *buf, const char *last, const void *object) const +{ + uint bitmask = (uint)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + uint id = 0; + bool first = true; + FOR_EACH_SET_BIT(id, bitmask) { + if (!first) buf = strecpy(buf, "|", last); + buf = this->FormatSingleValue(buf, last, id); + first = false; } - - *buf = '\0'; } /** @@ -380,52 +336,46 @@ static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 */ size_t IntSettingDesc::ParseValue(const char *str) const { - switch (this->cmd) { - case SDT_NUMX: { - char *end; - size_t val = strtoul(str, &end, 0); - if (end == str) { - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, this->name); - _settings_error_list.push_back(msg); - break; - } - if (*end != '\0') { - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS); - msg.SetDParamStr(0, this->name); - _settings_error_list.push_back(msg); - } - return val; - } - - case SDT_ONEOFMANY: { - size_t r = LookupOneOfMany(this->many, str); - /* if the first attempt of conversion from string to the appropriate value fails, - * look if we have defined a converter from old value to new value. */ - if (r == (size_t)-1 && this->many_cnvt != nullptr) r = this->many_cnvt(str); - if (r != (size_t)-1) return r; // and here goes converted value - - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, this->name); - _settings_error_list.push_back(msg); - break; - } - - case SDT_MANYOFMANY: { - size_t r = LookupManyOfMany(this->many, str); - if (r != (size_t)-1) return r; - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); - msg.SetDParamStr(0, str); - msg.SetDParamStr(1, this->name); - _settings_error_list.push_back(msg); - break; - } - - default: NOT_REACHED(); + char *end; + size_t val = strtoul(str, &end, 0); + if (end == str) { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, this->name); + _settings_error_list.push_back(msg); + return this->def; } + if (*end != '\0') { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS); + msg.SetDParamStr(0, this->name); + _settings_error_list.push_back(msg); + } + return val; +} +size_t OneOfManySettingDesc::ParseValue(const char *str) const +{ + size_t r = OneOfManySettingDesc::ParseSingleValue(str, strlen(str), this->many); + /* if the first attempt of conversion from string to the appropriate value fails, + * look if we have defined a converter from old value to new value. */ + if (r == (size_t)-1 && this->many_cnvt != nullptr) r = this->many_cnvt(str); + if (r != (size_t)-1) return r; // and here goes converted value + + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, this->name); + _settings_error_list.push_back(msg); + return this->def; +} + +size_t ManyOfManySettingDesc::ParseValue(const char *str) const +{ + size_t r = LookupManyOfMany(this->many, str); + if (r != (size_t)-1) return r; + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); + msg.SetDParamStr(0, str); + msg.SetDParamStr(1, this->name); + _settings_error_list.push_back(msg); return this->def; } @@ -663,12 +613,7 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object) const { uint32 i = (uint32)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); - switch (this->cmd) { - case SDT_NUMX: seprintf(buf, last, IsSignedVarMemType(this->save.conv) ? "%d" : (this->save.conv & SLF_HEX) ? "%X" : "%u", i); break; - case SDT_ONEOFMANY: MakeOneOfMany(buf, last, this->many, i); break; - case SDT_MANYOFMANY: MakeManyOfMany(buf, last, this->many, i); break; - default: NOT_REACHED(); - } + seprintf(buf, last, IsSignedVarMemType(this->save.conv) ? "%d" : (this->save.conv & SLF_HEX) ? "%X" : "%u", i); } void BoolSettingDesc::FormatValue(char *buf, const char *last, const void *object) const @@ -1263,7 +1208,8 @@ static bool CheckRoadSide(int p1) static size_t ConvertLandscape(const char *value) { /* try with the old values */ - return LookupOneOfMany("normal|hilly|desert|candy", value); + static std::vector _old_landscape_values{"normal", "hilly", "desert", "candy"}; + return OneOfManySettingDesc::ParseSingleValue(value, strlen(value), _old_landscape_values); } static bool CheckFreeformEdges(int32 p1) diff --git a/src/settings_internal.h b/src/settings_internal.h index 1174a1f63a..488b85441d 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -133,9 +133,9 @@ struct SettingDesc { struct IntSettingDesc : SettingDesc { IntSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, int32 def, int32 min, uint32 max, int32 interval, StringID str, StringID str_help, StringID str_val, - SettingCategory cat, OnChange *proc, const char *many = nullptr, OnConvert *many_cnvt = nullptr) : + SettingCategory cat, OnChange *proc) : SettingDesc(save, name, flags, cmd, startup), def(def), min(min), max(max), interval(interval), - str(str), str_help(str_help), str_val(str_val), cat(cat), proc(proc), many(many), many_cnvt(many_cnvt) {} + str(str), str_help(str_help), str_val(str_val), cat(cat), proc(proc) {} virtual ~IntSettingDesc() {} int32 def; ///< default value given when none is present @@ -147,8 +147,6 @@ struct IntSettingDesc : SettingDesc { StringID str_val; ///< (Translated) first string describing the value. SettingCategory cat; ///< assigned categories of the setting OnChange *proc; ///< callback procedure for when the value is changed - const char *many; ///< ONE/MANY_OF_MANY: string of possible values for this type - OnConvert *many_cnvt; ///< callback procedure when loading value mechanism fails void ChangeValue(const void *object, int32 newvalue) const; void Write_ValidateSetting(const void *object, int32 value) const; @@ -170,6 +168,41 @@ struct BoolSettingDesc : IntSettingDesc { void FormatValue(char *buf, const char *last, const void *object) const override; }; +/** One of many setting. */ +struct OneOfManySettingDesc : IntSettingDesc { + OneOfManySettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, + int32 def, int32 max, StringID str, StringID str_help, StringID str_val, SettingCategory cat, OnChange *proc, + std::initializer_list many, OnConvert *many_cnvt) : + IntSettingDesc(save, name, flags, cmd, startup, def, 0, max, 0, str, str_help, str_val, cat, proc), many_cnvt(many_cnvt) + { + for (auto one : many) this->many.push_back(one); + } + + virtual ~OneOfManySettingDesc() {} + + std::vector many; ///< possible values for this type + OnConvert *many_cnvt; ///< callback procedure when loading value mechanism fails + + static size_t ParseSingleValue(const char *str, size_t len, const std::vector &many); + char *FormatSingleValue(char *buf, const char *last, uint id) const; + + size_t ParseValue(const char *str) const override; + void FormatValue(char *buf, const char *last, const void *object) const override; +}; + +/** Many of many setting. */ +struct ManyOfManySettingDesc : OneOfManySettingDesc { + ManyOfManySettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, + int32 def, StringID str, StringID str_help, StringID str_val, SettingCategory cat, OnChange *proc, + std::initializer_list many, OnConvert *many_cnvt) : + OneOfManySettingDesc(save, name, flags, cmd, startup, def, (1 << many.size()) - 1, str, str_help, + str_val, cat, proc, many, many_cnvt) {} + virtual ~ManyOfManySettingDesc() {} + + size_t ParseValue(const char *str) const override; + void FormatValue(char *buf, const char *last, const void *object) const override; +}; + /** String settings. */ struct StringSettingDesc : SettingDesc { StringSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def, diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index 1e60770f21..56ac7d7816 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -12,16 +12,16 @@ uint8 _old_units; ///< Old units from old s /* Most of these strings are used both for gameopt-backward compatibility * and the settings tables. The rest is here for consistency. */ -static const char *_locale_currencies = "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|RON|RUR|SIT|SEK|YTL|SKK|BRL|EEK|custom"; -static const char *_locale_units = "imperial|metric|si|gameunits"; -static const char *_town_names = "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovak|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan"; -static const char *_climates = "temperate|arctic|tropic|toyland"; -static const char *_autosave_interval = "off|monthly|quarterly|half year|yearly"; -static const char *_roadsides = "left|right"; -static const char *_savegame_date = "long|short|iso"; -static const char *_osk_activation = "disabled|double|single|immediately"; -static const char *_settings_profiles = "easy|medium|hard"; -static const char *_news_display = "off|summarized|full"; +static std::initializer_list _locale_currencies{"GBP", "USD", "EUR", "YEN", "ATS", "BEF", "CHF", "CZK", "DEM", "DKK", "ESP", "FIM", "FRF", "GRD", "HUF", "ISK", "ITL", "NLG", "NOK", "PLN", "RON", "RUR", "SIT", "SEK", "YTL", "SKK", "BRL", "EEK", "custom"}; +static std::initializer_list _locale_units{"imperial", "metric", "si", "gameunits"}; +static std::initializer_list _town_names{"english", "french", "german", "american", "latin", "silly", "swedish", "dutch", "finnish", "polish", "slovak", "norwegian", "hungarian", "austrian", "romanian", "czech", "swiss", "danish", "turkish", "italian", "catalan"}; +static std::initializer_list _climates{"temperate", "arctic", "tropic", "toyland"}; +static std::initializer_list _autosave_interval{"off", "monthly", "quarterly", "half year", "yearly"}; +static std::initializer_list _roadsides{"left", "right"}; +static std::initializer_list _savegame_date{"long", "short", "iso"}; +static std::initializer_list _osk_activation{"disabled", "double", "single", "immediately"}; +static std::initializer_list _settings_profiles{"easy", "medium", "hard"}; +static std::initializer_list _news_display{ "off", "summarized", "full"}; static const SettingTable _gameopt_settings{ /* In version 4 a new difficulty setting has been added to the difficulty settings, diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index a3efbc65e8..017320c863 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -7,7 +7,8 @@ [pre-amble] extern std::string _config_language_file; -static const char *_support8bppmodes = "no|system|hardware"; +static std::initializer_list _support8bppmodes{"no", "system" , "hardware"}; +static std::initializer_list _display_opt_modes{"SHOW_TOWN_NAMES", "SHOW_STATION_NAMES", "SHOW_SIGNS", "FULL_ANIMATION", "", "FULL_DETAIL", "WAYPOINTS", "SHOW_COMPETITOR_SIGNS"}; #ifdef WITH_COCOA extern bool _allow_hidpi_window; @@ -53,7 +54,7 @@ name = ""display_opt"" type = SLE_UINT8 var = _display_opt def = (1 << DO_SHOW_TOWN_NAMES | 1 << DO_SHOW_STATION_NAMES | 1 << DO_SHOW_SIGNS | 1 << DO_FULL_ANIMATION | 1 << DO_FULL_DETAIL | 1 << DO_SHOW_WAYPOINT_NAMES | 1 << DO_SHOW_COMPETITOR_SIGNS) -full = ""SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|FULL_ANIMATION||FULL_DETAIL|WAYPOINTS|SHOW_COMPETITOR_SIGNS"" +full = _display_opt_modes [SDTG_BOOL] name = ""fullscreen"" diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index c6788f707e..df10b6deb6 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -71,10 +71,10 @@ static size_t ConvertLandscape(const char *value); NSD(String, SLEG_GENERAL(SL_STDSTR, var, type | flags, sizeof(var), from, to, extra), name, guiflags, SDT_STDSTRING, startup, def, max_length, proc) #define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_ONEOFMANY, startup, def, 0, max, 0, str, strhelp, strval, cat, proc, full) + NSD(OneOfMany, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_ONEOFMANY, startup, def, max, str, strhelp, strval, cat, proc, full, nullptr) #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_MANYOFMANY, startup, def, 0, 0, 0, str, strhelp, strval, cat, proc, full) + NSD(ManyOfMany, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_MANYOFMANY, startup, def, str, strhelp, strval, cat, proc, full, nullptr) #define SDTG_NULL(length, from, to)\ NSD(Null, SLEG_NULL(length, from, to)) @@ -94,10 +94,10 @@ static size_t ConvertLandscape(const char *value); NSD(String, SLE_GENERAL(SL_STDSTR, base, var, type | flags, sizeof(((base*)8)->var), from, to, extra), #var, guiflags, SDT_STDSTRING, startup, def, 0, proc) #define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat, extra, startup)\ - NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_ONEOFMANY, startup, def, 0, max, 0, str, strhelp, strval, cat, proc, full, load) + NSD(OneOfMany, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_ONEOFMANY, startup, def, max, str, strhelp, strval, cat, proc, full, load) #define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat, extra, startup)\ - NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_MANYOFMANY, startup, def, 0, 0, 0, str, strhelp, strval, cat, proc, full, nullptr) + NSD(ManyOfMany, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_MANYOFMANY, startup, def, str, strhelp, strval, cat, proc, full, nullptr) #define SDT_NULL(length, from, to)\ NSD(Null, SLE_CONDNULL(length, from, to)) From 86c9ef81345901afb015930fa0e3a637acbbc709 Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 23 May 2021 19:27:46 +0200 Subject: [PATCH 13/14] Codechange: remove SettingDescType in lieu of the actual classes --- src/script/api/script_gamesettings.cpp | 5 +- src/settings.cpp | 110 ++++++++++--------------- src/settings_gui.cpp | 87 +++++++++---------- src/settings_internal.h | 71 ++++++++-------- src/table/settings.h.preamble | 24 +++--- 5 files changed, 136 insertions(+), 161 deletions(-) diff --git a/src/script/api/script_gamesettings.cpp b/src/script/api/script_gamesettings.cpp index f96048e153..8b0459367e 100644 --- a/src/script/api/script_gamesettings.cpp +++ b/src/script/api/script_gamesettings.cpp @@ -18,7 +18,7 @@ /* static */ bool ScriptGameSettings::IsValid(const char *setting) { const SettingDesc *sd = GetSettingFromName(setting); - return sd != nullptr && sd->cmd != SDT_STDSTRING; + return sd != nullptr && sd->IsIntSetting(); } /* static */ int32 ScriptGameSettings::GetValue(const char *setting) @@ -28,8 +28,6 @@ const SettingDesc *sd = GetSettingFromName(setting); void *ptr = GetVariableAddress(&_settings_game, &sd->save); - if (sd->cmd == SDT_BOOLX) return *(bool*)ptr; - return (int32)ReadValue(ptr, sd->save.conv); } @@ -40,7 +38,6 @@ const SettingDesc *sd = GetSettingFromName(setting); if ((sd->save.conv & SLF_NO_NETWORK_SYNC) != 0) return false; - if (sd->cmd != SDT_BOOLX && sd->cmd != SDT_NUMX) return false; return ScriptObject::DoCommand(0, GetSettingIndex(sd), value, CMD_CHANGE_SETTING); } diff --git a/src/settings.cpp b/src/settings.cpp index 24950e779e..a86622fa5a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -400,52 +400,49 @@ void IntSettingDesc::Write_ValidateSetting(const void *object, int32 val) const { void *ptr = GetVariableAddress(object, &this->save); - /* We cannot know the maximum value of a bitset variable, so just have faith */ - if (this->cmd != SDT_MANYOFMANY) { - /* We need to take special care of the uint32 type as we receive from the function - * a signed integer. While here also bail out on 64-bit settings as those are not - * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed - * 32-bit variable - * TODO: Support 64-bit settings/variables */ - switch (GetVarMemType(this->save.conv)) { - case SLE_VAR_NULL: return; - case SLE_VAR_BL: - case SLE_VAR_I8: - case SLE_VAR_U8: - case SLE_VAR_I16: - case SLE_VAR_U16: - case SLE_VAR_I32: { - /* Override the minimum value. No value below sdb->min, except special value 0 */ - if (!(this->flags & SGF_0ISDISABLED) || val != 0) { - if (!(this->flags & SGF_MULTISTRING)) { - /* Clamp value-type setting to its valid range */ - val = Clamp(val, this->min, this->max); - } else if (val < this->min || val > (int32)this->max) { - /* Reset invalid discrete setting (where different values change gameplay) to its default value */ - val = this->def; - } + /* We need to take special care of the uint32 type as we receive from the function + * a signed integer. While here also bail out on 64-bit settings as those are not + * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed + * 32-bit variable + * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */ + switch (GetVarMemType(this->save.conv)) { + case SLE_VAR_NULL: return; + case SLE_VAR_BL: + case SLE_VAR_I8: + case SLE_VAR_U8: + case SLE_VAR_I16: + case SLE_VAR_U16: + case SLE_VAR_I32: { + /* Override the minimum value. No value below this->min, except special value 0 */ + if (!(this->flags & SGF_0ISDISABLED) || val != 0) { + if (!(this->flags & SGF_MULTISTRING)) { + /* Clamp value-type setting to its valid range */ + val = Clamp(val, this->min, this->max); + } else if (val < this->min || val > (int32)this->max) { + /* Reset invalid discrete setting (where different values change gameplay) to its default value */ + val = this->def; } - break; } - case SLE_VAR_U32: { - /* Override the minimum value. No value below sdb->min, except special value 0 */ - uint32 uval = (uint32)val; - if (!(this->flags & SGF_0ISDISABLED) || uval != 0) { - if (!(this->flags & SGF_MULTISTRING)) { - /* Clamp value-type setting to its valid range */ - uval = ClampU(uval, this->min, this->max); - } else if (uval < (uint)this->min || uval > this->max) { - /* Reset invalid discrete setting to its default value */ - uval = (uint32)this->def; - } - } - WriteValue(ptr, SLE_VAR_U32, (int64)uval); - return; - } - case SLE_VAR_I64: - case SLE_VAR_U64: - default: NOT_REACHED(); + break; } + case SLE_VAR_U32: { + /* Override the minimum value. No value below this->min, except special value 0 */ + uint32 uval = (uint32)val; + if (!(this->flags & SGF_0ISDISABLED) || uval != 0) { + if (!(this->flags & SGF_MULTISTRING)) { + /* Clamp value-type setting to its valid range */ + uval = ClampU(uval, this->min, this->max); + } else if (uval < (uint)this->min || uval > this->max) { + /* Reset invalid discrete setting to its default value */ + uval = (uint32)this->def; + } + } + WriteValue(ptr, SLE_VAR_U32, (int64)uval); + return; + } + case SLE_VAR_I64: + case SLE_VAR_U64: + default: NOT_REACHED(); } WriteValue(ptr, this->save.conv, (int64)val); @@ -755,22 +752,6 @@ SettingType SettingDesc::GetType() const return (this->save.conv & SLF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME; } -/** - * Check whether this setting is an integer type setting. - * @return True when the underlying type is an integer. - */ -bool SettingDesc::IsIntSetting() const { - return this->cmd == SDT_BOOLX || this->cmd == SDT_NUMX || this->cmd == SDT_ONEOFMANY || this->cmd == SDT_MANYOFMANY; -} - -/** - * Check whether this setting is an string type setting. - * @return True when the underlying type is a string. - */ -bool SettingDesc::IsStringSetting() const { - return this->cmd == SDT_STDSTRING; -} - /** * Get the setting description of this setting as an integer setting. * @return The integer setting description. @@ -2109,10 +2090,10 @@ void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) return; } - bool success; - if (sd->cmd == SDT_STDSTRING) { + bool success = true; + if (sd->IsStringSetting()) { success = SetSettingValue(sd->AsStringSetting(), value, force_newgame); - } else { + } else if (sd->IsIntSetting()) { uint32 val; extern bool GetArgumentInteger(uint32 *value, const char *arg); success = GetArgumentInteger(&val, value); @@ -2155,9 +2136,8 @@ void IConsoleGetSetting(const char *name, bool force_newgame) const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game; - if (sd->cmd == SDT_STDSTRING) { - const void *ptr = GetVariableAddress(object, &sd->save); - IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, reinterpret_cast(ptr)->c_str()); + if (sd->IsStringSetting()) { + IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, sd->AsStringSetting()->Read(object).c_str()); } else if (sd->IsIntSetting()) { char value[20]; sd->FormatValue(value, lastof(value), object); diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 18beb690a8..183b98a1e9 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1167,7 +1167,7 @@ static const void *ResolveVariableAddress(const GameSettings *settings_ptr, cons */ void SettingEntry::SetValueDParams(uint first_param, int32 value) const { - if (this->setting->cmd == SDT_BOOLX) { + if (this->setting->IsBoolSetting()) { SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); } else { if ((this->setting->flags & SGF_MULTISTRING) != 0) { @@ -1207,7 +1207,7 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, SetDParam(0, highlight ? STR_ORANGE_STRING1_WHITE : STR_ORANGE_STRING1_LTBLUE); int32 value = (int32)ReadValue(var, sd->save.conv); - if (sd->cmd == SDT_BOOLX) { + if (sd->IsBoolSetting()) { /* Draw checkbox for boolean-value either on/off */ DrawBoolButton(buttons_left, button_y, value != 0, editable); } else if ((sd->flags & SGF_MULTISTRING) != 0) { @@ -2228,52 +2228,47 @@ struct GameSettingsWindow : Window { this->SetDisplayedHelpText(pe); int32 oldvalue = value; - switch (sd->cmd) { - case SDT_BOOLX: value ^= 1; break; - case SDT_ONEOFMANY: - case SDT_NUMX: { - /* Add a dynamic step-size to the scroller. In a maximum of - * 50-steps you should be able to get from min to max, - * unless specified otherwise in the 'interval' variable - * of the current setting. */ - uint32 step = (sd->interval == 0) ? ((sd->max - sd->min) / 50) : sd->interval; - if (step == 0) step = 1; + if (sd->IsBoolSetting()) { + value ^= 1; + } else { + /* Add a dynamic step-size to the scroller. In a maximum of + * 50-steps you should be able to get from min to max, + * unless specified otherwise in the 'interval' variable + * of the current setting. */ + uint32 step = (sd->interval == 0) ? ((sd->max - sd->min) / 50) : sd->interval; + if (step == 0) step = 1; - /* don't allow too fast scrolling */ - if ((this->flags & WF_TIMEOUT) && this->timeout_timer > 1) { - _left_button_clicked = false; - return; - } - - /* Increase or decrease the value and clamp it to extremes */ - if (x >= SETTING_BUTTON_WIDTH / 2) { - value += step; - if (sd->min < 0) { - assert((int32)sd->max >= 0); - if (value > (int32)sd->max) value = (int32)sd->max; - } else { - if ((uint32)value > sd->max) value = (int32)sd->max; - } - if (value < sd->min) value = sd->min; // skip between "disabled" and minimum - } else { - value -= step; - if (value < sd->min) value = (sd->flags & SGF_0ISDISABLED) ? 0 : sd->min; - } - - /* Set up scroller timeout for numeric values */ - if (value != oldvalue) { - if (this->clicked_entry != nullptr) { // Release previous buttons if any - this->clicked_entry->SetButtons(0); - } - this->clicked_entry = pe; - this->clicked_entry->SetButtons((x >= SETTING_BUTTON_WIDTH / 2) != (_current_text_dir == TD_RTL) ? SEF_RIGHT_DEPRESSED : SEF_LEFT_DEPRESSED); - this->SetTimeout(); - _left_button_clicked = false; - } - break; + /* don't allow too fast scrolling */ + if ((this->flags & WF_TIMEOUT) && this->timeout_timer > 1) { + _left_button_clicked = false; + return; } - default: NOT_REACHED(); + /* Increase or decrease the value and clamp it to extremes */ + if (x >= SETTING_BUTTON_WIDTH / 2) { + value += step; + if (sd->min < 0) { + assert((int32)sd->max >= 0); + if (value > (int32)sd->max) value = (int32)sd->max; + } else { + if ((uint32)value > sd->max) value = (int32)sd->max; + } + if (value < sd->min) value = sd->min; // skip between "disabled" and minimum + } else { + value -= step; + if (value < sd->min) value = (sd->flags & SGF_0ISDISABLED) ? 0 : sd->min; + } + + /* Set up scroller timeout for numeric values */ + if (value != oldvalue) { + if (this->clicked_entry != nullptr) { // Release previous buttons if any + this->clicked_entry->SetButtons(0); + } + this->clicked_entry = pe; + this->clicked_entry->SetButtons((x >= SETTING_BUTTON_WIDTH / 2) != (_current_text_dir == TD_RTL) ? SEF_RIGHT_DEPRESSED : SEF_LEFT_DEPRESSED); + this->SetTimeout(); + _left_button_clicked = false; + } } if (value != oldvalue) { @@ -2282,7 +2277,7 @@ struct GameSettingsWindow : Window { } } else { /* Only open editbox if clicked for the second time, and only for types where it is sensible for. */ - if (this->last_clicked == pe && sd->cmd != SDT_BOOLX && !(sd->flags & SGF_MULTISTRING)) { + if (this->last_clicked == pe && !sd->IsBoolSetting() && !(sd->flags & SGF_MULTISTRING)) { int64 value64 = value; /* Show the correct currency-translated value */ if (sd->flags & SGF_CURRENCY) value64 *= _currency->rate; diff --git a/src/settings_internal.h b/src/settings_internal.h index 488b85441d..0f6d0c3ade 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -12,22 +12,6 @@ #include "saveload/saveload.h" -/** - * Convention/Type of settings. This is then further specified if necessary - * with the SLE_ (SLE_VAR/SLE_FILE) enums in saveload.h - * @see VarTypes - * @see SettingDesc - */ -enum SettingDescType : byte { - SDT_NUMX = 0, ///< any number-type - SDT_BOOLX = 1, ///< a boolean number - SDT_ONEOFMANY = 2, ///< bitmasked number where only ONE bit may be set - SDT_MANYOFMANY = 3, ///< bitmasked number where MULTIPLE bits may be set - SDT_INTLIST = 4, ///< list of integers separated by a comma ',' - SDT_STDSTRING = 6, ///< \c std::string - SDT_NULL = 7, ///< an old setting that has been removed but could still be in savegames -}; - enum SettingGuiFlag : uint16 { /* 2 bytes allocated for a maximum of 16 flags. */ SGF_NONE = 0, @@ -85,20 +69,30 @@ typedef size_t OnConvert(const char *value); ///< callback prototype for convers /** Properties of config file settings. */ struct SettingDesc { - SettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup) : - name(name), flags(flags), cmd(cmd), startup(startup), save(save) {} + SettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, bool startup) : + name(name), flags(flags), startup(startup), save(save) {} virtual ~SettingDesc() {} const char *name; ///< name of the setting. Used in configuration file and for console SettingGuiFlag flags; ///< handles how a setting would show up in the GUI (text/currency, etc.) - SettingDescType cmd; ///< various flags for the variable bool startup; ///< setting has to be loaded directly at startup? SaveLoad save; ///< Internal structure (going to savegame, parts to config) bool IsEditable(bool do_command = false) const; SettingType GetType() const; - bool IsIntSetting() const; - bool IsStringSetting() const; + + /** + * Check whether this setting is an integer type setting. + * @return True when the underlying type is an integer. + */ + virtual bool IsIntSetting() const { return false; } + + /** + * Check whether this setting is an string type setting. + * @return True when the underlying type is a string. + */ + virtual bool IsStringSetting() const { return false; } + const struct IntSettingDesc *AsIntSetting() const; const struct StringSettingDesc *AsStringSetting() const; @@ -131,10 +125,10 @@ struct SettingDesc { /** Base integer type, including boolean, settings. Only these are shown in the settings UI. */ struct IntSettingDesc : SettingDesc { - IntSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, int32 def, + IntSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, bool startup, int32 def, int32 min, uint32 max, int32 interval, StringID str, StringID str_help, StringID str_val, SettingCategory cat, OnChange *proc) : - SettingDesc(save, name, flags, cmd, startup), def(def), min(min), max(max), interval(interval), + SettingDesc(save, name, flags, startup), def(def), min(min), max(max), interval(interval), str(str), str_help(str_help), str_val(str_val), cat(cat), proc(proc) {} virtual ~IntSettingDesc() {} @@ -148,6 +142,13 @@ struct IntSettingDesc : SettingDesc { SettingCategory cat; ///< assigned categories of the setting OnChange *proc; ///< callback procedure for when the value is changed + /** + * Check whether this setting is a boolean type setting. + * @return True when the underlying type is an integer. + */ + virtual bool IsBoolSetting() const { return false; } + bool IsIntSetting() const override { return true; } + void ChangeValue(const void *object, int32 newvalue) const; void Write_ValidateSetting(const void *object, int32 value) const; @@ -159,21 +160,22 @@ struct IntSettingDesc : SettingDesc { /** Boolean setting. */ struct BoolSettingDesc : IntSettingDesc { - BoolSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, bool def, + BoolSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, bool startup, bool def, StringID str, StringID str_help, StringID str_val, SettingCategory cat, OnChange *proc) : - IntSettingDesc(save, name, flags, cmd, startup, def, 0, 1, 0, str, str_help, str_val, cat, proc) {} + IntSettingDesc(save, name, flags, startup, def, 0, 1, 0, str, str_help, str_val, cat, proc) {} virtual ~BoolSettingDesc() {} + bool IsBoolSetting() const override { return true; } size_t ParseValue(const char *str) const override; void FormatValue(char *buf, const char *last, const void *object) const override; }; /** One of many setting. */ struct OneOfManySettingDesc : IntSettingDesc { - OneOfManySettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, + OneOfManySettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, bool startup, int32 def, int32 max, StringID str, StringID str_help, StringID str_val, SettingCategory cat, OnChange *proc, std::initializer_list many, OnConvert *many_cnvt) : - IntSettingDesc(save, name, flags, cmd, startup, def, 0, max, 0, str, str_help, str_val, cat, proc), many_cnvt(many_cnvt) + IntSettingDesc(save, name, flags, startup, def, 0, max, 0, str, str_help, str_val, cat, proc), many_cnvt(many_cnvt) { for (auto one : many) this->many.push_back(one); } @@ -192,10 +194,10 @@ struct OneOfManySettingDesc : IntSettingDesc { /** Many of many setting. */ struct ManyOfManySettingDesc : OneOfManySettingDesc { - ManyOfManySettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, + ManyOfManySettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, bool startup, int32 def, StringID str, StringID str_help, StringID str_val, SettingCategory cat, OnChange *proc, std::initializer_list many, OnConvert *many_cnvt) : - OneOfManySettingDesc(save, name, flags, cmd, startup, def, (1 << many.size()) - 1, str, str_help, + OneOfManySettingDesc(save, name, flags, startup, def, (1 << many.size()) - 1, str, str_help, str_val, cat, proc, many, many_cnvt) {} virtual ~ManyOfManySettingDesc() {} @@ -205,15 +207,16 @@ struct ManyOfManySettingDesc : OneOfManySettingDesc { /** String settings. */ struct StringSettingDesc : SettingDesc { - StringSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def, + StringSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, bool startup, const char *def, uint32 max_length, OnChange proc) : - SettingDesc(save, name, flags, cmd, startup), def(def), max_length(max_length), proc(proc) {} + SettingDesc(save, name, flags, startup), def(def), max_length(max_length), proc(proc) {} virtual ~StringSettingDesc() {} const char *def; ///< default value given when none is present uint32 max_length; ///< maximum length of the string, 0 means no maximum length OnChange *proc; ///< callback procedure for when the value is changed + bool IsStringSetting() const override { return true; } void ChangeValue(const void *object, const char *newval) const; void Write_ValidateSetting(const void *object, const char *str) const; @@ -225,8 +228,8 @@ struct StringSettingDesc : SettingDesc { /** List/array settings. */ struct ListSettingDesc : SettingDesc { - ListSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, SettingDescType cmd, bool startup, const char *def) : - SettingDesc(save, name, flags, cmd, startup), def(def) {} + ListSettingDesc(SaveLoad save, const char *name, SettingGuiFlag flags, bool startup, const char *def) : + SettingDesc(save, name, flags, startup), def(def) {} virtual ~ListSettingDesc() {} const char *def; ///< default value given when none is present @@ -239,7 +242,7 @@ struct ListSettingDesc : SettingDesc { /** Placeholder for settings that have been removed, but might still linger in the savegame. */ struct NullSettingDesc : SettingDesc { NullSettingDesc(SaveLoad save) : - SettingDesc(save, "", SGF_NONE, SDT_NULL, false) {} + SettingDesc(save, "", SGF_NONE, false) {} virtual ~NullSettingDesc() {} void FormatValue(char *buf, const char *last, const void *object) const override { NOT_REACHED(); } diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index df10b6deb6..7f9ac2dd59 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -59,22 +59,22 @@ static size_t ConvertLandscape(const char *value); /* Macros for various objects to go in the configuration file. * This section is for global variables */ #define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_NUMX, startup, def, min, max, interval, str, strhelp, strval, cat, proc) + NSD(Int, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, startup, def, min, max, interval, str, strhelp, strval, cat, proc) #define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Bool, SLEG_GENERAL(SL_VAR, var, SLE_BOOL | flags, 1, from, to, extra), name, guiflags, SDT_BOOLX, startup, def, str, strhelp, strval, cat, proc) + NSD(Bool, SLEG_GENERAL(SL_VAR, var, SLE_BOOL | flags, 1, from, to, extra), name, guiflags, startup, def, str, strhelp, strval, cat, proc) #define SDTG_LIST(name, type, flags, guiflags, var, def, length, from, to, cat, extra, startup)\ - NSD(List, SLEG_GENERAL(SL_ARR, var, type | flags, length, from, to, extra), name, guiflags, SDT_INTLIST, startup, def) + NSD(List, SLEG_GENERAL(SL_ARR, var, type | flags, length, from, to, extra), name, guiflags, startup, def) #define SDTG_SSTR(name, type, flags, guiflags, var, def, max_length, proc, from, to, cat, extra, startup)\ - NSD(String, SLEG_GENERAL(SL_STDSTR, var, type | flags, sizeof(var), from, to, extra), name, guiflags, SDT_STDSTRING, startup, def, max_length, proc) + NSD(String, SLEG_GENERAL(SL_STDSTR, var, type | flags, sizeof(var), from, to, extra), name, guiflags, startup, def, max_length, proc) #define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(OneOfMany, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_ONEOFMANY, startup, def, max, str, strhelp, strval, cat, proc, full, nullptr) + NSD(OneOfMany, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, startup, def, max, str, strhelp, strval, cat, proc, full, nullptr) #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(ManyOfMany, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, SDT_MANYOFMANY, startup, def, str, strhelp, strval, cat, proc, full, nullptr) + NSD(ManyOfMany, SLEG_GENERAL(SL_VAR, var, type | flags, 1, from, to, extra), name, guiflags, startup, def, str, strhelp, strval, cat, proc, full, nullptr) #define SDTG_NULL(length, from, to)\ NSD(Null, SLEG_NULL(length, from, to)) @@ -82,22 +82,22 @@ static size_t ConvertLandscape(const char *value); /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ #define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_NUMX, startup, def, min, max, interval, str, strhelp, strval, cat, proc) + NSD(Int, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, startup, def, min, max, interval, str, strhelp, strval, cat, proc) #define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - NSD(Bool, SLE_GENERAL(SL_VAR, base, var, SLE_BOOL | flags, 1, from, to, extra), #var, guiflags, SDT_BOOLX, startup, def, str, strhelp, strval, cat, proc) + NSD(Bool, SLE_GENERAL(SL_VAR, base, var, SLE_BOOL | flags, 1, from, to, extra), #var, guiflags, startup, def, str, strhelp, strval, cat, proc) #define SDT_LIST(base, var, type, flags, guiflags, def, from, to, cat, extra, startup)\ - NSD(List, SLE_GENERAL(SL_ARR, base, var, type | flags, lengthof(((base*)8)->var), from, to, extra), #var, guiflags, SDT_INTLIST, startup, def) + NSD(List, SLE_GENERAL(SL_ARR, base, var, type | flags, lengthof(((base*)8)->var), from, to, extra), #var, guiflags, startup, def) #define SDT_SSTR(base, var, type, flags, guiflags, def, proc, from, to, cat, extra, startup)\ - NSD(String, SLE_GENERAL(SL_STDSTR, base, var, type | flags, sizeof(((base*)8)->var), from, to, extra), #var, guiflags, SDT_STDSTRING, startup, def, 0, proc) + NSD(String, SLE_GENERAL(SL_STDSTR, base, var, type | flags, sizeof(((base*)8)->var), from, to, extra), #var, guiflags, startup, def, 0, proc) #define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat, extra, startup)\ - NSD(OneOfMany, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_ONEOFMANY, startup, def, max, str, strhelp, strval, cat, proc, full, load) + NSD(OneOfMany, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, startup, def, max, str, strhelp, strval, cat, proc, full, load) #define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat, extra, startup)\ - NSD(ManyOfMany, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, SDT_MANYOFMANY, startup, def, str, strhelp, strval, cat, proc, full, nullptr) + NSD(ManyOfMany, SLE_GENERAL(SL_VAR, base, var, type | flags, 1, from, to, extra), #var, guiflags, startup, def, str, strhelp, strval, cat, proc, full, nullptr) #define SDT_NULL(length, from, to)\ NSD(Null, SLE_CONDNULL(length, from, to)) From 8372c679e3c16f776ecd0847b60c940ac066ed4c Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Mon, 24 May 2021 10:42:02 +0200 Subject: [PATCH 14/14] Codechange: add helper functions to read an int setting value --- src/settings.cpp | 44 ++++++++++++++++++++++++++--------------- src/settings_gui.cpp | 29 +++++++++++---------------- src/settings_internal.h | 1 + 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index a86622fa5a..af06d3befc 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -313,13 +313,13 @@ char *OneOfManySettingDesc::FormatSingleValue(char *buf, const char *last, uint void OneOfManySettingDesc::FormatValue(char *buf, const char *last, const void *object) const { - uint id = (uint)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + uint id = (uint)this->Read(object); this->FormatSingleValue(buf, last, id); } void ManyOfManySettingDesc::FormatValue(char *buf, const char *last, const void *object) const { - uint bitmask = (uint)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + uint bitmask = (uint)this->Read(object); uint id = 0; bool first = true; FOR_EACH_SET_BIT(id, bitmask) { @@ -448,6 +448,17 @@ void IntSettingDesc::Write_ValidateSetting(const void *object, int32 val) const WriteValue(ptr, this->save.conv, (int64)val); } +/** + * Read the integer from the the actual setting. + * @param object The object the setting is to be saved in. + * @return The value of the saved integer. + */ +int32 IntSettingDesc::Read(const void *object) const +{ + void *ptr = GetVariableAddress(object, &this->save); + return (int32)ReadValue(ptr, this->save.conv); +} + /** * Set the string value of a setting. * @param object The object the setting is to be saved in. @@ -609,20 +620,20 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object) const { - uint32 i = (uint32)ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + uint32 i = (uint32)this->Read(object); seprintf(buf, last, IsSignedVarMemType(this->save.conv) ? "%d" : (this->save.conv & SLF_HEX) ? "%X" : "%u", i); } void BoolSettingDesc::FormatValue(char *buf, const char *last, const void *object) const { - bool val = ReadValue(GetVariableAddress(object, &this->save), this->save.conv) != 0; + bool val = this->Read(object) != 0; strecpy(buf, val ? "true" : "false", last); } bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const { - int64 item_value = this->ParseValue(item->value->c_str()); - int64 object_value = ReadValue(GetVariableAddress(object, &this->save), this->save.conv); + int32 item_value = (int32)this->ParseValue(item->value->c_str()); + int32 object_value = this->Read(object); return item_value == object_value; } @@ -1814,18 +1825,16 @@ void DeleteGRFPresetFromConfig(const char *config_name) */ void IntSettingDesc::ChangeValue(const void *object, int32 newval) const { - void *var = GetVariableAddress(object, &this->save); - - int32 oldval = (int32)ReadValue(var, this->save.conv); + int32 oldval = this->Read(object); this->Write_ValidateSetting(object, newval); - newval = (int32)ReadValue(var, this->save.conv); + newval = this->Read(object); if (oldval == newval) return; if (this->proc != nullptr && !this->proc(newval)) { /* The change was not allowed, so revert. */ - WriteValue(var, this->save.conv, (int64)oldval); + WriteValue(GetVariableAddress(object, &this->save), this->save.conv, (int64)oldval); return; } @@ -1989,12 +1998,12 @@ void SetDefaultCompanySettings(CompanyID cid) */ void SyncCompanySettings() { + const void *old_object = &Company::Get(_current_company)->settings; + const void *new_object = &_settings_client.company; uint i = 0; for (auto &sd : _company_settings) { - const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); - const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save); - uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv); - uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv); + uint32 old_value = (uint32)sd->AsIntSetting()->Read(new_object); + uint32 new_value = (uint32)sd->AsIntSetting()->Read(old_object); if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, nullptr, nullptr, _local_company); i++; } @@ -2179,7 +2188,10 @@ static void LoadSettings(const SettingTable &settings, void *object) void *ptr = GetVariableAddress(object, &osd->save); if (!SlObjectMember(ptr, &osd->save)) continue; - if (osd->IsIntSetting()) osd->AsIntSetting()->Write_ValidateSetting(object, ReadValue(ptr, osd->save.conv)); + if (osd->IsIntSetting()) { + const IntSettingDesc *int_setting = osd->AsIntSetting(); + int_setting->Write_ValidateSetting(object, int_setting->Read(object)); + } } } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 183b98a1e9..559c395875 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -74,7 +74,7 @@ static const StringID _font_zoom_dropdown[] = { static Dimension _circle_size; ///< Dimension of the circle +/- icon. This is here as not all users are within the class of the settings window. -static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const IntSettingDesc *sd); +static const void *ResolveObject(const GameSettings *settings_ptr, const IntSettingDesc *sd); /** * Get index of the current screen resolution. @@ -1075,16 +1075,14 @@ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const /* There shall not be any restriction, i.e. all settings shall be visible. */ if (mode == RM_ALL) return true; - GameSettings *settings_ptr = &GetGameSettings(); const IntSettingDesc *sd = this->setting; if (mode == RM_BASIC) return (this->setting->cat & SC_BASIC_LIST) != 0; if (mode == RM_ADVANCED) return (this->setting->cat & SC_ADVANCED_LIST) != 0; /* Read the current value. */ - const void *var = ResolveVariableAddress(settings_ptr, sd); - int64 current_value = ReadValue(var, sd->save.conv); - + const void *object = ResolveObject(&GetGameSettings(), sd); + int64 current_value = sd->Read(object); int64 filter_value; if (mode == RM_CHANGED_AGAINST_DEFAULT) { @@ -1098,11 +1096,10 @@ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const * its value is used when starting a new game. */ /* Make sure we're not comparing the new game settings against itself. */ - assert(settings_ptr != &_settings_newgame); + assert(&GetGameSettings() != &_settings_newgame); /* Read the new game's value. */ - var = ResolveVariableAddress(&_settings_newgame, sd); - filter_value = ReadValue(var, sd->save.conv); + filter_value = sd->Read(ResolveObject(&_settings_newgame, sd)); } return current_value != filter_value; @@ -1147,17 +1144,15 @@ bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) return visible; } -static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const IntSettingDesc *sd) +static const void *ResolveObject(const GameSettings *settings_ptr, const IntSettingDesc *sd) { if ((sd->flags & SGF_PER_COMPANY) != 0) { if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { - return GetVariableAddress(&Company::Get(_local_company)->settings, &sd->save); - } else { - return GetVariableAddress(&_settings_client.company, &sd->save); + return &Company::Get(_local_company)->settings; } - } else { - return GetVariableAddress(settings_ptr, &sd->save); + return &_settings_client.company; } + return settings_ptr; } /** @@ -1193,7 +1188,6 @@ void SettingEntry::SetValueDParams(uint first_param, int32 value) const void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const { const IntSettingDesc *sd = this->setting; - const void *var = ResolveVariableAddress(settings_ptr, sd); int state = this->flags & SEF_BUTTONS_MASK; bool rtl = _current_text_dir == TD_RTL; @@ -1206,7 +1200,7 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, bool editable = sd->IsEditable(); SetDParam(0, highlight ? STR_ORANGE_STRING1_WHITE : STR_ORANGE_STRING1_LTBLUE); - int32 value = (int32)ReadValue(var, sd->save.conv); + int32 value = sd->Read(ResolveObject(settings_ptr, sd)); if (sd->IsBoolSetting()) { /* Draw checkbox for boolean-value either on/off */ DrawBoolButton(buttons_left, button_y, value != 0, editable); @@ -2184,8 +2178,7 @@ struct GameSettingsWindow : Window { return; } - const void *var = ResolveVariableAddress(settings_ptr, sd); - int32 value = (int32)ReadValue(var, sd->save.conv); + int32 value = sd->Read(ResolveObject(settings_ptr, sd)); /* clicked on the icon on the left side. Either scroller, bool on/off or dropdown */ if (x < SETTING_BUTTON_WIDTH && (sd->flags & SGF_MULTISTRING)) { diff --git a/src/settings_internal.h b/src/settings_internal.h index 0f6d0c3ade..e7dd6e9149 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -156,6 +156,7 @@ struct IntSettingDesc : SettingDesc { void FormatValue(char *buf, const char *last, const void *object) const override; void ParseValue(const IniItem *item, void *object) const override; bool IsSameValue(const IniItem *item, void *object) const override; + int32 Read(const void *object) const; }; /** Boolean setting. */