From 97df27e41f85a9f0d1d422f19ad31b5396a506f8 Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 2 Oct 2023 13:29:32 +0200 Subject: [PATCH 01/57] Codechange: Store base graphics settings in a separate section in openttd.cfg. --- src/base_media_base.h | 16 +++++++++---- src/base_media_func.h | 1 - src/openttd.cpp | 23 +++++++++++------- src/settings.cpp | 36 ++++++++++++++++++++++++++++ src/settings_gui.cpp | 34 ++++++++++---------------- src/table/settings/misc_settings.ini | 7 ------ 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/base_media_base.h b/src/base_media_base.h index 2bd8b58265..79266177a5 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -170,9 +170,6 @@ protected: */ static const char *GetExtension(); public: - /** The set as saved in the config file. */ - static std::string ini_set; - /** * Determine the graphics pack that has to be used. * The one with the most correct files wins. @@ -207,7 +204,6 @@ public: static bool HasSet(const ContentInfo *ci, bool md5sum); }; -template /* static */ std::string BaseMedia::ini_set; template /* static */ const Tbase_set *BaseMedia::used_set; template /* static */ Tbase_set *BaseMedia::available_sets; template /* static */ Tbase_set *BaseMedia::duplicate_sets; @@ -252,6 +248,12 @@ struct GraphicsSet : BaseSet { /** All data/functions related with replacing the base graphics. */ class BaseGraphics : public BaseMedia { public: + /** Values loaded from config file. */ + struct Ini { + std::string name; + }; + static inline Ini ini_data; + }; /** All data of a sounds set. */ @@ -261,6 +263,9 @@ struct SoundsSet : BaseSet { /** All data/functions related with replacing the base sounds */ class BaseSounds : public BaseMedia { public: + /** The set as saved in the config file. */ + static inline std::string ini_set; + }; /** Maximum number of songs in the 'class' playlists. */ @@ -307,6 +312,9 @@ struct MusicSet : BaseSet { /** All data/functions related with replacing the base music */ class BaseMusic : public BaseMedia { public: + /** The set as saved in the config file. */ + static inline std::string ini_set; + }; #endif /* BASE_MEDIA_BASE_H */ diff --git a/src/base_media_func.h b/src/base_media_func.h index 56af002cba..0403a65f29 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -373,7 +373,6 @@ template * @param set_type the type of the BaseSet to instantiate */ #define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \ - template std::string repl_type::ini_set; \ template const char *repl_type::GetExtension(); \ template bool repl_type::AddFile(const std::string &filename, size_t pathlength, const std::string &tar_filename); \ template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ diff --git a/src/openttd.cpp b/src/openttd.cpp index b1808316c5..d906e98efc 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -700,15 +700,22 @@ int openttd_main(int argc, char *argv[]) InitWindowSystem(); BaseGraphics::FindSets(); - if (graphics_set.empty() && !BaseGraphics::ini_set.empty()) graphics_set = BaseGraphics::ini_set; - if (!BaseGraphics::SetSet(graphics_set)) { - if (!graphics_set.empty()) { - BaseGraphics::SetSet({}); + bool valid_graphics_set; + if (!graphics_set.empty()) { + valid_graphics_set = BaseGraphics::SetSet(graphics_set); + } else if (!BaseGraphics::ini_data.name.empty()) { + graphics_set = BaseGraphics::ini_data.name; + valid_graphics_set = BaseGraphics::SetSet(BaseGraphics::ini_data.name); + } else { + valid_graphics_set = true; + BaseGraphics::SetSet(nullptr); // ignore error, continue to bootstrap GUI + } + if (!valid_graphics_set) { + BaseGraphics::SetSet(nullptr); - ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); - msg.SetDParamStr(0, graphics_set); - ScheduleErrorMessage(msg); - } + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); + msg.SetDParamStr(0, graphics_set); + ScheduleErrorMessage(msg); } /* Initialize game palette */ diff --git a/src/settings.cpp b/src/settings.cpp index a9d79b53f4..0dec3a5288 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -42,6 +42,7 @@ #include "ai/ai_config.hpp" #include "game/game_config.hpp" #include "newgrf_config.h" +#include "base_media_base.h" #include "fios.h" #include "fileio_func.h" #include "settings_cmd.h" @@ -981,6 +982,22 @@ static bool DecodeHexText(const char *pos, uint8_t *dest, size_t dest_size) return *pos == '|'; } +/** + * Load BaseGraphics set selection and configuration. + */ +static void GraphicsSetLoadConfig(IniFile &ini) +{ + if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) { + /* Load old setting first. */ + if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value; + } + + if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) { + /* Load new settings. */ + if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value; + } +} + /** * Load a GRF configuration * @param ini The configuration to read from. @@ -1153,6 +1170,20 @@ static void SaveVersionInConfig(IniFile &ini) group.GetOrCreateItem("ini_version").SetValue(std::to_string(INIFILE_VERSION)); } +/** + * Save BaseGraphics set selection and configuration. + */ +static void GraphicsSetSaveConfig(IniFile &ini) +{ + const GraphicsSet *used_set = BaseGraphics::GetUsedSet(); + if (used_set == nullptr) return; + + IniGroup &group = ini.GetOrCreateGroup("graphicsset"); + group.Clear(); + + group.GetOrCreateItem("name").SetValue(used_set->name); +} + /* Save a GRF configuration to the given group name */ static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfig *list) { @@ -1285,6 +1316,10 @@ void LoadFromConfig(bool startup) IniFileVersion generic_version = LoadVersionFromConfig(generic_ini); + if (startup) { + GraphicsSetLoadConfig(generic_ini); + } + /* Before the split of private/secrets, we have to look in the generic for these settings. */ if (generic_version < IFV_PRIVATE_SECRETS) { HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup); @@ -1416,6 +1451,7 @@ void SaveToConfig() } HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList); + GraphicsSetSaveConfig(generic_ini); GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame); GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static); AISaveConfig(generic_ini, "ai_players"); diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 847d75ac47..f79d9eeace 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -649,25 +649,6 @@ struct GameOptionsWindow : Window { } } - /** - * Set the base media set. - * @param index the index of the media set - * @tparam T class of media set - */ - template - void SetMediaSet(int index) - { - if (_game_mode == GM_MENU) { - auto name = T::GetSet(index)->name; - - T::ini_set = name; - - T::SetSet(name); - this->reload = true; - this->InvalidateData(); - } - } - void OnDropdownSelect(int widget, int index) override { switch (widget) { @@ -710,11 +691,22 @@ struct GameOptionsWindow : Window { } case WID_GO_BASE_GRF_DROPDOWN: - this->SetMediaSet(index); + if (_game_mode == GM_MENU) { + auto* set = BaseGraphics::GetSet(index); + BaseGraphics::SetSet(set->name); + this->reload = true; + this->InvalidateData(); + } break; case WID_GO_BASE_SFX_DROPDOWN: - this->SetMediaSet(index); + if (_game_mode == GM_MENU) { + auto* set = BaseSounds::GetSet(index); + BaseSounds::ini_set = set->name; + BaseSounds::SetSet(set->name); + this->reload = true; + this->InvalidateData(); + } break; case WID_GO_BASE_MUSIC_DROPDOWN: diff --git a/src/table/settings/misc_settings.ini b/src/table/settings/misc_settings.ini index dd3a58e24e..7e9db80c83 100644 --- a/src/table/settings/misc_settings.ini +++ b/src/table/settings/misc_settings.ini @@ -94,13 +94,6 @@ max = 2 full = _support8bppmodes cat = SC_BASIC -[SDTG_SSTR] -name = ""graphicsset"" -type = SLE_STRQ -var = BaseGraphics::ini_set -def = nullptr -cat = SC_BASIC - [SDTG_SSTR] name = ""soundsset"" type = SLE_STRQ From 0b7ecf6102df51bad70339fe23f5755d5d2224c0 Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 2 Oct 2023 14:17:32 +0200 Subject: [PATCH 02/57] Codechange: use the shortname as unique id to identify the base graphics in openttd.cfg. --- src/base_media_base.h | 5 ++++- src/base_media_func.h | 51 ++++++++++++++++++++++++++++++++++++------- src/music_gui.cpp | 2 +- src/openttd.cpp | 11 ++++++---- src/settings.cpp | 5 +++++ src/settings_gui.cpp | 4 ++-- 6 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/base_media_base.h b/src/base_media_base.h index 79266177a5..3ecc4125e1 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -188,7 +188,9 @@ public: static Tbase_set *GetAvailableSets(); - static bool SetSet(const std::string &name); + static bool SetSet(const Tbase_set *set); + static bool SetSetByName(const std::string &name); + static bool SetSetByShortname(uint32_t shortname); static void GetSetsList(std::back_insert_iterator &output_iterator); static int GetNumSets(); static int GetIndexOfUsedSet(); @@ -251,6 +253,7 @@ public: /** Values loaded from config file. */ struct Ini { std::string name; + uint32_t shortname; ///< unique key for base set }; static inline Ini ini_data; diff --git a/src/base_media_func.h b/src/base_media_func.h index 0403a65f29..28ad0e305f 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -226,25 +226,58 @@ bool BaseMedia::AddFile(const std::string &filename, size_t basepath_ return ret; } +/** + * Set the set to be used. + * @param set the set to use + * @return true if it could be loaded + */ +template +/* static */ bool BaseMedia::SetSet(const Tbase_set *set) +{ + if (set == nullptr) { + if (!BaseMedia::DetermineBestSet()) return false; + } else { + BaseMedia::used_set = set; + } + CheckExternalFiles(); + return true; +} + /** * Set the set to be used. * @param name of the set to use * @return true if it could be loaded */ template -/* static */ bool BaseMedia::SetSet(const std::string &name) +/* static */ bool BaseMedia::SetSetByName(const std::string &name) { if (name.empty()) { - if (!BaseMedia::DetermineBestSet()) return false; - CheckExternalFiles(); - return true; + return SetSet(nullptr); } for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { if (name == s->name) { - BaseMedia::used_set = s; - CheckExternalFiles(); - return true; + return SetSet(s); + } + } + return false; +} + +/** + * Set the set to be used. + * @param shortname of the set to use + * @return true if it could be loaded + */ +template +/* static */ bool BaseMedia::SetSetByShortname(uint32_t shortname) +{ + if (shortname == 0) { + return SetSet(nullptr); + } + + for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { + if (shortname == s->shortname) { + return SetSet(s); } } return false; @@ -376,7 +409,9 @@ template template const char *repl_type::GetExtension(); \ template bool repl_type::AddFile(const std::string &filename, size_t pathlength, const std::string &tar_filename); \ template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ - template bool repl_type::SetSet(const std::string &name); \ + template bool repl_type::SetSet(const set_type *set); \ + template bool repl_type::SetSetByName(const std::string &name); \ + template bool repl_type::SetSetByShortname(uint32_t shortname); \ template void repl_type::GetSetsList(std::back_insert_iterator &output_iterator); \ template int repl_type::GetNumSets(); \ template int repl_type::GetIndexOfUsedSet(); \ diff --git a/src/music_gui.cpp b/src/music_gui.cpp index 2a2f1e2832..188cfbc4f7 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -173,7 +173,7 @@ void MusicSystem::ChangePlaylist(PlaylistChoices pl) */ void MusicSystem::ChangeMusicSet(const std::string &set_name) { - BaseMusic::SetSet(set_name); + BaseMusic::SetSetByName(set_name); BaseMusic::ini_set = set_name; this->BuildPlaylists(); diff --git a/src/openttd.cpp b/src/openttd.cpp index d906e98efc..1856743724 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -702,10 +702,13 @@ int openttd_main(int argc, char *argv[]) BaseGraphics::FindSets(); bool valid_graphics_set; if (!graphics_set.empty()) { - valid_graphics_set = BaseGraphics::SetSet(graphics_set); + valid_graphics_set = BaseGraphics::SetSetByName(graphics_set); + } else if (BaseGraphics::ini_data.shortname != 0) { + graphics_set = BaseGraphics::ini_data.name; + valid_graphics_set = BaseGraphics::SetSetByShortname(BaseGraphics::ini_data.shortname); } else if (!BaseGraphics::ini_data.name.empty()) { graphics_set = BaseGraphics::ini_data.name; - valid_graphics_set = BaseGraphics::SetSet(BaseGraphics::ini_data.name); + valid_graphics_set = BaseGraphics::SetSetByName(BaseGraphics::ini_data.name); } else { valid_graphics_set = true; BaseGraphics::SetSet(nullptr); // ignore error, continue to bootstrap GUI @@ -769,7 +772,7 @@ int openttd_main(int argc, char *argv[]) BaseSounds::FindSets(); if (sounds_set.empty() && !BaseSounds::ini_set.empty()) sounds_set = BaseSounds::ini_set; - if (!BaseSounds::SetSet(sounds_set)) { + if (!BaseSounds::SetSetByName(sounds_set)) { if (sounds_set.empty() || !BaseSounds::SetSet({})) { UserError("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 1.4 of README.md."); } else { @@ -781,7 +784,7 @@ int openttd_main(int argc, char *argv[]) BaseMusic::FindSets(); if (music_set.empty() && !BaseMusic::ini_set.empty()) music_set = BaseMusic::ini_set; - if (!BaseMusic::SetSet(music_set)) { + if (!BaseMusic::SetSetByName(music_set)) { if (music_set.empty() || !BaseMusic::SetSet({})) { UserError("Failed to find a music set. Please acquire a music set for OpenTTD. See section 1.4 of README.md."); } else { diff --git a/src/settings.cpp b/src/settings.cpp index 0dec3a5288..e072d8b7bd 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -995,6 +995,10 @@ static void GraphicsSetLoadConfig(IniFile &ini) if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) { /* Load new settings. */ if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value; + + if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) { + BaseGraphics::ini_data.shortname = BSWAP32(std::strtoul(item->value->c_str(), nullptr, 16)); + } } } @@ -1182,6 +1186,7 @@ static void GraphicsSetSaveConfig(IniFile &ini) group.Clear(); group.GetOrCreateItem("name").SetValue(used_set->name); + group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", BSWAP32(used_set->shortname))); } /* Save a GRF configuration to the given group name */ diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index f79d9eeace..1749a6633c 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -693,7 +693,7 @@ struct GameOptionsWindow : Window { case WID_GO_BASE_GRF_DROPDOWN: if (_game_mode == GM_MENU) { auto* set = BaseGraphics::GetSet(index); - BaseGraphics::SetSet(set->name); + BaseGraphics::SetSet(set); this->reload = true; this->InvalidateData(); } @@ -703,7 +703,7 @@ struct GameOptionsWindow : Window { if (_game_mode == GM_MENU) { auto* set = BaseSounds::GetSet(index); BaseSounds::ini_set = set->name; - BaseSounds::SetSet(set->name); + BaseSounds::SetSet(set); this->reload = true; this->InvalidateData(); } From f09fda1ff0b91d3a0007a65033c5891ac349120c Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 2 Oct 2023 14:28:16 +0200 Subject: [PATCH 03/57] Codechange: store the GRFConfig of the base graphics, once loaded. --- src/base_media_base.h | 10 +++++++++ src/gfxinit.cpp | 47 ++++++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/base_media_base.h b/src/base_media_base.h index 3ecc4125e1..9cd36ef336 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -237,12 +237,22 @@ enum BlitterType { BLT_32BPP, ///< Base set has both 8 bpp and 32 bpp sprites. }; +struct GRFConfig; + /** All data of a graphics set. */ struct GraphicsSet : BaseSet { +private: + mutable std::unique_ptr extra_cfg; ///< Parameters for extra GRF +public: PaletteType palette; ///< Palette of this graphics set BlitterType blitter; ///< Blitter of this graphics set + GraphicsSet(); + ~GraphicsSet(); + bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename); + GRFConfig *GetExtraConfig() const { return this->extra_cfg.get(); } + GRFConfig &GetOrCreateExtraConfig() const; static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir); }; diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 2f8ac4702c..b2fb5fd70a 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -192,18 +192,7 @@ static void LoadSpriteTables() ClrBit(master->flags, GCF_INIT_ONLY); /* Baseset extra graphics */ - GRFConfig *extra = new GRFConfig(used_set->files[GFT_EXTRA].filename.c_str()); - - /* We know the palette of the base set, so if the base NewGRF is not - * setting one, use the palette of the base set and not the global - * one which might be the wrong palette for this base NewGRF. - * The value set here might be overridden via action14 later. */ - switch (used_set->palette) { - case PAL_DOS: extra->palette |= GRFP_GRF_DOS; break; - case PAL_WINDOWS: extra->palette |= GRFP_GRF_WINDOWS; break; - default: break; - } - FillGRFDetails(extra, false, BASESET_DIR); + GRFConfig *extra = new GRFConfig(used_set->GetOrCreateExtraConfig()); ClrBit(extra->flags, GCF_INIT_ONLY); extra->next = top; @@ -347,6 +336,17 @@ void GfxLoadSprites() UpdateCursorSize(); } +GraphicsSet::GraphicsSet() + : BaseSet{}, palette{}, blitter{} +{ + // instantiate here, because unique_ptr needs a complete type +} + +GraphicsSet::~GraphicsSet() +{ + // instantiate here, because unique_ptr needs a complete type +} + bool GraphicsSet::FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename) { bool ret = this->BaseSet::FillSetDetails(ini, path, full_filename, false); @@ -365,6 +365,29 @@ bool GraphicsSet::FillSetDetails(const IniFile &ini, const std::string &path, co return ret; } +/** + * Return configuration for the extra GRF, or lazily create it. + * @return NewGRF configuration + */ +GRFConfig &GraphicsSet::GetOrCreateExtraConfig() const +{ + if (!this->extra_cfg) { + this->extra_cfg.reset(new GRFConfig(this->files[GFT_EXTRA].filename)); + + /* We know the palette of the base set, so if the base NewGRF is not + * setting one, use the palette of the base set and not the global + * one which might be the wrong palette for this base NewGRF. + * The value set here might be overridden via action14 later. */ + switch (this->palette) { + case PAL_DOS: this->extra_cfg->palette |= GRFP_GRF_DOS; break; + case PAL_WINDOWS: this->extra_cfg->palette |= GRFP_GRF_WINDOWS; break; + default: break; + } + FillGRFDetails(this->extra_cfg.get(), false, BASESET_DIR); + } + return *this->extra_cfg; +} + /** * Calculate and check the MD5 hash of the supplied GRF. * @param file The file get the hash of. From de3f29d7b23ef9447ee4c59f34fcf44f8cdc4601 Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 2 Oct 2023 14:37:43 +0200 Subject: [PATCH 04/57] Add: store base graphics parameters in openttd.cfg. --- src/base_media_base.h | 4 ++++ src/base_media_func.h | 3 +++ src/gfxinit.cpp | 10 ++++++++++ src/newgrf_config.cpp | 6 ++++++ src/newgrf_config.h | 1 + src/openttd.cpp | 6 ++++++ src/settings.cpp | 20 ++++++++++++++++++++ 7 files changed, 50 insertions(+) diff --git a/src/base_media_base.h b/src/base_media_base.h index 9cd36ef336..f85c9c40f8 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -96,6 +96,7 @@ struct BaseSet { } bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename, bool allow_empty_filename = true); + void CopyCompatibleConfig([[maybe_unused]] const T &src) {} /** * Get the description for the given ISO code. @@ -253,6 +254,7 @@ public: bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename); GRFConfig *GetExtraConfig() const { return this->extra_cfg.get(); } GRFConfig &GetOrCreateExtraConfig() const; + void CopyCompatibleConfig(const GraphicsSet &src); static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir); }; @@ -264,6 +266,8 @@ public: struct Ini { std::string name; uint32_t shortname; ///< unique key for base set + uint32_t extra_version; ///< version of the extra GRF + std::vector extra_params; ///< parameters for the extra GRF }; static inline Ini ini_data; diff --git a/src/base_media_func.h b/src/base_media_func.h index 28ad0e305f..2d30528df5 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -198,6 +198,9 @@ bool BaseMedia::AddFile(const std::string &filename, size_t basepath_ *prev = set; set->next = duplicate->next; + /* Keep baseset configuration, if compatible */ + set->CopyCompatibleConfig(*duplicate); + /* If the duplicate set is currently used (due to rescanning this can happen) * update the currently used set to the new one. This will 'lie' about the * version number until a new game is started which isn't a big problem */ diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index b2fb5fd70a..aa4d1c66fc 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -193,6 +193,7 @@ static void LoadSpriteTables() /* Baseset extra graphics */ GRFConfig *extra = new GRFConfig(used_set->GetOrCreateExtraConfig()); + if (extra->num_params == 0) extra->SetParameterDefaults(); ClrBit(extra->flags, GCF_INIT_ONLY); extra->next = top; @@ -388,6 +389,15 @@ GRFConfig &GraphicsSet::GetOrCreateExtraConfig() const return *this->extra_cfg; } +void GraphicsSet::CopyCompatibleConfig(const GraphicsSet &src) +{ + const GRFConfig *src_cfg = src.GetExtraConfig(); + if (src_cfg == nullptr || src_cfg->num_params == 0) return; + GRFConfig &dest_cfg = this->GetOrCreateExtraConfig(); + if (dest_cfg.IsCompatible(src_cfg->version)) return; + dest_cfg.CopyParams(*src_cfg); +} + /** * Calculate and check the MD5 hash of the supplied GRF. * @param file The file get the hash of. diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index c45498ee2b..f3cec8b5a5 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -66,6 +66,12 @@ GRFConfig::GRFConfig(const GRFConfig &config) : { } +void GRFConfig::SetParams(const std::vector &pars) +{ + this->num_params = static_cast(std::min(this->param.size(), pars.size())); + std::copy(pars.begin(), pars.begin() + this->num_params, this->param.begin()); +} + /** * Return whether this NewGRF can replace an older version of the same NewGRF. */ diff --git a/src/newgrf_config.h b/src/newgrf_config.h index 3620501b19..8596eab563 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -174,6 +174,7 @@ struct GRFConfig : ZeroedMemoryAllocator { struct GRFConfig *next; ///< NOSAVE: Next item in the linked list bool IsCompatible(uint32_t old_version) const; + void SetParams(const std::vector &pars); void CopyParams(const GRFConfig &src); std::optional GetTextfile(TextfileType type) const; diff --git a/src/openttd.cpp b/src/openttd.cpp index 1856743724..611d21f1e3 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -706,6 +706,12 @@ int openttd_main(int argc, char *argv[]) } else if (BaseGraphics::ini_data.shortname != 0) { graphics_set = BaseGraphics::ini_data.name; valid_graphics_set = BaseGraphics::SetSetByShortname(BaseGraphics::ini_data.shortname); + if (valid_graphics_set && !BaseGraphics::ini_data.extra_params.empty()) { + GRFConfig &extra_cfg = BaseGraphics::GetUsedSet()->GetOrCreateExtraConfig(); + if (extra_cfg.IsCompatible(BaseGraphics::ini_data.extra_version)) { + extra_cfg.SetParams(BaseGraphics::ini_data.extra_params); + } + } } else if (!BaseGraphics::ini_data.name.empty()) { graphics_set = BaseGraphics::ini_data.name; valid_graphics_set = BaseGraphics::SetSetByName(BaseGraphics::ini_data.name); diff --git a/src/settings.cpp b/src/settings.cpp index e072d8b7bd..d86c153828 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -999,6 +999,20 @@ static void GraphicsSetLoadConfig(IniFile &ini) if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) { BaseGraphics::ini_data.shortname = BSWAP32(std::strtoul(item->value->c_str(), nullptr, 16)); } + + if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) BaseGraphics::ini_data.extra_version = std::strtoul(item->value->c_str(), nullptr, 10); + + if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) { + auto &extra_params = BaseGraphics::ini_data.extra_params; + extra_params.resize(lengthof(GRFConfig::param)); + int count = ParseIntList(item->value->c_str(), &extra_params.front(), extra_params.size()); + if (count < 0) { + SetDParamStr(0, BaseGraphics::ini_data.name); + ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); + count = 0; + } + extra_params.resize(count); + } } } @@ -1187,6 +1201,12 @@ static void GraphicsSetSaveConfig(IniFile &ini) group.GetOrCreateItem("name").SetValue(used_set->name); group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", BSWAP32(used_set->shortname))); + + const GRFConfig *extra_cfg = used_set->GetExtraConfig(); + if (extra_cfg != nullptr && extra_cfg->num_params > 0) { + group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version)); + group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(extra_cfg)); + } } /* Save a GRF configuration to the given group name */ From e81313e93e61b5f5f847c61add5c6e0a7e2cc978 Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 2 Oct 2023 14:43:10 +0200 Subject: [PATCH 05/57] Feature: Base graphics can offer parameters for additional settings. --- src/base_media_base.h | 1 + src/gfxinit.cpp | 8 ++++++++ src/lang/english.txt | 1 + src/newgrf_config.h | 1 + src/newgrf_gui.cpp | 11 ++++++----- src/settings_gui.cpp | 15 +++++++++++++++ src/widgets/newgrf_widget.h | 1 + src/widgets/settings_widget.h | 1 + 8 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/base_media_base.h b/src/base_media_base.h index f85c9c40f8..0875996103 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -254,6 +254,7 @@ public: bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename); GRFConfig *GetExtraConfig() const { return this->extra_cfg.get(); } GRFConfig &GetOrCreateExtraConfig() const; + bool IsConfigurable() const; void CopyCompatibleConfig(const GraphicsSet &src); static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir); diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index aa4d1c66fc..943c5bb102 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -389,6 +389,14 @@ GRFConfig &GraphicsSet::GetOrCreateExtraConfig() const return *this->extra_cfg; } +bool GraphicsSet::IsConfigurable() const +{ + const GRFConfig &cfg = this->GetOrCreateExtraConfig(); + /* This check is more strict than the one for NewGRF Settings. + * There are no legacy basesets with parameters, but without Action14 */ + return !cfg.param_info.empty(); +} + void GraphicsSet::CopyCompatibleConfig(const GraphicsSet &src) { const GRFConfig *src_cfg = src.GetExtraConfig(); diff --git a/src/lang/english.txt b/src/lang/english.txt index 69e4f3c989..1ff9eaf612 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3384,6 +3384,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Save STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Save the preset to the current selected name # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Change base graphics parameters STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Change NewGRF parameters STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Close STR_NEWGRF_PARAMETERS_RESET :{BLACK}Reset diff --git a/src/newgrf_config.h b/src/newgrf_config.h index 8596eab563..c9f6d51d71 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -226,6 +226,7 @@ std::string GRFBuildParamList(const GRFConfig *c); /* In newgrf_gui.cpp */ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config); +void OpenGRFParameterWindow(bool is_baseset, GRFConfig *c, bool editable); void UpdateNewGRFScanStatus(uint num, const char *name); void UpdateNewGRFConfigPalette(int32_t new_value = 0); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index f9e8e100d8..036914cfe1 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -155,7 +155,7 @@ struct NewGRFParametersWindow : public Window { bool action14present; ///< True if action14 information is present. bool editable; ///< Allow editing parameters. - NewGRFParametersWindow(WindowDesc *desc, GRFConfig *c, bool editable) : Window(desc), + NewGRFParametersWindow(WindowDesc *desc, bool is_baseset, GRFConfig *c, bool editable) : Window(desc), grf_config(c), clicked_button(UINT_MAX), clicked_dropdown(false), @@ -166,6 +166,7 @@ struct NewGRFParametersWindow : public Window { this->action14present = (c->num_valid_params != c->param.size() || !c->param_info.empty()); this->CreateNestedTree(); + this->GetWidget(WID_NP_CAPTION)->SetDataTip(is_baseset ? STR_BASEGRF_PARAMETERS_CAPTION : STR_NEWGRF_PARAMETERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); this->vscroll = this->GetScrollbar(WID_NP_SCROLLBAR); this->GetWidget(WID_NP_SHOW_NUMPAR)->SetDisplayedPlane(this->action14present ? SZSP_HORIZONTAL : 0); this->GetWidget(WID_NP_SHOW_DESCRIPTION)->SetDisplayedPlane(this->action14present ? 0 : SZSP_HORIZONTAL); @@ -509,7 +510,7 @@ GRFParameterInfo NewGRFParametersWindow::dummy_parameter_info(0); static const NWidgetPart _nested_newgrf_parameter_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), - NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_PARAMETERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_NP_CAPTION), NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_NUMPAR), @@ -546,10 +547,10 @@ static WindowDesc _newgrf_parameters_desc( std::begin(_nested_newgrf_parameter_widgets), std::end(_nested_newgrf_parameter_widgets) ); -static void OpenGRFParameterWindow(GRFConfig *c, bool editable) +void OpenGRFParameterWindow(bool is_baseset, GRFConfig *c, bool editable) { CloseWindowByClass(WC_GRF_PARAMETERS); - new NewGRFParametersWindow(&_newgrf_parameters_desc, c, editable); + new NewGRFParametersWindow(&_newgrf_parameters_desc, is_baseset, c, editable); } /** Window for displaying the textfile of a NewGRF. */ @@ -1133,7 +1134,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_SET_PARAMETERS: { // Edit parameters if (this->active_sel == nullptr || !this->show_params || this->active_sel->num_valid_params == 0) break; - OpenGRFParameterWindow(this->active_sel, this->editable); + OpenGRFParameterWindow(false, this->active_sel, this->editable); this->InvalidateData(GOID_NEWGRF_CHANGES_MADE); break; } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 1749a6633c..dc56f92812 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -41,6 +41,7 @@ #include "music/music_driver.hpp" #include "gui.h" #include "mixer.h" +#include "newgrf_config.h" #include "network/core/config.h" #include "network/network_gui.h" #include "network/network_survey.h" @@ -601,6 +602,16 @@ struct GameOptionsWindow : Window { break; } + case WID_GO_BASE_GRF_PARAMETERS: { + auto *used_set = BaseGraphics::GetUsedSet(); + if (used_set == nullptr || !used_set->IsConfigurable()) break; + GRFConfig &extra_cfg = used_set->GetOrCreateExtraConfig(); + if (extra_cfg.num_params == 0) extra_cfg.SetParameterDefaults(); + OpenGRFParameterWindow(true, &extra_cfg, _game_mode == GM_MENU); + if (_game_mode == GM_MENU) this->reload = true; + break; + } + case WID_GO_BASE_SFX_VOLUME: case WID_GO_BASE_MUSIC_VOLUME: { byte &vol = (widget == WID_GO_BASE_MUSIC_VOLUME) ? _settings_client.music.music_vol : _settings_client.music.effect_vol; @@ -692,6 +703,7 @@ struct GameOptionsWindow : Window { case WID_GO_BASE_GRF_DROPDOWN: if (_game_mode == GM_MENU) { + CloseWindowByClass(WC_GRF_PARAMETERS); auto* set = BaseGraphics::GetSet(index); BaseGraphics::SetSet(set); this->reload = true; @@ -742,6 +754,8 @@ struct GameOptionsWindow : Window { bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); + this->SetWidgetDisabledState(WID_GO_BASE_GRF_PARAMETERS, BaseGraphics::GetUsedSet() == nullptr || !BaseGraphics::GetUsedSet()->IsConfigurable()); + for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) { this->SetWidgetDisabledState(WID_GO_BASE_GRF_TEXTFILE + tft, BaseGraphics::GetUsedSet() == nullptr || !BaseGraphics::GetUsedSet()->GetTextfile(tft).has_value()); this->SetWidgetDisabledState(WID_GO_BASE_SFX_TEXTFILE + tft, BaseSounds::GetUsedSet() == nullptr || !BaseSounds::GetUsedSet()->GetTextfile(tft).has_value()); @@ -853,6 +867,7 @@ static const NWidgetPart _nested_game_options_widgets[] = { NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_JUST_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(100, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_PARAMETERS), SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL), EndContainer(), NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(200, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), diff --git a/src/widgets/newgrf_widget.h b/src/widgets/newgrf_widget.h index 2d39665447..da4e4d584d 100644 --- a/src/widgets/newgrf_widget.h +++ b/src/widgets/newgrf_widget.h @@ -15,6 +15,7 @@ /** Widgets of the #NewGRFParametersWindow class. */ enum NewGRFParametersWidgets { + WID_NP_CAPTION, ///< Caption of the window. WID_NP_SHOW_NUMPAR, ///< #NWID_SELECTION to optionally display #WID_NP_NUMPAR. WID_NP_NUMPAR_DEC, ///< Button to decrease number of parameters. WID_NP_NUMPAR_INC, ///< Button to increase number of parameters. diff --git a/src/widgets/settings_widget.h b/src/widgets/settings_widget.h index f358e6ccda..58541546d5 100644 --- a/src/widgets/settings_widget.h +++ b/src/widgets/settings_widget.h @@ -26,6 +26,7 @@ enum GameOptionsWidgets { WID_GO_GUI_SCALE_AUTO, ///< Autodetect GUI scale button. WID_GO_GUI_SCALE_BEVEL_BUTTON, ///< Toggle for chunky bevels. WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. + WID_GO_BASE_GRF_PARAMETERS, ///< Base GRF parameters. WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). WID_GO_BASE_GRF_DESCRIPTION = WID_GO_BASE_GRF_TEXTFILE + TFT_CONTENT_END, ///< Description of selected base GRF. From 35a7770fde294df2d52a1b9e2c23a7ec9bc22102 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 01:19:04 +0000 Subject: [PATCH 06/57] Fix 233aac5: Set newline default comment for new groups. (#11411) The newline space between ini groups is actually recorded as a comment of the group. This got inadvertantly dropped in #11364. --- src/ini_load.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ini_load.cpp b/src/ini_load.cpp index c3a8d8103c..cc7d681467 100644 --- a/src/ini_load.cpp +++ b/src/ini_load.cpp @@ -39,7 +39,7 @@ void IniItem::SetValue(const std::string_view value) * @param parent the file we belong to * @param name the name of the group */ -IniGroup::IniGroup(const std::string &name, IniGroupType type) : type(type) +IniGroup::IniGroup(const std::string &name, IniGroupType type) : type(type), comment("\n") { this->name = StrMakeValid(name); } From c97120f003fd5c5cd909ef0f02aa27f2da693c92 Mon Sep 17 00:00:00 2001 From: translators Date: Wed, 1 Nov 2023 18:38:53 +0000 Subject: [PATCH 07/57] Update: Translations from eints english (au): 1 change by krysclarke chinese (simplified): 5 changes by WenSimEHRP korean: 2 changes by telk5093 russian: 1 change by Ln-Wolf portuguese: 1 change by azulcosta portuguese (brazilian): 1 change by pasantoro polish: 1 change by pAter-exe --- src/lang/brazilian_portuguese.txt | 1 + src/lang/english_AU.txt | 1 + src/lang/korean.txt | 2 ++ src/lang/polish.txt | 1 + src/lang/portuguese.txt | 1 + src/lang/russian.txt | 1 + src/lang/simplified_chinese.txt | 5 +++++ 7 files changed, 12 insertions(+) diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index ed8c6bbba2..d65902b572 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -3385,6 +3385,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Salvar STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Salva o padrão com o nome selecionado # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Alterar parâmetros dos gráficos base STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Alterar parâmetros NewGRF STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Fechar STR_NEWGRF_PARAMETERS_RESET :{BLACK}Redefinir parâmetros diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index 27e2cd00ec..eb1e3b6991 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -3384,6 +3384,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Save STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Save the preset to the current selected name # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Change base graphics parameters STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Change NewGRF parameters STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Close STR_NEWGRF_PARAMETERS_RESET :{BLACK}Reset diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 368451cdb5..cfa679c383 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -534,6 +534,7 @@ STR_ABOUT_MENU_ABOUT_OPENTTD :'OpenTTD'에 STR_ABOUT_MENU_SPRITE_ALIGNER :스프라이트 정렬 도구 STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :박스 경계선 보기 전환 STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :시각적 업데이트 블록 표시 전환 +STR_ABOUT_MENU_TOGGLE_WIDGET_OUTLINES :위젯 경계선 켜기/끄기 # Place in highscore window ###length 15 @@ -3384,6 +3385,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}저장 STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}이 프리셋을 선택한 이름으로 저장합니다 # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}기본 그래픽 매개 변수를 변경합니다 STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}NewGRF 매개 변숫값 변경 STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}닫기 STR_NEWGRF_PARAMETERS_RESET :{BLACK}초기화 diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 223416a0a5..1b5d60ed86 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -3764,6 +3764,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Zapisz STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Zapisz schemat z wybraną nazwą # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Zmień parametry grafik podstawowych STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Zmień parametry NewGRF STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Zamknij STR_NEWGRF_PARAMETERS_RESET :{BLACK}Resetuj diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index ee3a92f01b..7682b7bcac 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -3385,6 +3385,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Grava STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Grava a predefinição com o nome seleccionado # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Alterar os parâmetros dos gráficos base STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Alterar parâmetros de NewGRF STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Fechar STR_NEWGRF_PARAMETERS_RESET :{BLACK}Repor diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 3f4100355a..8b9389ca34 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -3559,6 +3559,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Сохр STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Сохранить набор под выбранным именем # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Изменение параметров графического пакета STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Изменить параметры NewGRF STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Закрыть STR_NEWGRF_PARAMETERS_RESET :{BLACK}Сброс diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index 821e910479..c0fb39f00d 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -533,6 +533,7 @@ STR_ABOUT_MENU_ABOUT_OPENTTD :关于 'OpenTTD STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite 对齐 STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :切换边界框 STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :切换脏方块的颜色 +STR_ABOUT_MENU_TOGGLE_WIDGET_OUTLINES :调节小组件边框 # Place in highscore window ###length 15 @@ -924,6 +925,8 @@ STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}新 {STR STR_NEWS_SHOW_VEHICLE_GROUP_TOOLTIP :{BLACK}打开该运输工具所属的组 +STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_LIST :{WHITE}{STATION}不再接受:{CARGO_LIST} +STR_NEWS_STATION_NOW_ACCEPTS_CARGO_LIST :{WHITE}{STATION}现在接受:{CARGO_LIST} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}财政补贴项目到期:{}{}将 {STRING} 从 {STRING} 运送到 {STRING} 将不再获得财政补贴。 STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}财政补贴项目流标:{}{}将 {STRING} 从 {STRING} 运送到 {STRING} 将不是财政补贴项目。 @@ -2192,6 +2195,7 @@ STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}修改 STR_CHEAT_CHANGE_DATE :{LTBLUE}改变日期:{ORANGE}{DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}改变当前年份 STR_CHEAT_SETUP_PROD :{LTBLUE}开启可调整产量模式:{ORANGE}{STRING} +STR_CHEAT_STATION_RATING :{LTBLUE}车站评价固定为100%:{ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}{COMPANY} 的色彩方案 @@ -3380,6 +3384,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}保存 STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}以当前选定的名称保存预设值 # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}改变基本图形组参数 STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}调整 NewGRF 参数 STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}关闭 STR_NEWGRF_PARAMETERS_RESET :{BLACK}重置 From bb50cbb7728ccdd0641399777033e1e9d4eca61a Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 1 Nov 2023 18:44:23 +0000 Subject: [PATCH 08/57] Codechange: Assign/StoreSizePosition x/y can be negative. (#11416) AssignSizePosition is used with negative values when an NWidgetMatrix is scrolled, but they were passed as unsigned and then stored as signed. Widget pos_x/pos_y were already made signed. --- src/network/network_gui.cpp | 2 +- src/newgrf_gui.cpp | 2 +- src/smallmap_gui.cpp | 2 +- src/toolbar_gui.cpp | 2 +- src/widget.cpp | 16 ++++++++-------- src/widget_type.h | 20 ++++++++++---------- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 97ee785cb9..4d9d6b464a 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -129,7 +129,7 @@ public: this->smallest_x = this->head->smallest_x + this->tail->smallest_x; // First and last are always shown, rest not } - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 036914cfe1..04929fb2b8 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1667,7 +1667,7 @@ public: this->smallest_y = ComputeMaxSize(min_acs_height, this->smallest_y + this->resize_y - 1, this->resize_y); } - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override { this->StoreSizePosition(sizing, x, y, given_width, given_height); diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 7ff1c62dfe..09f73b6d32 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1740,7 +1740,7 @@ public: this->resize_y = std::min(display->resize_y, bar->resize_y); } - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override { this->pos_x = x; this->pos_y = y; diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 2fa08a805f..5f3f279acf 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1424,7 +1424,7 @@ public: _toolbar_width = nbuttons * this->smallest_x; } - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); diff --git a/src/widget.cpp b/src/widget.cpp index ebeefc55aa..fa91b1f66d 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1008,7 +1008,7 @@ NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator() */ /** - * @fn void NWidgetBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + * @fn void NWidgetBase::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) * Assign size and position to the widget. * @param sizing Type of resizing to perform. * @param x Horizontal offset of the widget relative to the left edge of the window. @@ -1163,7 +1163,7 @@ bool NWidgetResizeBase::UpdateVerticalSize(uint min_y) return true; } -void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool) +void NWidgetResizeBase::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool) { this->StoreSizePosition(sizing, x, y, given_width, given_height); } @@ -1400,7 +1400,7 @@ void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array) } } -void NWidgetStacked::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +void NWidgetStacked::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); this->StoreSizePosition(sizing, x, y, given_width, given_height); @@ -1570,7 +1570,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) this->pip_pre = this->pip_inter = this->pip_post = 0; } -void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); @@ -1678,7 +1678,7 @@ NWidgetHorizontalLTR::NWidgetHorizontalLTR(NWidContainerFlags flags) : NWidgetHo this->type = NWID_HORIZONTAL_LTR; } -void NWidgetHorizontalLTR::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool) +void NWidgetHorizontalLTR::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool) { NWidgetHorizontal::AssignSizePosition(sizing, x, y, given_width, given_height, false); } @@ -1755,7 +1755,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) this->pip_pre = this->pip_inter = this->pip_post = 0; } -void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); @@ -1981,7 +1981,7 @@ void NWidgetMatrix::SetupSmallestSize(Window *w, bool init_array) this->resize_y = resize.height; } -void NWidgetMatrix::AssignSizePosition(SizingType, uint x, uint y, uint given_width, uint given_height, bool) +void NWidgetMatrix::AssignSizePosition(SizingType, int x, int y, uint given_width, uint given_height, bool) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); @@ -2249,7 +2249,7 @@ void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) } } -void NWidgetBackground::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) +void NWidgetBackground::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) { this->StoreSizePosition(sizing, x, y, given_width, given_height); diff --git a/src/widget_type.h b/src/widget_type.h index ae71ca11e6..baa9623053 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -127,7 +127,7 @@ public: virtual void AdjustPaddingForZoom(); virtual void SetupSmallestSize(Window *w, bool init_array) = 0; - virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) = 0; + virtual void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) = 0; virtual void FillNestedArray(NWidgetBase **array, uint length) = 0; @@ -204,7 +204,7 @@ public: RectPadding uz_padding; ///< Unscaled padding, for resize calculation. protected: - inline void StoreSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height); + inline void StoreSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height); }; /** @@ -233,7 +233,7 @@ inline uint NWidgetBase::GetVerticalStepSize(SizingType sizing) const * @param given_width Width allocated to the widget. * @param given_height Height allocated to the widget. */ -inline void NWidgetBase::StoreSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height) +inline void NWidgetBase::StoreSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height) { this->pos_x = x; this->pos_y = y; @@ -263,7 +263,7 @@ public: bool UpdateVerticalSize(uint min_y); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; uint min_x; ///< Minimal horizontal size of only this widget. uint min_y; ///< Minimal vertical size of only this widget. @@ -452,7 +452,7 @@ public: void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w, bool init_array) override; - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; void FillNestedArray(NWidgetBase **array, uint length) override; void Draw(const Window *w) override; @@ -503,7 +503,7 @@ public: NWidgetHorizontal(NWidContainerFlags flags = NC_NONE); void SetupSmallestSize(Window *w, bool init_array) override; - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; }; /** @@ -514,7 +514,7 @@ class NWidgetHorizontalLTR : public NWidgetHorizontal { public: NWidgetHorizontalLTR(NWidContainerFlags flags = NC_NONE); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; }; /** @@ -526,7 +526,7 @@ public: NWidgetVertical(NWidContainerFlags flags = NC_NONE); void SetupSmallestSize(Window *w, bool init_array) override; - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; }; /** @@ -548,7 +548,7 @@ public: void SetScrollbar(Scrollbar *sb); void SetupSmallestSize(Window *w, bool init_array) override; - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; void FillNestedArray(NWidgetBase **array, uint length) override; NWidgetCore *GetWidgetFromPos(int x, int y) override; @@ -599,7 +599,7 @@ public: void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w, bool init_array) override; - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; void FillNestedArray(NWidgetBase **array, uint length) override; From 89480f35314c32a4d8917bc72c3d054ca3d95cab Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Wed, 1 Nov 2023 15:26:39 -0400 Subject: [PATCH 09/57] Change: Don't set vehicle on time if timetable not started (#11359) --- src/lang/english.txt | 1 + src/timetable_cmd.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/lang/english.txt b/src/lang/english.txt index 1ff9eaf612..baa40974e6 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -5189,6 +5189,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Can't ti STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehicles can only wait at stations STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}This vehicle is not stopping at this station STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... timetable is incomplete +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... timetable has not started yet # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... too many signs diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 8fe617ed70..6b77355c59 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -221,6 +221,10 @@ CommandCost CmdSetVehicleOnTime(DoCommandFlag flags, VehicleID veh, bool apply_t Vehicle *v = Vehicle::GetIfValid(veh); if (v == nullptr || !v->IsPrimaryVehicle() || v->orders == nullptr) return CMD_ERROR; + /* A vehicle can't be late if its timetable hasn't started. + * If we're setting all vehicles in the group, we handle that below. */ + if (!apply_to_group && !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return CommandCost(STR_ERROR_TIMETABLE_NOT_STARTED); + CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -228,12 +232,18 @@ CommandCost CmdSetVehicleOnTime(DoCommandFlag flags, VehicleID veh, bool apply_t if (apply_to_group) { int32_t most_late = 0; for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) { + /* A vehicle can't be late if its timetable hasn't started. */ + if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) continue; + if (u->lateness_counter > most_late) { most_late = u->lateness_counter; } } if (most_late > 0) { for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) { + /* A vehicle can't be late if its timetable hasn't started. */ + if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) continue; + u->lateness_counter -= most_late; SetWindowDirty(WC_VEHICLE_TIMETABLE, u->index); } From d3cb6e1e6776279249ab8f1ceda843e5c551f9f7 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 1 Nov 2023 20:12:08 +0000 Subject: [PATCH 10/57] Codechange: Call Widget::SetDirty/SetLowered directly. (#11417) In these instances we already have the widget to hand, so don't need to look it up by index again. --- src/widgets/dropdown.cpp | 4 ++-- src/window.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index bca67a504e..5ee04219b5 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -438,9 +438,9 @@ void ShowDropDownList(Window *w, DropDownList &&list, int selected, int button, if ((nwi->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) { nwi->disp_flags |= ND_DROPDOWN_ACTIVE; } else { - w->LowerWidget(button); + nwi->SetLowered(true); } - w->SetWidgetDirty(button); + nwi->SetDirty(w); if (width != 0) { if (_current_text_dir == TD_RTL) { diff --git a/src/window.cpp b/src/window.cpp index 8782b49056..5de2f8f6cf 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -228,7 +228,7 @@ void Window::DisableAllWidgetHighlight() if (nwid->IsHighlighted()) { nwid->SetHighlighted(TC_INVALID); - this->SetWidgetDirty(i); + nwid->SetDirty(this); } } @@ -248,7 +248,7 @@ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour if (nwid == nullptr) return; nwid->SetHighlighted(highlighted_colour); - this->SetWidgetDirty(widget_index); + nwid->SetDirty(this); if (highlighted_colour != TC_INVALID) { /* If we set a highlight, the window has a highlight */ From 49d53c41ab0fbf1845c02e8b46c113554f0a7ca7 Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Wed, 1 Nov 2023 17:19:31 -0400 Subject: [PATCH 11/57] Doc: Don't use other names for road vehicle bay stops (#11418) --- src/newgrf_roadstop.cpp | 2 +- src/road.h | 2 +- src/station_cmd.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/newgrf_roadstop.cpp b/src/newgrf_roadstop.cpp index c3410e3032..2b16653030 100644 --- a/src/newgrf_roadstop.cpp +++ b/src/newgrf_roadstop.cpp @@ -294,7 +294,7 @@ void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, } } } else { - /* Drive-in stop */ + /* Bay stop */ if ((spec->draw_mode & ROADSTOP_DRAW_MODE_ROAD) && rti->UsesOverlay()) { SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP); DrawSprite(ground + view, PAL_NONE, x, y); diff --git a/src/road.h b/src/road.h index 3fa95c273e..6110819108 100644 --- a/src/road.h +++ b/src/road.h @@ -64,7 +64,7 @@ enum RoadTypeSpriteGroup { ROTSG_reserved2, ///< Placeholder, if we need specific level crossing sprites. ROTSG_DEPOT, ///< Optional: Depot images ROTSG_reserved3, ///< Placeholder, if we add road fences (for highways). - ROTSG_ROADSTOP, ///< Required: Drive-in stop surface + ROTSG_ROADSTOP, ///< Required: Bay stop surface ROTSG_ONEWAY, ///< Optional: One-way indicator images ROTSG_END, }; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index bb4faef811..2f03490441 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3246,7 +3246,7 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y); } } else { - /* Drive-in stop */ + /* Bay stop */ if (RoadTypeIsRoad(roadtype) && roadtype_info->UsesOverlay()) { SpriteID ground = GetCustomRoadSprite(roadtype_info, INVALID_TILE, ROTSG_ROADSTOP); DrawSprite(ground + image, PAL_NONE, x, y); From 4f3adc038a27ef72b192870178a5e85ecf6817eb Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 1 Nov 2023 17:03:26 +0000 Subject: [PATCH 12/57] Cleanup: Use standard comment codestyle. --- src/industry.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/industry.h b/src/industry.h index b3783ef3bf..912709c86f 100644 --- a/src/industry.h +++ b/src/industry.h @@ -150,23 +150,27 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> { return std::find_if(std::begin(this->accepted), std::end(this->accepted), [&cargo](const auto &a) { return a.cargo == cargo; }); } - /** Test if this industry accepts any cargo. + /** + * Test if this industry accepts any cargo. * @return true iff the industry accepts any cargo. */ bool IsCargoAccepted() const { return std::any_of(std::begin(this->accepted), std::end(this->accepted), [](const auto &a) { return IsValidCargoID(a.cargo); }); } - /** Test if this industry produces any cargo. + /** + * Test if this industry produces any cargo. * @return true iff the industry produces any cargo. */ bool IsCargoProduced() const { return std::any_of(std::begin(this->produced), std::end(this->produced), [](const auto &p) { return IsValidCargoID(p.cargo); }); } - /** Test if this industry accepts a specific cargo. + /** + * Test if this industry accepts a specific cargo. * @param cargo Cargo type to test. * @return true iff the industry accepts the given cargo type. */ bool IsCargoAccepted(CargoID cargo) const { return std::any_of(std::begin(this->accepted), std::end(this->accepted), [&cargo](const auto &a) { return a.cargo == cargo; }); } - /** Test if this industry produces a specific cargo. + /** + * Test if this industry produces a specific cargo. * @param cargo Cargo type to test. * @return true iff the industry produces the given cargo types. */ From 278b42d078f68899abc68ff5845697584fd7d3d8 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 20:14:03 +0000 Subject: [PATCH 13/57] Codechange: Document Industry::GetCargoProduced/Accepted and add const-variant. --- src/industry.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/industry.h b/src/industry.h index 912709c86f..bc6f79bb23 100644 --- a/src/industry.h +++ b/src/industry.h @@ -138,12 +138,33 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> { return IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->index; } + /** + * Get produced cargo slot for a specific cargo type. + * @param cargo CargoID to find. + * @return Iterator pointing to produced cargo slot if it exists, or the end iterator. + */ inline ProducedCargoArray::iterator GetCargoProduced(CargoID cargo) { if (!IsValidCargoID(cargo)) return std::end(this->produced); return std::find_if(std::begin(this->produced), std::end(this->produced), [&cargo](const auto &p) { return p.cargo == cargo; }); } + /** + * Get produced cargo slot for a specific cargo type (const-variant). + * @param cargo CargoID to find. + * @return Iterator pointing to produced cargo slot if it exists, or the end iterator. + */ + inline ProducedCargoArray::const_iterator GetCargoProduced(CargoID cargo) const + { + if (!IsValidCargoID(cargo)) return std::end(this->produced); + return std::find_if(std::begin(this->produced), std::end(this->produced), [&cargo](const auto &p) { return p.cargo == cargo; }); + } + + /** + * Get accepted cargo slot for a specific cargo type. + * @param cargo CargoID to find. + * @return Iterator pointing to accepted cargo slot if it exists, or the end iterator. + */ inline AcceptedCargoArray::iterator GetCargoAccepted(CargoID cargo) { if (!IsValidCargoID(cargo)) return std::end(this->accepted); From ff5e8bb9a3fc5aa57f5277d56a49ff95e6bc3a75 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 20:21:47 +0000 Subject: [PATCH 14/57] Fix #11413: Incorrect sorting by industry production. Error caused by single character mistake. However this algorithm was inefficent if a filter was specified, and clearly the flow was error-prone. Now using separately-scoped loops to avoid similar. --- src/industry_gui.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 4d808eecc9..824ce9b172 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1509,14 +1509,16 @@ protected: if (filter == CF_NONE) return IndustryTypeSorter(a, b); uint prod_a = 0, prod_b = 0; - for (auto ita = std::begin(a->produced), itb = std::begin(b->produced); ita != std::end(a->produced) && itb != std::end(b->produced); ++ita, ++itb) { - if (filter == CF_ANY) { - if (IsValidCargoID(ita->cargo)) prod_a += ita->history[LAST_MONTH].production; - if (IsValidCargoID(itb->cargo)) prod_b += ita->history[LAST_MONTH].production; - } else { - if (ita->cargo == filter) prod_a += ita->history[LAST_MONTH].production; - if (itb->cargo == filter) prod_b += itb->history[LAST_MONTH].production; + if (filter == CF_ANY) { + for (const auto &pa : a->produced) { + if (IsValidCargoID(pa.cargo)) prod_a += pa.history[LAST_MONTH].production; } + for (const auto &pb : b->produced) { + if (IsValidCargoID(pb.cargo)) prod_b += pb.history[LAST_MONTH].production; + } + } else { + if (auto ita = a->GetCargoProduced(filter); ita != std::end(a->produced)) prod_a = ita->history[LAST_MONTH].production; + if (auto itb = b->GetCargoProduced(filter); itb != std::end(b->produced)) prod_b = itb->history[LAST_MONTH].production; } int r = prod_a - prod_b; From f91462f54b3e660cb6bbd14453133f75b1569a8c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 01:29:16 +0000 Subject: [PATCH 15/57] Codechange: Don't access SmallMapWindow method directly from LinkGraphOverlay. --- src/linkgraph/linkgraph_gui.cpp | 2 +- src/smallmap_gui.cpp | 10 ++++++++++ src/smallmap_gui.h | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index e284a156be..18337ffa18 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -425,7 +425,7 @@ Point LinkGraphOverlay::GetStationMiddle(const Station *st) const return GetViewportStationMiddle(this->window->viewport, st); } else { /* assume this is a smallmap */ - return static_cast(this->window)->GetStationMiddle(st); + return GetSmallMapStationMiddle(this->window, st); } } diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 09f73b6d32..91f0ead98b 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1888,3 +1888,13 @@ bool ScrollMainWindowTo(int x, int y, int z, bool instant) return res; } + +/** + * Determine the middle of a station in the smallmap window. + * @param st The station we're looking for. + * @return Middle point of the station in the smallmap window. + */ +Point GetSmallMapStationMiddle(const Window *w, const Station *st) +{ + return static_cast(w)->GetStationMiddle(st); +} diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h index 570a256f98..e051f788a8 100644 --- a/src/smallmap_gui.h +++ b/src/smallmap_gui.h @@ -212,4 +212,6 @@ public: void OnMouseOver([[maybe_unused]] Point pt, int widget) override; }; +Point GetSmallMapStationMiddle(const Window *w, const Station *st); + #endif /* SMALLMAP_GUI_H */ From ed8df72c49aa1b21fd04146f26757cc505e30f40 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 01:32:40 +0000 Subject: [PATCH 16/57] Revert 6b68956: Move declaration of SmallMapWindow out of header file. This split needlessly complicates `SmallMapWindow` for the sake of one method (no longer) used by `LinkGraphOverlay`. --- src/smallmap_gui.cpp | 2022 ++++++++++++++++++++++-------------------- src/smallmap_gui.h | 175 ---- 2 files changed, 1075 insertions(+), 1122 deletions(-) diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 91f0ead98b..c4333ad616 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -36,6 +36,18 @@ static int _smallmap_industry_count; ///< Number of used industries static int _smallmap_company_count; ///< Number of entries in the owner legend. static int _smallmap_cargo_count; ///< Number of cargos in the link stats legend. +/** Structure for holding relevant data for legends in small map */ +struct LegendAndColour { + uint8_t colour; ///< Colour of the item on the map. + StringID legend; ///< String corresponding to the coloured item. + IndustryType type; ///< Type of industry. Only valid for industry entries. + uint8_t height; ///< Height in tiles. Only valid for height legend entries. + CompanyID company; ///< Company to display. Only valid for company entries of the owner legend. + bool show_on_map; ///< For filtering industries, if \c true, industry is shown on the map in colour. + bool end; ///< This is the end of the list. + bool col_break; ///< Perform a column break and go further at the next column. +}; + /** Link stat colours shown in legenda. */ static uint8_t _linkstat_colours_in_legenda[] = {0, 1, 3, 5, 7, 9, 11}; @@ -594,1113 +606,1229 @@ static const byte _vehicle_type_colours[6] = { PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED }; +/** Class managing the smallmap window. */ +class SmallMapWindow : public Window { +protected: + /** Types of legends in the #WID_SM_LEGEND widget. */ + enum SmallMapType { + SMT_CONTOUR, + SMT_VEHICLES, + SMT_INDUSTRY, + SMT_LINKSTATS, + SMT_ROUTES, + SMT_VEGETATION, + SMT_OWNER, + }; + + /** Available kinds of zoomlevel changes. */ + enum ZoomLevelChange { + ZLC_INITIALIZE, ///< Initialize zoom level. + ZLC_ZOOM_OUT, ///< Zoom out. + ZLC_ZOOM_IN, ///< Zoom in. + }; + + static SmallMapType map_type; ///< Currently displayed legends. + static bool show_towns; ///< Display town names in the smallmap. + static int map_height_limit; ///< Currently used/cached map height limit. + + static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; ///< Minimal number of columns in the #WID_SM_LEGEND widget for the #SMT_INDUSTRY legend. + + uint min_number_of_columns; ///< Minimal number of columns in legends. + uint min_number_of_fixed_rows; ///< Minimal number of rows in the legends for the fixed layouts only (all except #SMT_INDUSTRY). + uint column_width; ///< Width of a column in the #WID_SM_LEGEND widget. + uint legend_width; ///< Width of legend 'blob'. + + int32_t scroll_x; ///< Horizontal world coordinate of the base tile left of the top-left corner of the smallmap display. + int32_t scroll_y; ///< Vertical world coordinate of the base tile left of the top-left corner of the smallmap display. + int32_t subscroll; ///< Number of pixels (0..3) between the right end of the base tile and the pixel at the top-left corner of the smallmap display. + int zoom; ///< Zoom level. Bigger number means more zoom-out (further away). + + LinkGraphOverlay *overlay; + + /** Notify the industry chain window to stop sending newly selected industries. */ + static void BreakIndustryChainLink() + { + InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES); + } -/** Notify the industry chain window to stop sending newly selected industries. */ -/* static */ void SmallMapWindow::BreakIndustryChainLink() -{ - InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES); -} + static inline Point SmallmapRemapCoords(int x, int y) + { + Point pt; + pt.x = (y - x) * 2; + pt.y = y + x; + return pt; + } -inline Point SmallMapWindow::SmallmapRemapCoords(int x, int y) const -{ - Point pt; - pt.x = (y - x) * 2; - pt.y = y + x; - return pt; -} + /** + * Draws vertical part of map indicator + * @param x X coord of left/right border of main viewport + * @param y Y coord of top border of main viewport + * @param y2 Y coord of bottom border of main viewport + */ + static inline void DrawVertMapIndicator(int x, int y, int y2) + { + GfxFillRect(x, y, x, y + 3, PC_VERY_LIGHT_YELLOW); + GfxFillRect(x, y2 - 3, x, y2, PC_VERY_LIGHT_YELLOW); + } -/** - * Remap tile to location on this smallmap. - * @param tile_x X coordinate of the tile. - * @param tile_y Y coordinate of the tile. - * @return Position to draw on. - */ -inline Point SmallMapWindow::RemapTile(int tile_x, int tile_y) const -{ - int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE; - int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE; + /** + * Draws horizontal part of map indicator + * @param x X coord of left border of main viewport + * @param x2 X coord of right border of main viewport + * @param y Y coord of top/bottom border of main viewport + */ + static inline void DrawHorizMapIndicator(int x, int x2, int y) + { + GfxFillRect(x, y, x + 3, y, PC_VERY_LIGHT_YELLOW); + GfxFillRect(x2 - 3, y, x2, y, PC_VERY_LIGHT_YELLOW); + } - if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset); + /** + * Compute minimal required width of the legends. + * @return Minimally needed width for displaying the smallmap legends in pixels. + */ + inline uint GetMinLegendWidth() const + { + return WidgetDimensions::scaled.framerect.left + this->min_number_of_columns * this->column_width; + } - /* For negative offsets, round towards -inf. */ - if (x_offset < 0) x_offset -= this->zoom - 1; - if (y_offset < 0) y_offset -= this->zoom - 1; + /** + * Return number of columns that can be displayed in \a width pixels. + * @return Number of columns to display. + */ + inline uint GetNumberColumnsLegend(uint width) const + { + return width / this->column_width; + } - return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom); -} + /** + * Compute height given a number of columns. + * @param num_columns Number of columns. + * @return Needed height for displaying the smallmap legends in pixels. + */ + inline uint GetLegendHeight(uint num_columns) const + { + return WidgetDimensions::scaled.framerect.Vertical() + + this->GetNumberRowsLegend(num_columns) * FONT_HEIGHT_SMALL; + } -/** - * Determine the tile relative to the base tile of the smallmap, and the pixel position at - * that tile for a point in the smallmap. - * @param px Horizontal coordinate of the pixel. - * @param py Vertical coordinate of the pixel. - * @param[out] sub Pixel position at the tile (0..3). - * @param add_sub Add current #subscroll to the position. - * @return Tile being displayed at the given position relative to #scroll_x and #scroll_y. - * @note The #subscroll offset is already accounted for. - */ -inline Point SmallMapWindow::PixelToTile(int px, int py, int *sub, bool add_sub) const -{ - if (add_sub) px += this->subscroll; // Total horizontal offset. + /** + * Get a bitmask for company links to be displayed. Usually this will be + * the _local_company. Spectators get to see all companies' links. + * @return Company mask. + */ + inline CompanyMask GetOverlayCompanyMask() const + { + return Company::IsValidID(_local_company) ? 1U << _local_company : MAX_UVALUE(CompanyMask); + } - /* For each two rows down, add a x and a y tile, and - * For each four pixels to the right, move a tile to the right. */ - Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom}; - px &= 3; + /** Blink the industries (if selected) on a regular interval. */ + IntervalTimer blink_interval = {std::chrono::milliseconds(450), [this](auto) { + Blink(); + }}; - if (py & 1) { // Odd number of rows, handle the 2 pixel shift. - if (px < 2) { - pt.x += this->zoom; - px += 2; - } else { - pt.y += this->zoom; - px -= 2; + /** Update the whole map on a regular interval. */ + IntervalTimer refresh_interval = {std::chrono::milliseconds(930), [this](auto) { + ForceRefresh(); + }}; + + /** + * Rebuilds the colour indices used for fast access to the smallmap contour colours based on the heightlevel. + */ + void RebuildColourIndexIfNecessary() + { + /* Rebuild colour indices if necessary. */ + if (SmallMapWindow::map_height_limit == _settings_game.construction.map_height_limit) return; + + for (uint n = 0; n < lengthof(_heightmap_schemes); n++) { + /* The heights go from 0 up to and including maximum. */ + int heights = _settings_game.construction.map_height_limit + 1; + _heightmap_schemes[n].height_colours = ReallocT(_heightmap_schemes[n].height_colours, heights); + + for (int z = 0; z < heights; z++) { + size_t access_index = (_heightmap_schemes[n].colour_count * z) / heights; + + /* Choose colour by mapping the range (0..max heightlevel) on the complete colour table. */ + _heightmap_schemes[n].height_colours[z] = _heightmap_schemes[n].height_colours_base[access_index]; + } } - } - *sub = px; - return pt; -} + SmallMapWindow::map_height_limit = _settings_game.construction.map_height_limit; + BuildLandLegend(); + } -/** - * Compute base parameters of the smallmap such that tile (\a tx, \a ty) starts at pixel (\a x, \a y). - * @param tx Tile x coordinate. - * @param ty Tile y coordinate. - * @param x Non-negative horizontal position in the display where the tile starts. - * @param y Non-negative vertical position in the display where the tile starts. - * @param[out] sub Value of #subscroll needed. - * @return #scroll_x, #scroll_y values. - */ -Point SmallMapWindow::ComputeScroll(int tx, int ty, int x, int y, int *sub) -{ - assert(x >= 0 && y >= 0); - - int new_sub; - Point tile_xy = PixelToTile(x, y, &new_sub, false); - tx -= tile_xy.x; - ty -= tile_xy.y; - - Point scroll; - if (new_sub == 0) { - *sub = 0; - scroll.x = (tx + this->zoom) * TILE_SIZE; - scroll.y = (ty - this->zoom) * TILE_SIZE; - } else { - *sub = 4 - new_sub; - scroll.x = (tx + 2 * this->zoom) * TILE_SIZE; - scroll.y = (ty - 2 * this->zoom) * TILE_SIZE; + /** + * Get the number of rows in the legend from the number of columns. Those + * are at least min_number_of_fixed_rows and possibly more if there are so + * many cargoes, industry types or companies that they won't fit in the + * available space. + * @param columns Number of columns in the legend. + * @return Number of rows needed for everything to fit in. + */ + uint GetNumberRowsLegend(uint columns) const + { + /* Reserve one column for link colours */ + uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1); + uint num_rows_others = CeilDiv(std::max(_smallmap_industry_count, _smallmap_company_count), columns); + return std::max({this->min_number_of_fixed_rows, num_rows_linkstats, num_rows_others}); } - return scroll; -} -/** - * Initialize or change the zoom level. - * @param change Way to change the zoom level. - * @param zoom_pt Position to keep fixed while zooming. - * @pre \c *zoom_pt should contain a point in the smallmap display when zooming in or out. - */ -void SmallMapWindow::SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt) -{ - static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away). - static const int MIN_ZOOM_INDEX = 0; - static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1; - - int new_index, cur_index, sub; - Point tile; - switch (change) { - case ZLC_INITIALIZE: - cur_index = - 1; // Definitely different from new_index. - new_index = MIN_ZOOM_INDEX; - tile.x = tile.y = 0; - break; - - case ZLC_ZOOM_IN: - case ZLC_ZOOM_OUT: - for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) { - if (this->zoom == zoomlevels[cur_index]) break; + /** + * Select and toggle a legend item. When CTRL is pressed, disable all other + * items in the group defined by begin_legend_item and end_legend_item and + * keep the clicked one enabled even if it was already enabled before. If + * the other items in the group are all disabled already and CTRL is pressed + * enable them instead. + * @param click_pos the index of the item being selected + * @param legend the legend from which we select + * @param end_legend_item index one past the last item in the group to be inverted + * @param begin_legend_item index of the first item in the group to be inverted + */ + void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0) + { + if (_ctrl_pressed) { + /* Disable all, except the clicked one */ + bool changes = false; + for (int i = begin_legend_item; i != end_legend_item; i++) { + bool new_state = (i == click_pos); + if (legend[i].show_on_map != new_state) { + changes = true; + legend[i].show_on_map = new_state; + } + } + if (!changes) { + /* Nothing changed? Then show all (again). */ + for (int i = begin_legend_item; i != end_legend_item; i++) { + legend[i].show_on_map = true; + } } - assert(cur_index <= MAX_ZOOM_INDEX); + } else { + legend[click_pos].show_on_map = !legend[click_pos].show_on_map; + } - tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); - new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX); - break; + if (this->map_type == SMT_INDUSTRY) this->BreakIndustryChainLink(); + } - default: NOT_REACHED(); + /** + * Select a new map type. + * @param map_type New map type. + */ + void SwitchMapType(SmallMapType map_type) + { + this->RaiseWidget(this->map_type + WID_SM_CONTOUR); + this->map_type = map_type; + this->LowerWidget(this->map_type + WID_SM_CONTOUR); + + this->SetupWidgetData(); + + if (map_type == SMT_LINKSTATS) this->overlay->SetDirty(); + if (map_type != SMT_INDUSTRY) this->BreakIndustryChainLink(); + this->SetDirty(); } - if (new_index != cur_index) { - this->zoom = zoomlevels[new_index]; - if (cur_index >= 0) { - Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); - this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE, - this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub); - } else if (this->map_type == SMT_LINKSTATS) { - this->overlay->SetDirty(); + /** + * Set new #scroll_x, #scroll_y, and #subscroll values after limiting them such that the center + * of the smallmap always contains a part of the map. + * @param sx Proposed new #scroll_x + * @param sy Proposed new #scroll_y + * @param sub Proposed new #subscroll + */ + void SetNewScroll(int sx, int sy, int sub) + { + const NWidgetBase *wi = this->GetWidget(WID_SM_MAP); + Point hv = InverseRemapCoords(wi->current_x * ZOOM_LVL_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_LVL_BASE * TILE_SIZE / 2); + hv.x *= this->zoom; + hv.y *= this->zoom; + + if (sx < -hv.x) { + sx = -hv.x; + sub = 0; } - this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]); - this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]); - this->SetDirty(); + if (sx > (int)(Map::MaxX() * TILE_SIZE) - hv.x) { + sx = Map::MaxX() * TILE_SIZE - hv.x; + sub = 0; + } + if (sy < -hv.y) { + sy = -hv.y; + sub = 0; + } + if (sy > (int)(Map::MaxY() * TILE_SIZE) - hv.y) { + sy = Map::MaxY() * TILE_SIZE - hv.y; + sub = 0; + } + + this->scroll_x = sx; + this->scroll_y = sy; + this->subscroll = sub; + if (this->map_type == SMT_LINKSTATS) this->overlay->SetDirty(); } -} -/** - * Decide which colours to show to the user for a group of tiles. - * @param ta Tile area to investigate. - * @return Colours to display. - */ -inline uint32_t SmallMapWindow::GetTileColours(const TileArea &ta) const -{ - int importance = 0; - TileIndex tile = INVALID_TILE; // Position of the most important tile. - TileType et = MP_VOID; // Effective tile type at that position. + /** + * Adds map indicators to the smallmap. + */ + void DrawMapIndicators() const + { + /* Find main viewport. */ + const Viewport *vp = GetMainWindow()->viewport; - for (TileIndex ti : ta) { - TileType ttype = GetTileType(ti); + Point upper_left_smallmap_coord = InverseRemapCoords2(vp->virtual_left, vp->virtual_top); + Point lower_right_smallmap_coord = InverseRemapCoords2(vp->virtual_left + vp->virtual_width - 1, vp->virtual_top + vp->virtual_height - 1); - switch (ttype) { - case MP_TUNNELBRIDGE: { - TransportType tt = GetTunnelBridgeTransportType(ti); + Point upper_left = this->RemapTile(upper_left_smallmap_coord.x / (int)TILE_SIZE, upper_left_smallmap_coord.y / (int)TILE_SIZE); + upper_left.x -= this->subscroll; - switch (tt) { - case TRANSPORT_RAIL: ttype = MP_RAILWAY; break; - case TRANSPORT_ROAD: ttype = MP_ROAD; break; - default: ttype = MP_WATER; break; - } - break; + Point lower_right = this->RemapTile(lower_right_smallmap_coord.x / (int)TILE_SIZE, lower_right_smallmap_coord.y / (int)TILE_SIZE); + lower_right.x -= this->subscroll; + + SmallMapWindow::DrawVertMapIndicator(upper_left.x, upper_left.y, lower_right.y); + SmallMapWindow::DrawVertMapIndicator(lower_right.x, upper_left.y, lower_right.y); + + SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, upper_left.y); + SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, lower_right.y); + } + + /** + * Draws one column of tiles of the small map in a certain mode onto the screen buffer, skipping the shifted rows in between. + * + * @param dst Pointer to a part of the screen buffer to write to. + * @param xc The X coordinate of the first tile in the column. + * @param yc The Y coordinate of the first tile in the column + * @param pitch Number of pixels to advance in the screen buffer each time a pixel is written. + * @param reps Number of lines to draw + * @param start_pos Position of first pixel to draw. + * @param end_pos Position of last pixel to draw (exclusive). + * @param blitter current blitter + * @note If pixel position is below \c 0, skip drawing. + */ + void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const + { + void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height); + uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0; + + do { + /* Check if the tile (xc,yc) is within the map range */ + if (xc >= Map::MaxX() || yc >= Map::MaxY()) continue; + + /* Check if the dst pointer points to a pixel inside the screen buffer */ + if (dst < _screen.dst_ptr) continue; + if (dst >= dst_ptr_abs_end) continue; + + /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */ + TileArea ta; + if (min_xy == 1 && (xc == 0 || yc == 0)) { + if (this->zoom == 1) continue; // The tile area is empty, don't draw anything. + + ta = TileArea(TileXY(std::max(min_xy, xc), std::max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0)); + } else { + ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom); + } + ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!). + + uint32_t val = this->GetTileColours(ta); + uint8_t *val8 = (uint8_t *)&val; + int idx = std::max(0, -start_pos); + for (int pos = std::max(0, start_pos); pos < end_pos; pos++) { + blitter->SetPixel(dst, idx, 0, val8[idx]); + idx++; } + /* Switch to next tile in the column */ + } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0); + } - case MP_INDUSTRY: - /* Special handling of industries while in "Industries" smallmap view. */ - if (this->map_type == SMT_INDUSTRY) { - /* If industry is allowed to be seen, use its colour on the map. - * This has the highest priority above any value in _tiletype_importance. */ - IndustryType type = Industry::GetByTile(ti)->type; - if (_legend_from_industries[_industry_to_list_pos[type]].show_on_map) { - if (type == _smallmap_industry_highlight) { - if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE); - } else { - return GetIndustrySpec(type)->map_colour * 0x01010101; - } - } - /* Otherwise make it disappear */ - ttype = IsTileOnWater(ti) ? MP_WATER : MP_CLEAR; - } - break; + /** + * Adds vehicles to the smallmap. + * @param dpi the part of the smallmap to be drawn into + * @param blitter current blitter + */ + void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const + { + for (const Vehicle *v : Vehicle::Iterate()) { + if (v->type == VEH_EFFECT) continue; + if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue; + + /* Remap into flat coordinates. */ + Point pt = this->RemapTile(v->x_pos / (int)TILE_SIZE, v->y_pos / (int)TILE_SIZE); + + int y = pt.y - dpi->top; + if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds. + + bool skip = false; // Default is to draw both pixels. + int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate. + if (x < 0) { + /* if x+1 is 0, that means we're on the very left edge, + * and should thus only draw a single pixel */ + if (++x != 0) continue; + skip = true; + } else if (x >= dpi->width - 1) { + /* Check if we're at the very right edge, and if so draw only a single pixel */ + if (x != dpi->width - 1) continue; + skip = true; + } - default: - break; + /* Calculate pointer to pixel and the colour */ + byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE; + + /* And draw either one or two pixels depending on clipping */ + blitter->SetPixel(dpi->dst_ptr, x, y, colour); + if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour); } + } - if (_tiletype_importance[ttype] > importance) { - importance = _tiletype_importance[ttype]; - tile = ti; - et = ttype; + /** + * Adds town names to the smallmap. + * @param dpi the part of the smallmap to be drawn into + */ + void DrawTowns(const DrawPixelInfo *dpi) const + { + for (const Town *t : Town::Iterate()) { + /* Remap the town coordinate */ + Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy)); + int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1); + int y = pt.y; + + /* Check if the town sign is within bounds */ + if (x + t->cache.sign.width_small > dpi->left && + x < dpi->left + dpi->width && + y + FONT_HEIGHT_SMALL > dpi->top && + y < dpi->top + dpi->height) { + /* And draw it. */ + SetDParam(0, t->index); + DrawString(x, x + t->cache.sign.width_small, y, STR_SMALLMAP_TOWN); + } } } - switch (this->map_type) { - case SMT_CONTOUR: - return GetSmallMapContoursPixels(tile, et); + /** + * Draws the small map. + * + * Basically, the small map is draw column of pixels by column of pixels. The pixels + * are drawn directly into the screen buffer. The final map is drawn in multiple passes. + * The passes are: + *
  1. The colours of tiles in the different modes.
  2. + *
  3. Town names (optional)
+ * + * @param dpi pointer to pixel to write onto + */ + void DrawSmallMap(DrawPixelInfo *dpi) const + { + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + AutoRestoreBackup dpi_backup(_cur_dpi, dpi); + + /* Clear it */ + GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK); + + /* Which tile is displayed at (dpi->left, dpi->top)? */ + int dx; + Point tile = this->PixelToTile(dpi->left, dpi->top, &dx); + int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x; + int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y; + + void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); + int x = - dx - 4; + int y = 0; + + for (;;) { + /* Distance from left edge */ + if (x >= -3) { + if (x >= dpi->width) break; // Exit the loop. + + int end_pos = std::min(dpi->width, x + 4); + int reps = (dpi->height - y + 1) / 2; // Number of lines. + if (reps > 0) { + this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter); + } + } - case SMT_VEHICLES: - return GetSmallMapVehiclesPixels(tile, et); + if (y == 0) { + tile_y += this->zoom; + y++; + ptr = blitter->MoveTo(ptr, 0, 1); + } else { + tile_x -= this->zoom; + y--; + ptr = blitter->MoveTo(ptr, 0, -1); + } + ptr = blitter->MoveTo(ptr, 2, 0); + x += 2; + } - case SMT_INDUSTRY: - return GetSmallMapIndustriesPixels(tile, et); + /* Draw vehicles */ + if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter); - case SMT_LINKSTATS: - return GetSmallMapLinkStatsPixels(tile, et); + /* Draw link stat overlay */ + if (this->map_type == SMT_LINKSTATS) this->overlay->Draw(dpi); - case SMT_ROUTES: - return GetSmallMapRoutesPixels(tile, et); + /* Draw town names */ + if (this->show_towns) this->DrawTowns(dpi); - case SMT_VEGETATION: - return GetSmallMapVegetationPixels(tile, et); + /* Draw map indicators */ + this->DrawMapIndicators(); + } - case SMT_OWNER: - return GetSmallMapOwnerPixels(tile, et, IncludeHeightmap::IfEnabled); + /** + * Remap tile to location on this smallmap. + * @param tile_x X coordinate of the tile. + * @param tile_y Y coordinate of the tile. + * @return Position to draw on. + */ + Point RemapTile(int tile_x, int tile_y) const + { + int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE; + int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE; + + if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset); + + /* For negative offsets, round towards -inf. */ + if (x_offset < 0) x_offset -= this->zoom - 1; + if (y_offset < 0) y_offset -= this->zoom - 1; - default: NOT_REACHED(); + return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom); } -} -/** - * Draws one column of tiles of the small map in a certain mode onto the screen buffer, skipping the shifted rows in between. - * - * @param dst Pointer to a part of the screen buffer to write to. - * @param xc The X coordinate of the first tile in the column. - * @param yc The Y coordinate of the first tile in the column - * @param pitch Number of pixels to advance in the screen buffer each time a pixel is written. - * @param reps Number of lines to draw - * @param start_pos Position of first pixel to draw. - * @param end_pos Position of last pixel to draw (exclusive). - * @param blitter current blitter - * @note If pixel position is below \c 0, skip drawing. - */ -void SmallMapWindow::DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const -{ - void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height); - uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0; + /** + * Determine the tile relative to the base tile of the smallmap, and the pixel position at + * that tile for a point in the smallmap. + * @param px Horizontal coordinate of the pixel. + * @param py Vertical coordinate of the pixel. + * @param[out] sub Pixel position at the tile (0..3). + * @param add_sub Add current #subscroll to the position. + * @return Tile being displayed at the given position relative to #scroll_x and #scroll_y. + * @note The #subscroll offset is already accounted for. + */ + Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const + { + if (add_sub) px += this->subscroll; // Total horizontal offset. - do { - /* Check if the tile (xc,yc) is within the map range */ - if (xc >= Map::MaxX() || yc >= Map::MaxY()) continue; + /* For each two rows down, add a x and a y tile, and + * For each four pixels to the right, move a tile to the right. */ + Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom}; + px &= 3; - /* Check if the dst pointer points to a pixel inside the screen buffer */ - if (dst < _screen.dst_ptr) continue; - if (dst >= dst_ptr_abs_end) continue; + if (py & 1) { // Odd number of rows, handle the 2 pixel shift. + if (px < 2) { + pt.x += this->zoom; + px += 2; + } else { + pt.y += this->zoom; + px -= 2; + } + } - /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */ - TileArea ta; - if (min_xy == 1 && (xc == 0 || yc == 0)) { - if (this->zoom == 1) continue; // The tile area is empty, don't draw anything. + *sub = px; + return pt; + } - ta = TileArea(TileXY(std::max(min_xy, xc), std::max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0)); + /** + * Compute base parameters of the smallmap such that tile (\a tx, \a ty) starts at pixel (\a x, \a y). + * @param tx Tile x coordinate. + * @param ty Tile y coordinate. + * @param x Non-negative horizontal position in the display where the tile starts. + * @param y Non-negative vertical position in the display where the tile starts. + * @param[out] sub Value of #subscroll needed. + * @return #scroll_x, #scroll_y values. + */ + Point ComputeScroll(int tx, int ty, int x, int y, int *sub) const + { + assert(x >= 0 && y >= 0); + + int new_sub; + Point tile_xy = PixelToTile(x, y, &new_sub, false); + tx -= tile_xy.x; + ty -= tile_xy.y; + + Point scroll; + if (new_sub == 0) { + *sub = 0; + scroll.x = (tx + this->zoom) * TILE_SIZE; + scroll.y = (ty - this->zoom) * TILE_SIZE; } else { - ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom); - } - ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!). - - uint32_t val = this->GetTileColours(ta); - uint8_t *val8 = (uint8_t *)&val; - int idx = std::max(0, -start_pos); - for (int pos = std::max(0, start_pos); pos < end_pos; pos++) { - blitter->SetPixel(dst, idx, 0, val8[idx]); - idx++; + *sub = 4 - new_sub; + scroll.x = (tx + 2 * this->zoom) * TILE_SIZE; + scroll.y = (ty - 2 * this->zoom) * TILE_SIZE; } - /* Switch to next tile in the column */ - } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0); -} + return scroll; + } -/** - * Adds vehicles to the smallmap. - * @param dpi the part of the smallmap to be drawn into - * @param blitter current blitter - */ -void SmallMapWindow::DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const -{ - for (const Vehicle *v : Vehicle::Iterate()) { - if (v->type == VEH_EFFECT) continue; - if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue; - - /* Remap into flat coordinates. */ - Point pt = this->RemapTile(v->x_pos / (int)TILE_SIZE, v->y_pos / (int)TILE_SIZE); - - int y = pt.y - dpi->top; - if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds. - - bool skip = false; // Default is to draw both pixels. - int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate. - if (x < 0) { - /* if x+1 is 0, that means we're on the very left edge, - * and should thus only draw a single pixel */ - if (++x != 0) continue; - skip = true; - } else if (x >= dpi->width - 1) { - /* Check if we're at the very right edge, and if so draw only a single pixel */ - if (x != dpi->width - 1) continue; - skip = true; + /** + * Initialize or change the zoom level. + * @param change Way to change the zoom level. + * @param zoom_pt Position to keep fixed while zooming. + * @pre \c *zoom_pt should contain a point in the smallmap display when zooming in or out. + */ + void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt) + { + static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away). + static const int MIN_ZOOM_INDEX = 0; + static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1; + + int new_index, cur_index, sub; + Point tile; + switch (change) { + case ZLC_INITIALIZE: + cur_index = - 1; // Definitely different from new_index. + new_index = MIN_ZOOM_INDEX; + tile.x = tile.y = 0; + break; + + case ZLC_ZOOM_IN: + case ZLC_ZOOM_OUT: + for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) { + if (this->zoom == zoomlevels[cur_index]) break; + } + assert(cur_index <= MAX_ZOOM_INDEX); + + tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); + new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX); + break; + + default: NOT_REACHED(); } - /* Calculate pointer to pixel and the colour */ - byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE; + if (new_index != cur_index) { + this->zoom = zoomlevels[new_index]; + if (cur_index >= 0) { + Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); + this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE, + this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub); + } else if (this->map_type == SMT_LINKSTATS) { + this->overlay->SetDirty(); + } + this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]); + this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]); + this->SetDirty(); + } + } - /* And draw either one or two pixels depending on clipping */ - blitter->SetPixel(dpi->dst_ptr, x, y, colour); - if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour); + /** + * Set the link graph overlay cargo mask from the legend. + */ + void SetOverlayCargoMask() + { + CargoTypes cargo_mask = 0; + for (int i = 0; i != _smallmap_cargo_count; ++i) { + if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type); + } + this->overlay->SetCargoMask(cargo_mask); } -} -/** - * Adds town names to the smallmap. - * @param dpi the part of the smallmap to be drawn into - */ -void SmallMapWindow::DrawTowns(const DrawPixelInfo *dpi) const -{ - for (const Town *t : Town::Iterate()) { - /* Remap the town coordinate */ - Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy)); - int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1); - int y = pt.y; - - /* Check if the town sign is within bounds */ - if (x + t->cache.sign.width_small > dpi->left && - x < dpi->left + dpi->width && - y + FONT_HEIGHT_SMALL > dpi->top && - y < dpi->top + dpi->height) { - /* And draw it. */ - SetDParam(0, t->index); - DrawString(x, x + t->cache.sign.width_small, y, STR_SMALLMAP_TOWN); + /** + * Function to set up widgets depending on the information being shown on the smallmap. + */ + void SetupWidgetData() + { + StringID legend_tooltip; + StringID enable_all_tooltip; + StringID disable_all_tooltip; + int plane; + switch (this->map_type) { + case SMT_INDUSTRY: + legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION; + enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES; + disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES; + plane = 0; + break; + + case SMT_OWNER: + legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION; + enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES; + disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES; + plane = 0; + break; + + case SMT_LINKSTATS: + legend_tooltip = STR_SMALLMAP_TOOLTIP_CARGO_SELECTION; + enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS; + disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS; + plane = 0; + break; + + default: + legend_tooltip = STR_NULL; + enable_all_tooltip = STR_NULL; + disable_all_tooltip = STR_NULL; + plane = 1; + break; } + + this->GetWidget(WID_SM_LEGEND)->SetDataTip(STR_NULL, legend_tooltip); + this->GetWidget(WID_SM_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip); + this->GetWidget(WID_SM_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip); + this->GetWidget(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(plane); } -} -/** - * Adds map indicators to the smallmap. - */ -void SmallMapWindow::DrawMapIndicators() const -{ - /* Find main viewport. */ - const Viewport *vp = GetMainWindow()->viewport; + /** + * Decide which colours to show to the user for a group of tiles. + * @param ta Tile area to investigate. + * @return Colours to display. + */ + uint32_t GetTileColours(const TileArea &ta) const + { + int importance = 0; + TileIndex tile = INVALID_TILE; // Position of the most important tile. + TileType et = MP_VOID; // Effective tile type at that position. - Point upper_left_smallmap_coord = InverseRemapCoords2(vp->virtual_left, vp->virtual_top); - Point lower_right_smallmap_coord = InverseRemapCoords2(vp->virtual_left + vp->virtual_width - 1, vp->virtual_top + vp->virtual_height - 1); + for (TileIndex ti : ta) { + TileType ttype = GetTileType(ti); - Point upper_left = this->RemapTile(upper_left_smallmap_coord.x / (int)TILE_SIZE, upper_left_smallmap_coord.y / (int)TILE_SIZE); - upper_left.x -= this->subscroll; + switch (ttype) { + case MP_TUNNELBRIDGE: { + TransportType tt = GetTunnelBridgeTransportType(ti); - Point lower_right = this->RemapTile(lower_right_smallmap_coord.x / (int)TILE_SIZE, lower_right_smallmap_coord.y / (int)TILE_SIZE); - lower_right.x -= this->subscroll; + switch (tt) { + case TRANSPORT_RAIL: ttype = MP_RAILWAY; break; + case TRANSPORT_ROAD: ttype = MP_ROAD; break; + default: ttype = MP_WATER; break; + } + break; + } - SmallMapWindow::DrawVertMapIndicator(upper_left.x, upper_left.y, lower_right.y); - SmallMapWindow::DrawVertMapIndicator(lower_right.x, upper_left.y, lower_right.y); + case MP_INDUSTRY: + /* Special handling of industries while in "Industries" smallmap view. */ + if (this->map_type == SMT_INDUSTRY) { + /* If industry is allowed to be seen, use its colour on the map. + * This has the highest priority above any value in _tiletype_importance. */ + IndustryType type = Industry::GetByTile(ti)->type; + if (_legend_from_industries[_industry_to_list_pos[type]].show_on_map) { + if (type == _smallmap_industry_highlight) { + if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE); + } else { + return GetIndustrySpec(type)->map_colour * 0x01010101; + } + } + /* Otherwise make it disappear */ + ttype = IsTileOnWater(ti) ? MP_WATER : MP_CLEAR; + } + break; - SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, upper_left.y); - SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, lower_right.y); -} + default: + break; + } -/** - * Draws the small map. - * - * Basically, the small map is draw column of pixels by column of pixels. The pixels - * are drawn directly into the screen buffer. The final map is drawn in multiple passes. - * The passes are: - *
  1. The colours of tiles in the different modes.
  2. - *
  3. Town names (optional)
- * - * @param dpi pointer to pixel to write onto - */ -void SmallMapWindow::DrawSmallMap(DrawPixelInfo *dpi) const -{ - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - AutoRestoreBackup dpi_backup(_cur_dpi, dpi); - - /* Clear it */ - GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK); - - /* Which tile is displayed at (dpi->left, dpi->top)? */ - int dx; - Point tile = this->PixelToTile(dpi->left, dpi->top, &dx); - int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x; - int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y; - - void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); - int x = - dx - 4; - int y = 0; - - for (;;) { - /* Distance from left edge */ - if (x >= -3) { - if (x >= dpi->width) break; // Exit the loop. - - int end_pos = std::min(dpi->width, x + 4); - int reps = (dpi->height - y + 1) / 2; // Number of lines. - if (reps > 0) { - this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter); + if (_tiletype_importance[ttype] > importance) { + importance = _tiletype_importance[ttype]; + tile = ti; + et = ttype; } } - if (y == 0) { - tile_y += this->zoom; - y++; - ptr = blitter->MoveTo(ptr, 0, 1); - } else { - tile_x -= this->zoom; - y--; - ptr = blitter->MoveTo(ptr, 0, -1); + switch (this->map_type) { + case SMT_CONTOUR: + return GetSmallMapContoursPixels(tile, et); + + case SMT_VEHICLES: + return GetSmallMapVehiclesPixels(tile, et); + + case SMT_INDUSTRY: + return GetSmallMapIndustriesPixels(tile, et); + + case SMT_LINKSTATS: + return GetSmallMapLinkStatsPixels(tile, et); + + case SMT_ROUTES: + return GetSmallMapRoutesPixels(tile, et); + + case SMT_VEGETATION: + return GetSmallMapVegetationPixels(tile, et); + + case SMT_OWNER: + return GetSmallMapOwnerPixels(tile, et, IncludeHeightmap::IfEnabled); + + default: NOT_REACHED(); } - ptr = blitter->MoveTo(ptr, 2, 0); - x += 2; } - /* Draw vehicles */ - if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter); - - /* Draw link stat overlay */ - if (this->map_type == SMT_LINKSTATS) this->overlay->Draw(dpi); + /** + * Determines the mouse position on the legend. + * @param pt Mouse position. + * @return Legend item under the mouse. + */ + int GetPositionOnLegend(Point pt) + { + const NWidgetBase *wi = this->GetWidget(WID_SM_LEGEND); + uint line = (pt.y - wi->pos_y - WidgetDimensions::scaled.framerect.top) / FONT_HEIGHT_SMALL; + uint columns = this->GetNumberColumnsLegend(wi->current_x); + uint number_of_rows = this->GetNumberRowsLegend(columns); + if (line >= number_of_rows) return -1; + + bool rtl = _current_text_dir == TD_RTL; + int x = pt.x - wi->pos_x; + if (rtl) x = wi->current_x - x; + uint column = (x - WidgetDimensions::scaled.framerect.left) / this->column_width; + + return (column * number_of_rows) + line; + } - /* Draw town names */ - if (this->show_towns) this->DrawTowns(dpi); + /** Update all the links on the map. */ + void UpdateLinks() + { + if (this->map_type == SMT_LINKSTATS) { + CompanyMask company_mask = this->GetOverlayCompanyMask(); + if (this->overlay->GetCompanyMask() != company_mask) { + this->overlay->SetCompanyMask(company_mask); + } else { + this->overlay->SetDirty(); + } + } + } - /* Draw map indicators */ - this->DrawMapIndicators(); -} + /** Blink the industries (if hover over an industry). */ + void Blink() + { + if (_smallmap_industry_highlight == INVALID_INDUSTRYTYPE) return; -/** - * Function to set up widgets depending on the information being shown on the smallmap. - */ -void SmallMapWindow::SetupWidgetData() -{ - StringID legend_tooltip; - StringID enable_all_tooltip; - StringID disable_all_tooltip; - int plane; - switch (this->map_type) { - case SMT_INDUSTRY: - legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION; - enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES; - disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES; - plane = 0; - break; - - case SMT_OWNER: - legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION; - enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES; - disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES; - plane = 0; - break; - - case SMT_LINKSTATS: - legend_tooltip = STR_SMALLMAP_TOOLTIP_CARGO_SELECTION; - enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS; - disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS; - plane = 0; - break; + _smallmap_industry_highlight_state = !_smallmap_industry_highlight_state; - default: - legend_tooltip = STR_NULL; - enable_all_tooltip = STR_NULL; - disable_all_tooltip = STR_NULL; - plane = 1; - break; + this->UpdateLinks(); + this->SetDirty(); } - this->GetWidget(WID_SM_LEGEND)->SetDataTip(STR_NULL, legend_tooltip); - this->GetWidget(WID_SM_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip); - this->GetWidget(WID_SM_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip); - this->GetWidget(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(plane); -} + /** Force a full refresh of the map. */ + void ForceRefresh() + { + if (_smallmap_industry_highlight != INVALID_INDUSTRYTYPE) return; -SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc) -{ - _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; - this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); - this->InitNested(window_number); - this->LowerWidget(this->map_type + WID_SM_CONTOUR); + this->UpdateLinks(); + this->SetDirty(); + } - this->RebuildColourIndexIfNecessary(); +public: + friend class NWidgetSmallmapDisplay; - this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); + SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc) + { + _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; + this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); + this->InitNested(window_number); + this->LowerWidget(this->map_type + WID_SM_CONTOUR); - this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); + this->RebuildColourIndexIfNecessary(); - this->SetupWidgetData(); + this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); - this->SetZoomLevel(ZLC_INITIALIZE, nullptr); - this->SmallMapCenterOnCurrentPos(); - this->SetOverlayCargoMask(); -} + this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); -SmallMapWindow::~SmallMapWindow() -{ - delete this->overlay; -} + this->SetupWidgetData(); -/* virtual */ void SmallMapWindow::Close([[maybe_unused]] int data) -{ - this->BreakIndustryChainLink(); - this->Window::Close(); -} + this->SetZoomLevel(ZLC_INITIALIZE, nullptr); + this->SmallMapCenterOnCurrentPos(); + this->SetOverlayCargoMask(); + } -/** - * Rebuilds the colour indices used for fast access to the smallmap contour colours based on the heightlevel. - */ -void SmallMapWindow::RebuildColourIndexIfNecessary() -{ - /* Rebuild colour indices if necessary. */ - if (SmallMapWindow::map_height_limit == _settings_game.construction.map_height_limit) return; + virtual ~SmallMapWindow() + { + delete this->overlay; + } - for (uint n = 0; n < lengthof(_heightmap_schemes); n++) { - /* The heights go from 0 up to and including maximum. */ - int heights = _settings_game.construction.map_height_limit + 1; - _heightmap_schemes[n].height_colours = ReallocT(_heightmap_schemes[n].height_colours, heights); + /** + * Center the small map on the current center of the viewport. + */ + void SmallMapCenterOnCurrentPos() + { + const Viewport *vp = GetMainWindow()->viewport; + Point viewport_center = InverseRemapCoords2(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2); - for (int z = 0; z < heights; z++) { - size_t access_index = (_heightmap_schemes[n].colour_count * z) / heights; + int sub; + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + Point sxy = this->ComputeScroll(viewport_center.x / (int)TILE_SIZE, viewport_center.y / (int)TILE_SIZE, + std::max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub); + this->SetNewScroll(sxy.x, sxy.y, sub); + this->SetDirty(); + } - /* Choose colour by mapping the range (0..max heightlevel) on the complete colour table. */ - _heightmap_schemes[n].height_colours[z] = _heightmap_schemes[n].height_colours_base[access_index]; - } + /** + * Get the center of the given station as point on the screen in the smallmap window. + * @param st Station to find in the smallmap. + * @return Point with coordinates of the station. + */ + Point GetStationMiddle(const Station *st) const + { + int x = CenterBounds(st->rect.left, st->rect.right, 0); + int y = CenterBounds(st->rect.top, st->rect.bottom, 0); + Point ret = this->RemapTile(x, y); + + /* Same magic 3 as in DrawVehicles; that's where I got it from. + * No idea what it is, but without it the result looks bad. + */ + ret.x -= 3 + this->subscroll; + return ret; } - SmallMapWindow::map_height_limit = _settings_game.construction.map_height_limit; - BuildLandLegend(); -} + void Close([[maybe_unused]] int data) override + { + this->BreakIndustryChainLink(); + this->Window::Close(); + } -/* virtual */ void SmallMapWindow::SetStringParameters(int widget) const -{ - switch (widget) { - case WID_SM_CAPTION: - SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type); - break; + void SetStringParameters(int widget) const override + { + switch (widget) { + case WID_SM_CAPTION: + SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type); + break; + } } -} -/* virtual */ void SmallMapWindow::OnInit() -{ - uint min_width = 0; - this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS; - this->min_number_of_fixed_rows = lengthof(_linkstat_colours_in_legenda); - for (uint i = 0; i < lengthof(_legend_table); i++) { - uint height = 0; - uint num_columns = 1; - for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) { - StringID str; - if (i == SMT_INDUSTRY) { - SetDParam(0, tbl->legend); - SetDParam(1, IndustryPool::MAX_SIZE); - str = STR_SMALLMAP_INDUSTRY; - } else if (i == SMT_LINKSTATS) { - SetDParam(0, tbl->legend); - str = STR_SMALLMAP_LINKSTATS; - } else if (i == SMT_OWNER) { - if (tbl->company != INVALID_COMPANY) { - if (!Company::IsValidID(tbl->company)) { - /* Rebuild the owner legend. */ - BuildOwnerLegend(); - this->OnInit(); - return; + void OnInit() override + { + uint min_width = 0; + this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS; + this->min_number_of_fixed_rows = lengthof(_linkstat_colours_in_legenda); + for (uint i = 0; i < lengthof(_legend_table); i++) { + uint height = 0; + uint num_columns = 1; + for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) { + StringID str; + if (i == SMT_INDUSTRY) { + SetDParam(0, tbl->legend); + SetDParam(1, IndustryPool::MAX_SIZE); + str = STR_SMALLMAP_INDUSTRY; + } else if (i == SMT_LINKSTATS) { + SetDParam(0, tbl->legend); + str = STR_SMALLMAP_LINKSTATS; + } else if (i == SMT_OWNER) { + if (tbl->company != INVALID_COMPANY) { + if (!Company::IsValidID(tbl->company)) { + /* Rebuild the owner legend. */ + BuildOwnerLegend(); + this->OnInit(); + return; + } + /* Non-fixed legend entries for the owner view. */ + SetDParam(0, tbl->company); + str = STR_SMALLMAP_COMPANY; + } else { + str = tbl->legend; } - /* Non-fixed legend entries for the owner view. */ - SetDParam(0, tbl->company); - str = STR_SMALLMAP_COMPANY; } else { + if (tbl->col_break) { + this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height); + height = 0; + num_columns++; + } + height++; str = tbl->legend; } - } else { - if (tbl->col_break) { - this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height); - height = 0; - num_columns++; - } - height++; - str = tbl->legend; + min_width = std::max(GetStringBoundingBox(str).width, min_width); } - min_width = std::max(GetStringBoundingBox(str).width, min_width); + this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height); + this->min_number_of_columns = std::max(this->min_number_of_columns, num_columns); } - this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height); - this->min_number_of_columns = std::max(this->min_number_of_columns, num_columns); - } - /* Width of the legend blob. */ - this->legend_width = (FONT_HEIGHT_SMALL - ScaleGUITrad(1)) * 8 / 5; + /* Width of the legend blob. */ + this->legend_width = (FONT_HEIGHT_SMALL - ScaleGUITrad(1)) * 8 / 5; - /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */ - this->column_width = min_width + WidgetDimensions::scaled.hsep_normal + this->legend_width + WidgetDimensions::scaled.framerect.Horizontal(); -} + /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */ + this->column_width = min_width + WidgetDimensions::scaled.hsep_normal + this->legend_width + WidgetDimensions::scaled.framerect.Horizontal(); + } -/* virtual */ void SmallMapWindow::OnPaint() -{ - if (this->map_type == SMT_OWNER) { - for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { - if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) { - /* Rebuild the owner legend. */ - BuildOwnerLegend(); - this->InvalidateData(1); - break; + void OnPaint() override + { + if (this->map_type == SMT_OWNER) { + for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { + if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) { + /* Rebuild the owner legend. */ + BuildOwnerLegend(); + this->InvalidateData(1); + break; + } } } - } - this->DrawWidgets(); -} - -/* virtual */ void SmallMapWindow::DrawWidget(const Rect &r, int widget) const -{ - switch (widget) { - case WID_SM_MAP: { - Rect ir = r.Shrink(WidgetDimensions::scaled.bevel); - DrawPixelInfo new_dpi; - if (!FillDrawPixelInfo(&new_dpi, ir.left, ir.top, ir.Width(), ir.Height())) return; - this->DrawSmallMap(&new_dpi); - break; - } + this->DrawWidgets(); + } - case WID_SM_LEGEND: { - uint columns = this->GetNumberColumnsLegend(r.Width()); - uint number_of_rows = this->GetNumberRowsLegend(columns); - bool rtl = _current_text_dir == TD_RTL; - uint i = 0; // Row counter for industry legend. - uint row_height = FONT_HEIGHT_SMALL; - int padding = ScaleGUITrad(1); - - Rect origin = r.WithWidth(this->column_width, rtl).Shrink(WidgetDimensions::scaled.framerect).WithHeight(row_height); - Rect text = origin.Indent(this->legend_width + WidgetDimensions::scaled.hsep_normal, rtl); - Rect icon = origin.WithWidth(this->legend_width, rtl).Shrink(0, padding, 0, 0); - - StringID string = STR_NULL; - switch (this->map_type) { - case SMT_INDUSTRY: - string = STR_SMALLMAP_INDUSTRY; - break; - case SMT_LINKSTATS: - string = STR_SMALLMAP_LINKSTATS; - break; - case SMT_OWNER: - string = STR_SMALLMAP_COMPANY; - break; - default: - break; + void DrawWidget(const Rect &r, int widget) const override + { + switch (widget) { + case WID_SM_MAP: { + Rect ir = r.Shrink(WidgetDimensions::scaled.bevel); + DrawPixelInfo new_dpi; + if (!FillDrawPixelInfo(&new_dpi, ir.left, ir.top, ir.Width(), ir.Height())) return; + this->DrawSmallMap(&new_dpi); + break; } - for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { - if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) { - /* Column break needed, continue at top, COLUMN_WIDTH pixels - * (one "row") to the right. */ - int x = rtl ? -(int)this->column_width : this->column_width; - int y = origin.top - text.top; - text = text.Translate(x, y); - icon = icon.Translate(x, y); - i = 1; - } + case WID_SM_LEGEND: { + uint columns = this->GetNumberColumnsLegend(r.Width()); + uint number_of_rows = this->GetNumberRowsLegend(columns); + bool rtl = _current_text_dir == TD_RTL; + uint i = 0; // Row counter for industry legend. + uint row_height = FONT_HEIGHT_SMALL; + int padding = ScaleGUITrad(1); - uint8_t legend_colour = tbl->colour; + Rect origin = r.WithWidth(this->column_width, rtl).Shrink(WidgetDimensions::scaled.framerect).WithHeight(row_height); + Rect text = origin.Indent(this->legend_width + WidgetDimensions::scaled.hsep_normal, rtl); + Rect icon = origin.WithWidth(this->legend_width, rtl).Shrink(0, padding, 0, 0); + StringID string = STR_NULL; switch (this->map_type) { case SMT_INDUSTRY: - /* Industry name must be formatted, since it's not in tiny font in the specs. - * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */ - SetDParam(0, tbl->legend); - SetDParam(1, Industry::GetIndustryTypeCount(tbl->type)); - if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) { - legend_colour = _smallmap_industry_highlight_state ? PC_WHITE : PC_BLACK; - } - FALLTHROUGH; - + string = STR_SMALLMAP_INDUSTRY; + break; case SMT_LINKSTATS: - SetDParam(0, tbl->legend); - FALLTHROUGH; - + string = STR_SMALLMAP_LINKSTATS; + break; case SMT_OWNER: - if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) { - if (this->map_type == SMT_OWNER) SetDParam(0, tbl->company); - if (!tbl->show_on_map) { - /* Simply draw the string, not the black border of the legend colour. - * This will enforce the idea of the disabled item */ - DrawString(text, string, TC_GREY); - } else { - DrawString(text, string, TC_BLACK); - GfxFillRect(icon, PC_BLACK); // Outer border of the legend colour - } - break; - } - FALLTHROUGH; - + string = STR_SMALLMAP_COMPANY; + break; default: - if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); - /* Anything that is not an industry or a company is using normal process */ - GfxFillRect(icon, PC_BLACK); - DrawString(text, tbl->legend); break; } - GfxFillRect(icon.Shrink(WidgetDimensions::scaled.bevel), legend_colour); // Legend colour - text = text.Translate(0, row_height); - icon = icon.Translate(0, row_height); - } - } - } -} - -/** - * Select a new map type. - * @param map_type New map type. - */ -void SmallMapWindow::SwitchMapType(SmallMapType map_type) -{ - this->RaiseWidget(this->map_type + WID_SM_CONTOUR); - this->map_type = map_type; - this->LowerWidget(this->map_type + WID_SM_CONTOUR); + for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { + if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) { + /* Column break needed, continue at top, COLUMN_WIDTH pixels + * (one "row") to the right. */ + int x = rtl ? -(int)this->column_width : this->column_width; + int y = origin.top - text.top; + text = text.Translate(x, y); + icon = icon.Translate(x, y); + i = 1; + } - this->SetupWidgetData(); + uint8_t legend_colour = tbl->colour; - if (map_type == SMT_LINKSTATS) this->overlay->SetDirty(); - if (map_type != SMT_INDUSTRY) this->BreakIndustryChainLink(); - this->SetDirty(); -} + switch (this->map_type) { + case SMT_INDUSTRY: + /* Industry name must be formatted, since it's not in tiny font in the specs. + * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */ + SetDParam(0, tbl->legend); + SetDParam(1, Industry::GetIndustryTypeCount(tbl->type)); + if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) { + legend_colour = _smallmap_industry_highlight_state ? PC_WHITE : PC_BLACK; + } + FALLTHROUGH; + + case SMT_LINKSTATS: + SetDParam(0, tbl->legend); + FALLTHROUGH; + + case SMT_OWNER: + if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) { + if (this->map_type == SMT_OWNER) SetDParam(0, tbl->company); + if (!tbl->show_on_map) { + /* Simply draw the string, not the black border of the legend colour. + * This will enforce the idea of the disabled item */ + DrawString(text, string, TC_GREY); + } else { + DrawString(text, string, TC_BLACK); + GfxFillRect(icon, PC_BLACK); // Outer border of the legend colour + } + break; + } + FALLTHROUGH; -/** - * Get the number of rows in the legend from the number of columns. Those - * are at least min_number_of_fixed_rows and possibly more if there are so - * many cargoes, industry types or companies that they won't fit in the - * available space. - * @param columns Number of columns in the legend. - * @return Number of rows needed for everything to fit in. - */ -inline uint SmallMapWindow::GetNumberRowsLegend(uint columns) const -{ - /* Reserve one column for link colours */ - uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1); - uint num_rows_others = CeilDiv(std::max(_smallmap_industry_count, _smallmap_company_count), columns); - return std::max({this->min_number_of_fixed_rows, num_rows_linkstats, num_rows_others}); -} + default: + if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); + /* Anything that is not an industry or a company is using normal process */ + GfxFillRect(icon, PC_BLACK); + DrawString(text, tbl->legend); + break; + } + GfxFillRect(icon.Shrink(WidgetDimensions::scaled.bevel), legend_colour); // Legend colour -/** - * Select and toggle a legend item. When CTRL is pressed, disable all other - * items in the group defined by begin_legend_item and end_legend_item and - * keep the clicked one enabled even if it was already enabled before. If - * the other items in the group are all disabled already and CTRL is pressed - * enable them instead. - * @param click_pos the index of the item being selected - * @param legend the legend from which we select - * @param end_legend_item index one past the last item in the group to be inverted - * @param begin_legend_item index of the first item in the group to be inverted - */ -void SmallMapWindow::SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item) -{ - if (_ctrl_pressed) { - /* Disable all, except the clicked one */ - bool changes = false; - for (int i = begin_legend_item; i != end_legend_item; i++) { - bool new_state = (i == click_pos); - if (legend[i].show_on_map != new_state) { - changes = true; - legend[i].show_on_map = new_state; - } - } - if (!changes) { - /* Nothing changed? Then show all (again). */ - for (int i = begin_legend_item; i != end_legend_item; i++) { - legend[i].show_on_map = true; + text = text.Translate(0, row_height); + icon = icon.Translate(0, row_height); + } } } - } else { - legend[click_pos].show_on_map = !legend[click_pos].show_on_map; } - if (this->map_type == SMT_INDUSTRY) this->BreakIndustryChainLink(); -} + void OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) override + { + switch (widget) { + case WID_SM_MAP: { // Map window + if (click_count > 0) this->mouse_capture_widget = widget; -/** - * Set the link graph overlay cargo mask from the legend. - */ -void SmallMapWindow::SetOverlayCargoMask() -{ - CargoTypes cargo_mask = 0; - for (int i = 0; i != _smallmap_cargo_count; ++i) { - if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type); - } - this->overlay->SetCargoMask(cargo_mask); -} + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + Window *w = GetMainWindow(); + int sub; + pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub); + ScrollWindowTo(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, -1, w); -/** - * Determines the mouse position on the legend. - * @param pt Mouse position. - * @return Legend item under the mouse. - */ -int SmallMapWindow::GetPositionOnLegend(Point pt) -{ - const NWidgetBase *wi = this->GetWidget(WID_SM_LEGEND); - uint line = (pt.y - wi->pos_y - WidgetDimensions::scaled.framerect.top) / FONT_HEIGHT_SMALL; - uint columns = this->GetNumberColumnsLegend(wi->current_x); - uint number_of_rows = this->GetNumberRowsLegend(columns); - if (line >= number_of_rows) return -1; - - bool rtl = _current_text_dir == TD_RTL; - int x = pt.x - wi->pos_x; - if (rtl) x = wi->current_x - x; - uint column = (x - WidgetDimensions::scaled.framerect.left) / this->column_width; - - return (column * number_of_rows) + line; -} + this->SetDirty(); + break; + } -/* virtual */ void SmallMapWindow::OnMouseOver([[maybe_unused]] Point pt, int widget) -{ - IndustryType new_highlight = INVALID_INDUSTRYTYPE; - if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) { - int industry_pos = GetPositionOnLegend(pt); - if (industry_pos >= 0 && industry_pos < _smallmap_industry_count) { - new_highlight = _legend_from_industries[industry_pos].type; - } - } - if (new_highlight != _smallmap_industry_highlight) { - _smallmap_industry_highlight = new_highlight; - _smallmap_industry_highlight_state = true; - this->SetDirty(); - } -} + case WID_SM_ZOOM_IN: + case WID_SM_ZOOM_OUT: { + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + Point zoom_pt = { (int)wid->current_x / 2, (int)wid->current_y / 2}; + this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &zoom_pt); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; + } -/* virtual */ void SmallMapWindow::OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) -{ - switch (widget) { - case WID_SM_MAP: { // Map window - if (click_count > 0) this->mouse_capture_widget = widget; + case WID_SM_CONTOUR: // Show land contours + case WID_SM_VEHICLES: // Show vehicles + case WID_SM_INDUSTRIES: // Show industries + case WID_SM_LINKSTATS: // Show route map + case WID_SM_ROUTES: // Show transport routes + case WID_SM_VEGETATION: // Show vegetation + case WID_SM_OWNERS: // Show land owners + this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR)); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - Window *w = GetMainWindow(); - int sub; - pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub); - ScrollWindowTo(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, -1, w); + case WID_SM_CENTERMAP: // Center the smallmap again + this->SmallMapCenterOnCurrentPos(); + this->HandleButtonClick(WID_SM_CENTERMAP); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; - this->SetDirty(); - break; - } + case WID_SM_TOGGLETOWNNAME: // Toggle town names + this->show_towns = !this->show_towns; + this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); - case WID_SM_ZOOM_IN: - case WID_SM_ZOOM_OUT: { - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - Point zoom_pt = { (int)wid->current_x / 2, (int)wid->current_y / 2}; - this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &zoom_pt); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - } + this->SetDirty(); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + break; - case WID_SM_CONTOUR: // Show land contours - case WID_SM_VEHICLES: // Show vehicles - case WID_SM_INDUSTRIES: // Show industries - case WID_SM_LINKSTATS: // Show route map - case WID_SM_ROUTES: // Show transport routes - case WID_SM_VEGETATION: // Show vegetation - case WID_SM_OWNERS: // Show land owners - this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR)); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - - case WID_SM_CENTERMAP: // Center the smallmap again - this->SmallMapCenterOnCurrentPos(); - this->HandleButtonClick(WID_SM_CENTERMAP); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - - case WID_SM_TOGGLETOWNNAME: // Toggle town names - this->show_towns = !this->show_towns; - this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); + case WID_SM_LEGEND: // Legend + if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) { + int click_pos = this->GetPositionOnLegend(pt); + if (click_pos < 0) break; - this->SetDirty(); - if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - break; - - case WID_SM_LEGEND: // Legend - if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) { - int click_pos = this->GetPositionOnLegend(pt); - if (click_pos < 0) break; - - /* If industry type small map*/ - if (this->map_type == SMT_INDUSTRY) { - /* If click on industries label, find right industry type and enable/disable it. */ - if (click_pos < _smallmap_industry_count) { - this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count); - } - } else if (this->map_type == SMT_LINKSTATS) { - if (click_pos < _smallmap_cargo_count) { - this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count); - this->SetOverlayCargoMask(); - } - } else if (this->map_type == SMT_OWNER) { - if (click_pos < _smallmap_company_count) { - this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES); + /* If industry type small map*/ + if (this->map_type == SMT_INDUSTRY) { + /* If click on industries label, find right industry type and enable/disable it. */ + if (click_pos < _smallmap_industry_count) { + this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count); + } + } else if (this->map_type == SMT_LINKSTATS) { + if (click_pos < _smallmap_cargo_count) { + this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count); + this->SetOverlayCargoMask(); + } + } else if (this->map_type == SMT_OWNER) { + if (click_pos < _smallmap_company_count) { + this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES); + } } + this->SetDirty(); } + break; + + case WID_SM_ENABLE_ALL: + case WID_SM_DISABLE_ALL: { + LegendAndColour *tbl = nullptr; + switch (this->map_type) { + case SMT_INDUSTRY: + tbl = _legend_from_industries; + this->BreakIndustryChainLink(); + break; + case SMT_OWNER: + tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]); + break; + case SMT_LINKSTATS: + tbl = _legend_linkstats; + break; + default: + NOT_REACHED(); + } + for (;!tbl->end && tbl->legend != STR_LINKGRAPH_LEGEND_UNUSED; ++tbl) { + tbl->show_on_map = (widget == WID_SM_ENABLE_ALL); + } + if (this->map_type == SMT_LINKSTATS) this->SetOverlayCargoMask(); this->SetDirty(); + break; } - break; - - case WID_SM_ENABLE_ALL: - case WID_SM_DISABLE_ALL: { - LegendAndColour *tbl = nullptr; - switch (this->map_type) { - case SMT_INDUSTRY: - tbl = _legend_from_industries; - this->BreakIndustryChainLink(); - break; - case SMT_OWNER: - tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]); - break; - case SMT_LINKSTATS: - tbl = _legend_linkstats; - break; - default: - NOT_REACHED(); - } - for (;!tbl->end && tbl->legend != STR_LINKGRAPH_LEGEND_UNUSED; ++tbl) { - tbl->show_on_map = (widget == WID_SM_ENABLE_ALL); - } - if (this->map_type == SMT_LINKSTATS) this->SetOverlayCargoMask(); - this->SetDirty(); - break; - } - case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap. - _smallmap_show_heightmap = !_smallmap_show_heightmap; - this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); - this->SetDirty(); - break; + case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap. + _smallmap_show_heightmap = !_smallmap_show_heightmap; + this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); + this->SetDirty(); + break; + } } -} -/** - * Some data on this window has become invalid. - * @param data Information about the changed data. - * - data = 0: Displayed industries at the industry chain window have changed. - * - data = 1: Companies have changed. - * - data = 2: Cheat changing the maximum heightlevel has been used, rebuild our heightlevel-to-colour index - * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. - */ -/* virtual */ void SmallMapWindow::OnInvalidateData(int data, bool gui_scope) -{ - if (!gui_scope) return; + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * - data = 0: Displayed industries at the industry chain window have changed. + * - data = 1: Companies have changed. + * - data = 2: Cheat changing the maximum heightlevel has been used, rebuild our heightlevel-to-colour index + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + void OnInvalidateData(int data = 0, bool gui_scope = true) override + { + if (!gui_scope) return; - switch (data) { - case 1: - /* The owner legend has already been rebuilt. */ - this->ReInit(); - break; + switch (data) { + case 1: + /* The owner legend has already been rebuilt. */ + this->ReInit(); + break; - case 0: { - extern std::bitset _displayed_industries; - if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY); + case 0: { + extern std::bitset _displayed_industries; + if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY); - for (int i = 0; i != _smallmap_industry_count; i++) { - _legend_from_industries[i].show_on_map = _displayed_industries.test(_legend_from_industries[i].type); + for (int i = 0; i != _smallmap_industry_count; i++) { + _legend_from_industries[i].show_on_map = _displayed_industries.test(_legend_from_industries[i].type); + } + break; } - break; - } - case 2: - this->RebuildColourIndexIfNecessary(); - break; + case 2: + this->RebuildColourIndexIfNecessary(); + break; - default: NOT_REACHED(); + default: NOT_REACHED(); + } + this->SetDirty(); } - this->SetDirty(); -} -/* virtual */ bool SmallMapWindow::OnRightClick([[maybe_unused]] Point pt, int widget) -{ - if (widget != WID_SM_MAP || _scrolling_viewport) return false; - - _scrolling_viewport = true; - return true; -} + bool OnRightClick(Point, int widget) override + { + if (widget != WID_SM_MAP || _scrolling_viewport) return false; -/* virtual */ void SmallMapWindow::OnMouseWheel(int wheel) -{ - if (_settings_client.gui.scrollwheel_scrolling != 2) { - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - int cursor_x = _cursor.pos.x - this->left - wid->pos_x; - int cursor_y = _cursor.pos.y - this->top - wid->pos_y; - if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) { - Point pt = {cursor_x, cursor_y}; - this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); - } + _scrolling_viewport = true; + return true; } -} -/** Update all the links on the map. */ -void SmallMapWindow::UpdateLinks() -{ - if (this->map_type == SMT_LINKSTATS) { - CompanyMask company_mask = this->GetOverlayCompanyMask(); - if (this->overlay->GetCompanyMask() != company_mask) { - this->overlay->SetCompanyMask(company_mask); - } else { - this->overlay->SetDirty(); + void OnMouseWheel(int wheel) override + { + if (_settings_client.gui.scrollwheel_scrolling != 2) { + const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); + int cursor_x = _cursor.pos.x - this->left - wid->pos_x; + int cursor_y = _cursor.pos.y - this->top - wid->pos_y; + if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) { + Point pt = {cursor_x, cursor_y}; + this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); + } } } -} - -/** Blink the industries (if hover over an industry). */ -void SmallMapWindow::Blink() -{ - if (_smallmap_industry_highlight == INVALID_INDUSTRYTYPE) return; - - _smallmap_industry_highlight_state = !_smallmap_industry_highlight_state; - - this->UpdateLinks(); - this->SetDirty(); -} -/** Force a full refresh of the map. */ -void SmallMapWindow::ForceRefresh() -{ - if (_smallmap_industry_highlight != INVALID_INDUSTRYTYPE) return; + void OnScroll(Point delta) override + { + if (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED) _cursor.fix_at = true; - this->UpdateLinks(); - this->SetDirty(); -} + /* While tile is at (delta.x, delta.y)? */ + int sub; + Point pt = this->PixelToTile(delta.x, delta.y, &sub); + this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub); -/** - * Set new #scroll_x, #scroll_y, and #subscroll values after limiting them such that the center - * of the smallmap always contains a part of the map. - * @param sx Proposed new #scroll_x - * @param sy Proposed new #scroll_y - * @param sub Proposed new #subscroll - */ -void SmallMapWindow::SetNewScroll(int sx, int sy, int sub) -{ - const NWidgetBase *wi = this->GetWidget(WID_SM_MAP); - Point hv = InverseRemapCoords(wi->current_x * ZOOM_LVL_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_LVL_BASE * TILE_SIZE / 2); - hv.x *= this->zoom; - hv.y *= this->zoom; - - if (sx < -hv.x) { - sx = -hv.x; - sub = 0; - } - if (sx > (int)(Map::MaxX() * TILE_SIZE) - hv.x) { - sx = Map::MaxX() * TILE_SIZE - hv.x; - sub = 0; - } - if (sy < -hv.y) { - sy = -hv.y; - sub = 0; - } - if (sy > (int)(Map::MaxY() * TILE_SIZE) - hv.y) { - sy = Map::MaxY() * TILE_SIZE - hv.y; - sub = 0; + this->SetDirty(); } - this->scroll_x = sx; - this->scroll_y = sy; - this->subscroll = sub; - if (this->map_type == SMT_LINKSTATS) this->overlay->SetDirty(); -} - -/* virtual */ void SmallMapWindow::OnScroll(Point delta) -{ - if (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED) _cursor.fix_at = true; - - /* While tile is at (delta.x, delta.y)? */ - int sub; - Point pt = this->PixelToTile(delta.x, delta.y, &sub); - this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub); - - this->SetDirty(); -} - -/** - * Center the small map on the current center of the viewport. - */ -void SmallMapWindow::SmallMapCenterOnCurrentPos() -{ - const Viewport *vp = GetMainWindow()->viewport; - Point viewport_center = InverseRemapCoords2(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2); - - int sub; - const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); - Point sxy = this->ComputeScroll(viewport_center.x / (int)TILE_SIZE, viewport_center.y / (int)TILE_SIZE, - std::max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub); - this->SetNewScroll(sxy.x, sxy.y, sub); - this->SetDirty(); -} - -/** - * Get the center of the given station as point on the screen in the smallmap window. - * @param st Station to find in the smallmap. - * @return Point with coordinates of the station. - */ -Point SmallMapWindow::GetStationMiddle(const Station *st) const -{ - int x = CenterBounds(st->rect.left, st->rect.right, 0); - int y = CenterBounds(st->rect.top, st->rect.bottom, 0); - Point ret = this->RemapTile(x, y); + void OnMouseOver([[maybe_unused]] Point pt, int widget) override + { + IndustryType new_highlight = INVALID_INDUSTRYTYPE; + if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) { + int industry_pos = GetPositionOnLegend(pt); + if (industry_pos >= 0 && industry_pos < _smallmap_industry_count) { + new_highlight = _legend_from_industries[industry_pos].type; + } + } + if (new_highlight != _smallmap_industry_highlight) { + _smallmap_industry_highlight = new_highlight; + _smallmap_industry_highlight_state = true; + this->SetDirty(); + } + } - /* Same magic 3 as in DrawVehicles; that's where I got it from. - * No idea what it is, but without it the result looks bad. - */ - ret.x -= 3 + this->subscroll; - return ret; -} +}; SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR; bool SmallMapWindow::show_towns = true; diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h index e051f788a8..9285f00d97 100644 --- a/src/smallmap_gui.h +++ b/src/smallmap_gui.h @@ -37,181 +37,6 @@ enum class IncludeHeightmap { uint32_t GetSmallMapOwnerPixels(TileIndex tile, TileType t, IncludeHeightmap include_heightmap); -/** Structure for holding relevant data for legends in small map */ -struct LegendAndColour { - uint8_t colour; ///< Colour of the item on the map. - StringID legend; ///< String corresponding to the coloured item. - IndustryType type; ///< Type of industry. Only valid for industry entries. - uint8_t height; ///< Height in tiles. Only valid for height legend entries. - CompanyID company; ///< Company to display. Only valid for company entries of the owner legend. - bool show_on_map; ///< For filtering industries, if \c true, industry is shown on the map in colour. - bool end; ///< This is the end of the list. - bool col_break; ///< Perform a column break and go further at the next column. -}; - -/** Class managing the smallmap window. */ -class SmallMapWindow : public Window { -protected: - /** Types of legends in the #WID_SM_LEGEND widget. */ - enum SmallMapType { - SMT_CONTOUR, - SMT_VEHICLES, - SMT_INDUSTRY, - SMT_LINKSTATS, - SMT_ROUTES, - SMT_VEGETATION, - SMT_OWNER, - }; - - /** Available kinds of zoomlevel changes. */ - enum ZoomLevelChange { - ZLC_INITIALIZE, ///< Initialize zoom level. - ZLC_ZOOM_OUT, ///< Zoom out. - ZLC_ZOOM_IN, ///< Zoom in. - }; - - static SmallMapType map_type; ///< Currently displayed legends. - static bool show_towns; ///< Display town names in the smallmap. - static int map_height_limit; ///< Currently used/cached map height limit. - - static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; ///< Minimal number of columns in the #WID_SM_LEGEND widget for the #SMT_INDUSTRY legend. - - uint min_number_of_columns; ///< Minimal number of columns in legends. - uint min_number_of_fixed_rows; ///< Minimal number of rows in the legends for the fixed layouts only (all except #SMT_INDUSTRY). - uint column_width; ///< Width of a column in the #WID_SM_LEGEND widget. - uint legend_width; ///< Width of legend 'blob'. - - int32_t scroll_x; ///< Horizontal world coordinate of the base tile left of the top-left corner of the smallmap display. - int32_t scroll_y; ///< Vertical world coordinate of the base tile left of the top-left corner of the smallmap display. - int32_t subscroll; ///< Number of pixels (0..3) between the right end of the base tile and the pixel at the top-left corner of the smallmap display. - int zoom; ///< Zoom level. Bigger number means more zoom-out (further away). - - LinkGraphOverlay *overlay; - - static void BreakIndustryChainLink(); - Point SmallmapRemapCoords(int x, int y) const; - - /** - * Draws vertical part of map indicator - * @param x X coord of left/right border of main viewport - * @param y Y coord of top border of main viewport - * @param y2 Y coord of bottom border of main viewport - */ - static inline void DrawVertMapIndicator(int x, int y, int y2) - { - GfxFillRect(x, y, x, y + 3, PC_VERY_LIGHT_YELLOW); - GfxFillRect(x, y2 - 3, x, y2, PC_VERY_LIGHT_YELLOW); - } - - /** - * Draws horizontal part of map indicator - * @param x X coord of left border of main viewport - * @param x2 X coord of right border of main viewport - * @param y Y coord of top/bottom border of main viewport - */ - static inline void DrawHorizMapIndicator(int x, int x2, int y) - { - GfxFillRect(x, y, x + 3, y, PC_VERY_LIGHT_YELLOW); - GfxFillRect(x2 - 3, y, x2, y, PC_VERY_LIGHT_YELLOW); - } - - /** - * Compute minimal required width of the legends. - * @return Minimally needed width for displaying the smallmap legends in pixels. - */ - inline uint GetMinLegendWidth() const - { - return WidgetDimensions::scaled.framerect.left + this->min_number_of_columns * this->column_width; - } - - /** - * Return number of columns that can be displayed in \a width pixels. - * @return Number of columns to display. - */ - inline uint GetNumberColumnsLegend(uint width) const - { - return width / this->column_width; - } - - /** - * Compute height given a number of columns. - * @param num_columns Number of columns. - * @return Needed height for displaying the smallmap legends in pixels. - */ - inline uint GetLegendHeight(uint num_columns) const - { - return WidgetDimensions::scaled.framerect.Vertical() + - this->GetNumberRowsLegend(num_columns) * FONT_HEIGHT_SMALL; - } - - /** - * Get a bitmask for company links to be displayed. Usually this will be - * the _local_company. Spectators get to see all companies' links. - * @return Company mask. - */ - inline CompanyMask GetOverlayCompanyMask() const - { - return Company::IsValidID(_local_company) ? 1U << _local_company : MAX_UVALUE(CompanyMask); - } - - /** Blink the industries (if selected) on a regular interval. */ - IntervalTimer blink_interval = {std::chrono::milliseconds(450), [this](auto) { - Blink(); - }}; - - /** Update the whole map on a regular interval. */ - IntervalTimer refresh_interval = {std::chrono::milliseconds(930), [this](auto) { - ForceRefresh(); - }}; - - void RebuildColourIndexIfNecessary(); - uint GetNumberRowsLegend(uint columns) const; - void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0); - void SwitchMapType(SmallMapType map_type); - void SetNewScroll(int sx, int sy, int sub); - - void DrawMapIndicators() const; - void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const; - void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const; - void DrawTowns(const DrawPixelInfo *dpi) const; - void DrawSmallMap(DrawPixelInfo *dpi) const; - - Point RemapTile(int tile_x, int tile_y) const; - Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const; - Point ComputeScroll(int tx, int ty, int x, int y, int *sub); - void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt); - void SetOverlayCargoMask(); - void SetupWidgetData(); - uint32_t GetTileColours(const TileArea &ta) const; - - int GetPositionOnLegend(Point pt); - - void UpdateLinks(); - void Blink(); - void ForceRefresh(); - -public: - friend class NWidgetSmallmapDisplay; - - SmallMapWindow(WindowDesc *desc, int window_number); - virtual ~SmallMapWindow(); - - void SmallMapCenterOnCurrentPos(); - Point GetStationMiddle(const Station *st) const; - - void Close([[maybe_unused]] int data = 0) override; - void SetStringParameters(int widget) const override; - void OnInit() override; - void OnPaint() override; - void DrawWidget(const Rect &r, int widget) const override; - void OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) override; - void OnInvalidateData(int data = 0, bool gui_scope = true) override; - bool OnRightClick(Point pt, int widget) override; - void OnMouseWheel(int wheel) override; - void OnScroll(Point delta) override; - void OnMouseOver([[maybe_unused]] Point pt, int widget) override; -}; - Point GetSmallMapStationMiddle(const Window *w, const Station *st); #endif /* SMALLMAP_GUI_H */ From 53845bc024230dec47742e1e3f613e2b204463e3 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 02:07:29 +0000 Subject: [PATCH 17/57] Codechange: Move includes to correct place. Some other source file inadvertently included things via smallmap_gui.h --- src/linkgraph/linkgraph_gui.cpp | 2 ++ src/settings_table.cpp | 2 ++ src/smallmap_gui.cpp | 7 ++++++- src/smallmap_gui.h | 13 ++++--------- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index 18337ffa18..e94ba9786c 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -19,6 +19,8 @@ #include "../smallmap_gui.h" #include "../core/geometry_func.hpp" #include "../widgets/link_graph_legend_widget.h" +#include "../strings_func.h" +#include "linkgraph_gui.h" #include "table/strings.h" diff --git a/src/settings_table.cpp b/src/settings_table.cpp index f81bb0721e..e0aed793b2 100644 --- a/src/settings_table.cpp +++ b/src/settings_table.cpp @@ -46,6 +46,8 @@ #include "vehicle_func.h" #include "viewport_func.h" #include "void_map.h" +#include "station_func.h" +#include "station_base.h" #include "table/strings.h" #include "table/settings.h" diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index c4333ad616..e2ec46f9d8 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -23,7 +23,12 @@ #include "window_func.h" #include "company_base.h" #include "zoom_func.h" - +#include "strings_func.h" +#include "blitter/factory.hpp" +#include "linkgraph/linkgraph_gui.h" +#include "widgets/smallmap_widget.h" +#include "timer/timer.h" +#include "timer/timer_window.h" #include "smallmap_gui.h" #include "table/strings.h" diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h index 9285f00d97..8eb6906e31 100644 --- a/src/smallmap_gui.h +++ b/src/smallmap_gui.h @@ -10,15 +10,10 @@ #ifndef SMALLMAP_GUI_H #define SMALLMAP_GUI_H -#include "industry_type.h" -#include "company_base.h" -#include "window_gui.h" -#include "strings_func.h" -#include "blitter/factory.hpp" -#include "linkgraph/linkgraph_gui.h" -#include "widgets/smallmap_widget.h" -#include "timer/timer.h" -#include "timer/timer_window.h" +#include "core/geometry_type.hpp" +#include "station_type.h" +#include "tile_type.h" +#include "window_type.h" /* set up the cargos to be displayed in the smallmap's route legend */ void BuildLinkStatsLegend(); From c687b59efcd56789fb62cbef035aed8089b37098 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 18:53:07 +0000 Subject: [PATCH 18/57] Codechange: Use unique_ptr for SmallMapWindow's overlay. --- src/smallmap_gui.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index e2ec46f9d8..ae2473f4ec 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -648,7 +648,7 @@ protected: int32_t subscroll; ///< Number of pixels (0..3) between the right end of the base tile and the pixel at the top-left corner of the smallmap display. int zoom; ///< Zoom level. Bigger number means more zoom-out (further away). - LinkGraphOverlay *overlay; + std::unique_ptr overlay; /** Notify the industry chain window to stop sending newly selected industries. */ static void BreakIndustryChainLink() @@ -1402,7 +1402,7 @@ public: SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc) { _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; - this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); + this->overlay = std::make_unique(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); this->InitNested(window_number); this->LowerWidget(this->map_type + WID_SM_CONTOUR); @@ -1419,11 +1419,6 @@ public: this->SetOverlayCargoMask(); } - virtual ~SmallMapWindow() - { - delete this->overlay; - } - /** * Center the small map on the current center of the viewport. */ From c6411168d88d02420f31df9bbb58cd9ce73d7434 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 1 Nov 2023 21:46:33 +0100 Subject: [PATCH 19/57] Cleanup: missing spaces before continuation * in some comments --- src/console_gui.cpp | 2 +- src/core/bitmath_func.hpp | 2 +- src/core/kdtree.hpp | 16 ++++++++-------- src/fios.cpp | 6 +++--- src/framerate_gui.cpp | 12 ++++++------ src/framerate_type.h | 10 +++++----- src/music/midi.h | 10 +++++----- src/music/midifile.cpp | 10 +++++----- src/music/midifile.hpp | 10 +++++----- src/network/network_client.cpp | 6 +++--- src/network/network_content.cpp | 2 +- src/newgrf.cpp | 18 +++++++++--------- src/newgrf_roadtype.h | 12 ++++++------ src/os/unix/font_unix.cpp | 4 ++-- src/os/windows/string_uniscribe.h | 24 ++++++++++++------------ src/script/squirrel.cpp | 2 +- src/settings.cpp | 2 +- src/sound/xaudio2_s.cpp | 22 +++++++++++----------- src/terraform_gui.cpp | 2 +- src/tests/test_script_admin.cpp | 2 +- src/timer/timer_game_calendar.h | 16 ++++++++-------- src/vehicle.cpp | 2 +- src/video/cocoa/cocoa_v.mm | 2 +- src/viewport.cpp | 4 ++-- src/viewport_kdtree.h | 10 +++++----- 25 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/console_gui.cpp b/src/console_gui.cpp index d507c3b660..309dcb9a1b 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -457,7 +457,7 @@ void IConsoleGUIPrint(TextColour colour_code, const std::string &str) * all lines in the buffer are aged by one. When a line exceeds both the maximum position * and also the maximum age, it gets removed. * @return true if any lines were removed -*/ + */ static bool TruncateBuffer() { bool need_truncation = false; diff --git a/src/core/bitmath_func.hpp b/src/core/bitmath_func.hpp index 44e81612ca..1e55c1b88e 100644 --- a/src/core/bitmath_func.hpp +++ b/src/core/bitmath_func.hpp @@ -324,7 +324,7 @@ static inline T ROR(const T x, const uint8_t n) * Iterable ensemble of each set bit in a value. * @tparam Tbitpos Type of the position variable. * @tparam Tbitset Type of the bitset value. -*/ + */ template struct SetBitIterator { struct Iterator { diff --git a/src/core/kdtree.hpp b/src/core/kdtree.hpp index b84c30c33c..5dc3a1263d 100644 --- a/src/core/kdtree.hpp +++ b/src/core/kdtree.hpp @@ -447,14 +447,14 @@ public: } /** - * Find all items contained within the given rectangle. - * @note Start coordinates are inclusive, end coordinates are exclusive. x1 void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2, const Outputter &outputter) const { diff --git a/src/fios.cpp b/src/fios.cpp index 8e150daafd..e7bdac1e08 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -719,7 +719,7 @@ void ScanScenarios() /** * Constructs FiosNumberedSaveName. Initial number is the most recent save, or -1 if not found. * @param prefix The prefix to use to generate a filename. -*/ + */ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(prefix), number(-1) { static std::optional _autosave_path; @@ -756,7 +756,7 @@ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(p /** * Generate a savegame name and number according to _settings_client.gui.max_num_autosaves. * @return A filename in format ".sav". -*/ + */ std::string FiosNumberedSaveName::Filename() { if (++this->number >= _settings_client.gui.max_num_autosaves) this->number = 0; @@ -766,7 +766,7 @@ std::string FiosNumberedSaveName::Filename() /** * Generate an extension for a savegame name. * @return An extension in format "-.sav". -*/ + */ std::string FiosNumberedSaveName::Extension() { return fmt::format("-{}.sav", this->prefix); diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp index 4a6c687e31..97ad01b20b 100644 --- a/src/framerate_gui.cpp +++ b/src/framerate_gui.cpp @@ -1,9 +1,9 @@ /* -* This file is part of OpenTTD. -* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. -* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . -*/ + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ /** @file framerate_gui.cpp GUI for displaying framerate/game speed information. */ @@ -802,7 +802,7 @@ struct FrametimeGraphWindow : Window { void SelectHorizontalScale(TimingMeasurement range) { /* Determine horizontal scale based on period covered by 60 points - * (slightly less than 2 seconds at full game speed) */ + * (slightly less than 2 seconds at full game speed) */ struct ScaleDef { TimingMeasurement range; int scale; }; static const ScaleDef hscales[] = { { 120, 60 }, diff --git a/src/framerate_type.h b/src/framerate_type.h index fc4660f200..8dd84c29ce 100644 --- a/src/framerate_type.h +++ b/src/framerate_type.h @@ -1,9 +1,9 @@ /* -* This file is part of OpenTTD. -* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. -* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . -*/ + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ /** @file framerate_type.h * Types for recording game performance data. diff --git a/src/music/midi.h b/src/music/midi.h index 7408cd52d0..38f82220f4 100644 --- a/src/music/midi.h +++ b/src/music/midi.h @@ -1,9 +1,9 @@ /* -* This file is part of OpenTTD. -* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. -* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . -*/ + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ /* @file midi.h Declarations for MIDI data */ diff --git a/src/music/midifile.cpp b/src/music/midifile.cpp index 45a5bea24b..dc02bc280c 100644 --- a/src/music/midifile.cpp +++ b/src/music/midifile.cpp @@ -1,9 +1,9 @@ /* -* This file is part of OpenTTD. -* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. -* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . -*/ + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ /* @file midifile.cpp Parser for standard MIDI files */ diff --git a/src/music/midifile.hpp b/src/music/midifile.hpp index fcbe5abcce..c66094315e 100644 --- a/src/music/midifile.hpp +++ b/src/music/midifile.hpp @@ -1,9 +1,9 @@ /* -* This file is part of OpenTTD. -* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. -* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . -*/ + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ /* @file midifile.hpp Parser for standard MIDI files */ diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 85a20ed30d..fa01e6f110 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -171,9 +171,9 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta this->SendPackets(true); /* Wait a number of ticks so our leave message can reach the server. - * This is especially needed for Windows servers as they seem to get - * the "socket is closed" message before receiving our leave message, - * which would trigger the server to close the connection as well. */ + * This is especially needed for Windows servers as they seem to get + * the "socket is closed" message before receiving our leave message, + * which would trigger the server to close the connection as well. */ CSleep(3 * MILLISECONDS_PER_TICK); } diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index d54a61a1d2..c8854f536d 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -219,7 +219,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentType type) p->Send_string("patchpack"); // Or what-ever the name of your patchpack is. p->Send_string(_openttd_content_version_patchpack); - */ + */ this->SendPacket(p); } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index da7f9d5935..604fe777e8 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -3591,12 +3591,12 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, it.ti.y = (int8_t)GB(it.ti.y, 0, 8); /* When there were only 256x256 maps, TileIndex was a uint16_t and - * it.ti was just a TileIndexDiff that was added to it. - * As such negative "x" values were shifted into the "y" position. - * x = -1, y = 1 -> x = 255, y = 0 - * Since GRF version 8 the position is interpreted as pair of independent int8. - * For GRF version < 8 we need to emulate the old shifting behaviour. - */ + * it.ti was just a TileIndexDiff that was added to it. + * As such negative "x" values were shifted into the "y" position. + * x = -1, y = 1 -> x = 255, y = 0 + * Since GRF version 8 the position is interpreted as pair of independent int8. + * For GRF version < 8 we need to emulate the old shifting behaviour. + */ if (_cur.grffile->grf_version < 8 && it.ti.x < 0) it.ti.y += 1; } } @@ -9348,8 +9348,8 @@ static void FinaliseIndustriesArray() StringID strid; /* process the conversion of text at the end, so to be sure everything will be fine - * and available. Check if it does not return undefind marker, which is a very good sign of a - * substitute industry who has not changed the string been examined, thus using it as such */ + * and available. Check if it does not return undefind marker, which is a very good sign of a + * substitute industry who has not changed the string been examined, thus using it as such */ strid = GetGRFStringID(indsp->grf_prop.grffile->grfid, indsp->name); if (strid != STR_UNDEFINED) indsp->name = strid; @@ -9367,7 +9367,7 @@ static void FinaliseIndustriesArray() if (indsp->station_name != STR_NULL) { /* STR_NULL (0) can be set by grf. It has a meaning regarding assignation of the - * station's name. Don't want to lose the value, therefore, do not process. */ + * station's name. Don't want to lose the value, therefore, do not process. */ strid = GetGRFStringID(indsp->grf_prop.grffile->grfid, indsp->station_name); if (strid != STR_UNDEFINED) indsp->station_name = strid; } diff --git a/src/newgrf_roadtype.h b/src/newgrf_roadtype.h index 43c9c9cf7a..6a4ed878c5 100644 --- a/src/newgrf_roadtype.h +++ b/src/newgrf_roadtype.h @@ -21,12 +21,12 @@ struct RoadTypeScopeResolver : public ScopeResolver { const RoadTypeInfo *rti; /** - * Constructor of the roadtype scope resolvers. - * @param ro Surrounding resolver. - * @param rti Associated RoadTypeInfo. - * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. - * @param context Are we resolving sprites for the upper halftile, or on a bridge? - */ + * Constructor of the roadtype scope resolvers. + * @param ro Surrounding resolver. + * @param rti Associated RoadTypeInfo. + * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. + * @param context Are we resolving sprites for the upper halftile, or on a bridge? + */ RoadTypeScopeResolver(ResolverObject &ro, const RoadTypeInfo *rti, TileIndex tile, TileContext context) : ScopeResolver(ro), tile(tile), context(context), rti(rti) { diff --git a/src/os/unix/font_unix.cpp b/src/os/unix/font_unix.cpp index 87eac16384..c418cdb772 100644 --- a/src/os/unix/font_unix.cpp +++ b/src/os/unix/font_unix.cpp @@ -79,8 +79,8 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) if (!font_style.empty() && !StrEqualsIgnoreCase(font_style, (char *)style)) continue; /* Font config takes the best shot, which, if the family name is spelled - * wrongly a 'random' font, so check whether the family name is the - * same as the supplied name */ + * wrongly a 'random' font, so check whether the family name is the + * same as the supplied name */ if (StrEqualsIgnoreCase(font_family, (char *)family)) { err = FT_New_Face(_library, (char *)file, index, face); } diff --git a/src/os/windows/string_uniscribe.h b/src/os/windows/string_uniscribe.h index 0c63d468c3..0621f5885c 100644 --- a/src/os/windows/string_uniscribe.h +++ b/src/os/windows/string_uniscribe.h @@ -28,21 +28,21 @@ public: static const bool SUPPORTS_RTL = true; /** - * Get the actual ParagraphLayout for the given buffer. - * @param buff The begin of the buffer. - * @param buff_end The location after the last element in the buffer. - * @param fontMapping THe mapping of the fonts. - * @return The ParagraphLayout instance. - */ + * Get the actual ParagraphLayout for the given buffer. + * @param buff The begin of the buffer. + * @param buff_end The location after the last element in the buffer. + * @param fontMapping THe mapping of the fonts. + * @return The ParagraphLayout instance. + */ static ParagraphLayouter *GetParagraphLayout(CharType *buff, CharType *buff_end, FontMap &fontMapping); /** - * Append a wide character to the internal buffer. - * @param buff The buffer to append to. - * @param buffer_last The end of the buffer. - * @param c The character to add. - * @return The number of buffer spaces that were used. - */ + * Append a wide character to the internal buffer. + * @param buff The buffer to append to. + * @param buffer_last The end of the buffer. + * @param c The character to add. + * @return The number of buffer spaces that were used. + */ static size_t AppendToBuffer(CharType *buff, const CharType *buffer_last, char32_t c) { assert(buff < buffer_last); diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 167f970817..2c767b9abb 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -31,7 +31,7 @@ * If changing the call paths into the scripting engine, define this symbol to enable full debugging of allocations. * This lets you track whether the allocator context is being switched correctly in all call paths. #define SCRIPT_DEBUG_ALLOCATIONS -*/ + */ struct ScriptAllocator { size_t allocated_size; ///< Sum of allocated data size diff --git a/src/settings.cpp b/src/settings.cpp index d86c153828..bbf603413a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -413,7 +413,7 @@ 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. */ + * 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 diff --git a/src/sound/xaudio2_s.cpp b/src/sound/xaudio2_s.cpp index 70f8fa987f..f50a109dec 100644 --- a/src/sound/xaudio2_s.cpp +++ b/src/sound/xaudio2_s.cpp @@ -41,9 +41,9 @@ typedef HRESULT(__stdcall *API_XAudio2Create)(_Outptr_ IXAudio2** ppXAudio2, UIN static FSoundDriver_XAudio2 iFSoundDriver_XAudio2; /** -* Implementation of the IXAudio2VoiceCallback interface. -* Provides buffered audio to XAudio2 from the OpenTTD mixer. -*/ + * Implementation of the IXAudio2VoiceCallback interface. + * Provides buffered audio to XAudio2 from the OpenTTD mixer. + */ class StreamingVoiceContext : public IXAudio2VoiceCallback { private: @@ -132,12 +132,12 @@ static HRESULT CreateXAudio(API_XAudio2Create xAudio2Create) } /** -* Initialises the XAudio2 driver. -* -* @param parm Driver parameters. -* @return An error message if unsuccessful, or nullptr otherwise. -* -*/ + * Initialises the XAudio2 driver. + * + * @param parm Driver parameters. + * @return An error message if unsuccessful, or nullptr otherwise. + * + */ const char *SoundDriver_XAudio2::Start(const StringList &parm) { HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); @@ -261,8 +261,8 @@ const char *SoundDriver_XAudio2::Start(const StringList &parm) } /** -* Terminates the XAudio2 driver. -*/ + * Terminates the XAudio2 driver. + */ void SoundDriver_XAudio2::Stop() { // Clean up XAudio2 diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index f791c90852..5889ff19f2 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -279,7 +279,7 @@ struct TerraformToolbarWindow : Window { case DDSP_BUILD_OBJECT: if (!_settings_game.construction.freeform_edges) { /* When end_tile is MP_VOID, the error tile will not be visible to the - * user. This happens when terraforming at the southern border. */ + * user. This happens when terraforming at the southern border. */ if (TileX(end_tile) == Map::MaxX()) end_tile += TileDiffXY(-1, 0); if (TileY(end_tile) == Map::MaxY()) end_tile += TileDiffXY(0, -1); } diff --git a/src/tests/test_script_admin.cpp b/src/tests/test_script_admin.cpp index 7063c489df..c286e6293a 100644 --- a/src/tests/test_script_admin.cpp +++ b/src/tests/test_script_admin.cpp @@ -51,7 +51,7 @@ static std::optional TestScriptAdminMakeJSON(std::string_view squir { auto vm = sq_open(1024); /* sq_compile creates a closure with our snipper, which is a table. - * Add "return " to get the table on the stack. */ + * Add "return " to get the table on the stack. */ std::string buffer = fmt::format("return {}", squirrel); /* Insert an (empty) class for testing. */ diff --git a/src/timer/timer_game_calendar.h b/src/timer/timer_game_calendar.h index 22a7d91dcc..a4ea3f27a3 100644 --- a/src/timer/timer_game_calendar.h +++ b/src/timer/timer_game_calendar.h @@ -106,10 +106,10 @@ public: static void SetDate(Date date, DateFract fract); /** - * Calculate the year of a given date. - * @param date The date to consider. - * @return the year. - */ + * Calculate the year of a given date. + * @param date The date to consider. + * @return the year. + */ static constexpr Year DateToYear(Date date) { /* Hardcode the number of days in a year because we can't access CalendarTime from here. */ @@ -117,10 +117,10 @@ public: } /** - * Calculate the date of the first day of a given year. - * @param year the year to get the first day of. - * @return the date. - */ + * Calculate the date of the first day of a given year. + * @param year the year to get the first day of. + * @return the date. + */ static constexpr Date DateAtStartOfYear(Year year) { int32_t year_as_int = static_cast(year); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 8a935dfb03..d995547d63 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1609,7 +1609,7 @@ void Vehicle::UpdatePosition() /** * Update the bounding box co-ordinates of the vehicle * @param update_cache Update the cached values for previous co-ordinate values -*/ + */ void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const { Rect new_coord; diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 7129aae7e8..2a9ae02424 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -336,7 +336,7 @@ void VideoDriver_Cocoa::GameSizeChanged() ::GameSizeChanged(); /* We need to store the window size as non-Retina size in - * the config file to get same windows size on next start. */ + * the config file to get same windows size on next start. */ _cur_resolution.width = [ this->cocoaview frame ].size.width; _cur_resolution.height = [ this->cocoaview frame ].size.height; } diff --git a/src/viewport.cpp b/src/viewport.cpp index 0b77051ea9..caa33662a8 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1391,8 +1391,8 @@ static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi) const Sign *si = Sign::Get(item.id.sign); /* Don't draw if sign is owned by another company and competitor signs should be hidden. - * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt - * companies can leave OWNER_NONE signs after them. */ + * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt + * companies can leave OWNER_NONE signs after them. */ if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break; signs.push_back(si); diff --git a/src/viewport_kdtree.h b/src/viewport_kdtree.h index 940d695051..3c2f49c2e4 100644 --- a/src/viewport_kdtree.h +++ b/src/viewport_kdtree.h @@ -1,9 +1,9 @@ /* -* This file is part of OpenTTD. -* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. -* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . -*/ + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ /** @file town_kdtree.h Declarations for accessing the k-d tree of towns */ From a849b4e175bd089b136f077588ea9d3dc9af9c7e Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sun, 29 Oct 2023 20:16:26 +0100 Subject: [PATCH 20/57] Fix: allow same length server password in the UI --- src/network/network_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 4d9d6b464a..b5bdba28fb 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1037,7 +1037,7 @@ struct NetworkStartServerWindow : public Window { case WID_NSS_SETPWD: // Set password button this->widget_id = WID_NSS_SETPWD; SetDParamStr(0, _settings_client.network.server_password); - ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_START_SERVER_SET_PASSWORD, 20, this, CS_ALPHANUMERAL, QSF_NONE); + ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_START_SERVER_SET_PASSWORD, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, QSF_NONE); break; case WID_NSS_CONNTYPE_BTN: // Connection type From 82ebc9860b10bf5587b180322618ef8aa7e149f0 Mon Sep 17 00:00:00 2001 From: translators Date: Thu, 2 Nov 2023 18:38:58 +0000 Subject: [PATCH 21/57] Update: Translations from eints finnish: 2 changes by hpiirai danish: 1 change by bscargo --- src/lang/danish.txt | 1 + src/lang/finnish.txt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lang/danish.txt b/src/lang/danish.txt index dd1ff3b8a3..f8870f34b3 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -3384,6 +3384,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Gem STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Gem forudindstilling til det valgte navn # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Skift grundlæggende grafiske parametre STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Ændre NewGRF parameterne STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Luk STR_NEWGRF_PARAMETERS_RESET :{BLACK}Nulstil diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 2732555dd3..a54fbe8b31 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -3384,7 +3384,8 @@ STR_SAVE_PRESET_SAVE :{BLACK}Tallenna STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Tallenna valmislista valitulle nimelle # NewGRF parameters window -STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Muuta NewGRF-parametrejä +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Muuta perusgrafiikan parametreja +STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Muuta NewGRF-parametreja STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Sulje STR_NEWGRF_PARAMETERS_RESET :{BLACK}Palauta STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Aseta kaikki parametrit oletusarvoihin From 873f93cab1d94cdc43e653c4a640356a63932d44 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 21:28:24 +0000 Subject: [PATCH 22/57] Fix: AI config window should not have an ini_key. (#11423) This was missed by the workflow script that enforces this constraint. --- src/ai/ai_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 1e468a9b5c..6c12b37d98 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -74,7 +74,7 @@ static const NWidgetPart _nested_ai_config_widgets[] = { /** Window definition for the configure AI window. */ static WindowDesc _ai_config_desc( - WDP_CENTER, "settings_script_config", 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, std::begin(_nested_ai_config_widgets), std::end(_nested_ai_config_widgets) From 18fb8e153f7c993b3f58c229ffd32485b1cbb440 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 19:33:01 +0000 Subject: [PATCH 23/57] Codechange: Add __FILE__/__LINE__ of WindowDesc to WindowDesc. This is to allow unit-tests to produce more useful output. --- src/ai/ai_gui.cpp | 2 +- src/airport_gui.cpp | 4 ++-- src/autoreplace_gui.cpp | 6 +++--- src/bootstrap_gui.cpp | 8 ++++---- src/bridge_gui.cpp | 2 +- src/build_vehicle_gui.cpp | 2 +- src/cheat_gui.cpp | 2 +- src/company_gui.cpp | 12 ++++++------ src/console_gui.cpp | 2 +- src/date_gui.cpp | 2 +- src/depot_gui.cpp | 8 ++++---- src/dock_gui.cpp | 8 ++++---- src/engine_gui.cpp | 2 +- src/error_gui.cpp | 4 ++-- src/fios_gui.cpp | 6 +++--- src/framerate_gui.cpp | 4 ++-- src/game/game_gui.cpp | 2 +- src/genworld_gui.cpp | 8 ++++---- src/goal_gui.cpp | 6 +++++- src/graph_gui.cpp | 16 ++++++++-------- src/group_gui.cpp | 4 ++-- src/help_gui.cpp | 2 +- src/highscore_gui.cpp | 4 ++-- src/industry_gui.cpp | 8 ++++---- src/intro_gui.cpp | 2 +- src/league_gui.cpp | 4 ++-- src/linkgraph/linkgraph_gui.cpp | 2 +- src/main_gui.cpp | 2 +- src/misc_gui.cpp | 10 +++++----- src/music_gui.cpp | 4 ++-- src/network/network_chat_gui.cpp | 2 +- src/network/network_content_gui.cpp | 4 ++-- src/network/network_gui.cpp | 14 +++++++------- src/newgrf_debug_gui.cpp | 6 +++--- src/newgrf_gui.cpp | 8 ++++---- src/news_gui.cpp | 12 ++++++------ src/object_gui.cpp | 2 +- src/order_gui.cpp | 6 +++--- src/osk_gui.cpp | 2 +- src/rail_gui.cpp | 10 +++++----- src/road_gui.cpp | 14 +++++++------- src/screenshot_gui.cpp | 2 +- src/script/script_gui.cpp | 6 +++--- src/settings_gui.cpp | 6 +++--- src/signs_gui.cpp | 4 ++-- src/smallmap_gui.cpp | 2 +- src/station_gui.cpp | 6 +++--- src/statusbar_gui.cpp | 2 +- src/story_gui.cpp | 2 +- src/subsidy_gui.cpp | 2 +- src/terraform_gui.cpp | 4 ++-- src/textfile_gui.cpp | 2 +- src/timetable_gui.cpp | 2 +- src/toolbar_gui.cpp | 4 ++-- src/town_gui.cpp | 10 +++++----- src/transparency_gui.cpp | 2 +- src/tree_gui.cpp | 2 +- src/vehicle_gui.cpp | 14 +++++++------- src/viewport_gui.cpp | 2 +- src/waypoint_gui.cpp | 2 +- src/widgets/dropdown.cpp | 2 +- src/window.cpp | 4 +++- src/window_gui.h | 4 +++- 63 files changed, 161 insertions(+), 153 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 6c12b37d98..a383ba5132 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -73,7 +73,7 @@ static const NWidgetPart _nested_ai_config_widgets[] = { }; /** Window definition for the configure AI window. */ -static WindowDesc _ai_config_desc( +static WindowDesc _ai_config_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 9e5c86ce88..4638822c33 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -207,7 +207,7 @@ static const NWidgetPart _nested_air_toolbar_widgets[] = { EndContainer(), }; -static WindowDesc _air_toolbar_desc( +static WindowDesc _air_toolbar_desc(__FILE__, __LINE__, WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -618,7 +618,7 @@ static const NWidgetPart _nested_build_airport_widgets[] = { EndContainer(), }; -static WindowDesc _build_airport_desc( +static WindowDesc _build_airport_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index b358def3c8..a883cc3b8d 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -809,7 +809,7 @@ static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = { EndContainer(), }; -static WindowDesc _replace_rail_vehicle_desc( +static WindowDesc _replace_rail_vehicle_desc(__FILE__, __LINE__, WDP_AUTO, "replace_vehicle_train", 500, 140, WC_REPLACE_VEHICLE, WC_NONE, WDF_CONSTRUCTION, @@ -867,7 +867,7 @@ static const NWidgetPart _nested_replace_road_vehicle_widgets[] = { EndContainer(), }; -static WindowDesc _replace_road_vehicle_desc( +static WindowDesc _replace_road_vehicle_desc(__FILE__, __LINE__, WDP_AUTO, "replace_vehicle_road", 500, 140, WC_REPLACE_VEHICLE, WC_NONE, WDF_CONSTRUCTION, @@ -921,7 +921,7 @@ static const NWidgetPart _nested_replace_vehicle_widgets[] = { EndContainer(), }; -static WindowDesc _replace_vehicle_desc( +static WindowDesc _replace_vehicle_desc(__FILE__, __LINE__, WDP_AUTO, "replace_vehicle", 456, 118, WC_REPLACE_VEHICLE, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp index 0082c60008..62745270ce 100644 --- a/src/bootstrap_gui.cpp +++ b/src/bootstrap_gui.cpp @@ -39,7 +39,7 @@ static const struct NWidgetPart _background_widgets[] = { /** * Window description for the background window to prevent smearing. */ -static WindowDesc _background_desc( +static WindowDesc _background_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_BOOTSTRAP, WC_NONE, WDF_NO_CLOSE, @@ -75,7 +75,7 @@ static const NWidgetPart _nested_bootstrap_errmsg_widgets[] = { }; /** Window description for the error window. */ -static WindowDesc _bootstrap_errmsg_desc( +static WindowDesc _bootstrap_errmsg_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_BOOTSTRAP, WC_NONE, WDF_MODAL | WDF_NO_CLOSE, @@ -132,7 +132,7 @@ static const NWidgetPart _nested_bootstrap_download_status_window_widgets[] = { }; /** Window description for the download window */ -static WindowDesc _bootstrap_download_status_window_desc( +static WindowDesc _bootstrap_download_status_window_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL | WDF_NO_CLOSE, @@ -184,7 +184,7 @@ static const NWidgetPart _bootstrap_query_widgets[] = { }; /** The window description for the query. */ -static WindowDesc _bootstrap_query_desc( +static WindowDesc _bootstrap_query_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, WDF_NO_CLOSE, diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index b7f89ef975..bf3c5c7cef 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -341,7 +341,7 @@ static const NWidgetPart _nested_build_bridge_widgets[] = { }; /** Window definition for the rail bridge selection window. */ -static WindowDesc _build_bridge_desc( +static WindowDesc _build_bridge_desc(__FILE__, __LINE__, WDP_AUTO, "build_bridge", 200, 114, WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 94015c8cba..af8b927863 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1903,7 +1903,7 @@ struct BuildVehicleWindow : Window { }}; }; -static WindowDesc _build_vehicle_desc( +static WindowDesc _build_vehicle_desc(__FILE__, __LINE__, WDP_AUTO, "build_vehicle", 240, 268, WC_BUILD_VEHICLE, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 88bed5e387..2b69bbceb9 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -428,7 +428,7 @@ struct CheatWindow : Window { }; /** Window description of the cheats GUI. */ -static WindowDesc _cheats_desc( +static WindowDesc _cheats_desc(__FILE__, __LINE__, WDP_AUTO, "cheats", 0, 0, WC_CHEATS, WC_NONE, 0, diff --git a/src/company_gui.cpp b/src/company_gui.cpp index e1b95d2211..e35cc5e4fc 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -538,7 +538,7 @@ struct CompanyFinancesWindow : Window { /** First conservative estimate of the maximum amount of money */ Money CompanyFinancesWindow::max_money = INT32_MAX; -static WindowDesc _company_finances_desc( +static WindowDesc _company_finances_desc(__FILE__, __LINE__, WDP_AUTO, "company_finances", 0, 0, WC_FINANCES, WC_NONE, 0, @@ -1156,7 +1156,7 @@ static const NWidgetPart _nested_select_company_livery_widgets [] = { EndContainer(), }; -static WindowDesc _select_company_livery_desc( +static WindowDesc _select_company_livery_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_COMPANY_COLOUR, WC_NONE, 0, @@ -1773,7 +1773,7 @@ public: }; /** Company manager face selection window description */ -static WindowDesc _select_company_manager_face_desc( +static WindowDesc _select_company_manager_face_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_COMPANY_MANAGER_FACE, WC_NONE, WDF_CONSTRUCTION, @@ -2145,7 +2145,7 @@ struct CompanyInfrastructureWindow : Window } }; -static WindowDesc _company_infrastructure_desc( +static WindowDesc _company_infrastructure_desc(__FILE__, __LINE__, WDP_AUTO, "company_infrastructure", 0, 0, WC_COMPANY_INFRASTRUCTURE, WC_NONE, 0, @@ -2682,7 +2682,7 @@ struct CompanyWindow : Window } }; -static WindowDesc _company_desc( +static WindowDesc _company_desc(__FILE__, __LINE__, WDP_AUTO, "company", 0, 0, WC_COMPANY, WC_NONE, 0, @@ -2816,7 +2816,7 @@ static const NWidgetPart _nested_buy_company_widgets[] = { EndContainer(), }; -static WindowDesc _buy_company_desc( +static WindowDesc _buy_company_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_BUY_COMPANY, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/console_gui.cpp b/src/console_gui.cpp index 309dcb9a1b..952a21bb1a 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -102,7 +102,7 @@ static const struct NWidgetPart _nested_console_window_widgets[] = { NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_BACKGROUND), SetResize(1, 1), }; -static WindowDesc _console_window_desc( +static WindowDesc _console_window_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_CONSOLE, WC_NONE, 0, diff --git a/src/date_gui.cpp b/src/date_gui.cpp index d007f72146..c93dabe1e9 100644 --- a/src/date_gui.cpp +++ b/src/date_gui.cpp @@ -195,7 +195,7 @@ static const NWidgetPart _nested_set_date_widgets[] = { }; /** Description of the date setting window. */ -static WindowDesc _set_date_desc( +static WindowDesc _set_date_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_SET_DATE, WC_NONE, 0, diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index 32ad8d9143..de9fd5384a 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -85,28 +85,28 @@ static const NWidgetPart _nested_train_depot_widgets[] = { EndContainer(), }; -static WindowDesc _train_depot_desc( +static WindowDesc _train_depot_desc(__FILE__, __LINE__, WDP_AUTO, "depot_train", 362, 123, WC_VEHICLE_DEPOT, WC_NONE, 0, std::begin(_nested_train_depot_widgets), std::end(_nested_train_depot_widgets) ); -static WindowDesc _road_depot_desc( +static WindowDesc _road_depot_desc(__FILE__, __LINE__, WDP_AUTO, "depot_roadveh", 316, 97, WC_VEHICLE_DEPOT, WC_NONE, 0, std::begin(_nested_train_depot_widgets), std::end(_nested_train_depot_widgets) ); -static WindowDesc _ship_depot_desc( +static WindowDesc _ship_depot_desc(__FILE__, __LINE__, WDP_AUTO, "depot_ship", 306, 99, WC_VEHICLE_DEPOT, WC_NONE, 0, std::begin(_nested_train_depot_widgets), std::end(_nested_train_depot_widgets) ); -static WindowDesc _aircraft_depot_desc( +static WindowDesc _aircraft_depot_desc(__FILE__, __LINE__, WDP_AUTO, "depot_aircraft", 332, 99, WC_VEHICLE_DEPOT, WC_NONE, 0, diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index 18c4aa501d..c433117a92 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -344,7 +344,7 @@ static const NWidgetPart _nested_build_docks_toolbar_widgets[] = { EndContainer(), }; -static WindowDesc _build_docks_toolbar_desc( +static WindowDesc _build_docks_toolbar_desc(__FILE__, __LINE__, WDP_ALIGN_TOOLBAR, "toolbar_water", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -388,7 +388,7 @@ static const NWidgetPart _nested_build_docks_scen_toolbar_widgets[] = { }; /** Window definition for the build docks in scenario editor window. */ -static WindowDesc _build_docks_scen_toolbar_desc( +static WindowDesc _build_docks_scen_toolbar_desc(__FILE__, __LINE__, WDP_AUTO, "toolbar_water_scen", 0, 0, WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -494,7 +494,7 @@ static const NWidgetPart _nested_build_dock_station_widgets[] = { EndContainer(), }; -static WindowDesc _build_dock_station_desc( +static WindowDesc _build_dock_station_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, @@ -592,7 +592,7 @@ static const NWidgetPart _nested_build_docks_depot_widgets[] = { EndContainer(), }; -static WindowDesc _build_docks_depot_desc( +static WindowDesc _build_docks_depot_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp index 0534ff9fda..09d9f6c1f3 100644 --- a/src/engine_gui.cpp +++ b/src/engine_gui.cpp @@ -144,7 +144,7 @@ struct EnginePreviewWindow : Window { } }; -static WindowDesc _engine_preview_desc( +static WindowDesc _engine_preview_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_ENGINE_PREVIEW, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/error_gui.cpp b/src/error_gui.cpp index f573574dfd..cb8e800afc 100644 --- a/src/error_gui.cpp +++ b/src/error_gui.cpp @@ -42,7 +42,7 @@ static const NWidgetPart _nested_errmsg_widgets[] = { EndContainer(), }; -static WindowDesc _errmsg_desc( +static WindowDesc _errmsg_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_ERRMSG, WC_NONE, 0, @@ -62,7 +62,7 @@ static const NWidgetPart _nested_errmsg_face_widgets[] = { EndContainer(), }; -static WindowDesc _errmsg_face_desc( +static WindowDesc _errmsg_face_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_ERRMSG, WC_NONE, 0, diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 93555e7c5d..2b794ecd53 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -883,7 +883,7 @@ public: }; /** Load game/scenario */ -static WindowDesc _load_dialog_desc( +static WindowDesc _load_dialog_desc(__FILE__, __LINE__, WDP_CENTER, "load_game", 500, 294, WC_SAVELOAD, WC_NONE, 0, @@ -891,7 +891,7 @@ static WindowDesc _load_dialog_desc( ); /** Load heightmap */ -static WindowDesc _load_heightmap_dialog_desc( +static WindowDesc _load_heightmap_dialog_desc(__FILE__, __LINE__, WDP_CENTER, "load_heightmap", 257, 320, WC_SAVELOAD, WC_NONE, 0, @@ -899,7 +899,7 @@ static WindowDesc _load_heightmap_dialog_desc( ); /** Save game/scenario */ -static WindowDesc _save_dialog_desc( +static WindowDesc _save_dialog_desc(__FILE__, __LINE__, WDP_CENTER, "save_game", 500, 294, WC_SAVELOAD, WC_NONE, 0, diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp index 97ad01b20b..23fe4d000c 100644 --- a/src/framerate_gui.cpp +++ b/src/framerate_gui.cpp @@ -726,7 +726,7 @@ struct FramerateWindow : Window { } }; -static WindowDesc _framerate_display_desc( +static WindowDesc _framerate_display_desc(__FILE__, __LINE__, WDP_AUTO, "framerate_display", 0, 0, WC_FRAMERATE_DISPLAY, WC_NONE, 0, @@ -1011,7 +1011,7 @@ struct FrametimeGraphWindow : Window { } }; -static WindowDesc _frametime_graph_window_desc( +static WindowDesc _frametime_graph_window_desc(__FILE__, __LINE__, WDP_AUTO, "frametime_graph", 140, 90, WC_FRAMETIME_GRAPH, WC_NONE, 0, diff --git a/src/game/game_gui.cpp b/src/game/game_gui.cpp index 032d604392..2bc68f095b 100644 --- a/src/game/game_gui.cpp +++ b/src/game/game_gui.cpp @@ -68,7 +68,7 @@ static const NWidgetPart _nested_gs_config_widgets[] = { }; /** Window definition for the configure GS window. */ -static WindowDesc _gs_config_desc( +static WindowDesc _gs_config_desc(__FILE__, __LINE__, WDP_CENTER, "settings_gs_config", 500, 350, WC_GAME_OPTIONS, WC_NONE, 0, diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index d961b5d3df..5b9e36f3d3 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -1015,14 +1015,14 @@ struct GenerateLandscapeWindow : public Window { } }; -static WindowDesc _generate_landscape_desc( +static WindowDesc _generate_landscape_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, std::begin(_nested_generate_landscape_widgets), std::end(_nested_generate_landscape_widgets) ); -static WindowDesc _heightmap_load_desc( +static WindowDesc _heightmap_load_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, @@ -1312,7 +1312,7 @@ static const NWidgetPart _nested_create_scenario_widgets[] = { EndContainer(), }; -static WindowDesc _create_scenario_desc( +static WindowDesc _create_scenario_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, @@ -1338,7 +1338,7 @@ static const NWidgetPart _nested_generate_progress_widgets[] = { }; -static WindowDesc _generate_progress_desc( +static WindowDesc _generate_progress_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_MODAL_PROGRESS, WC_NONE, 0, diff --git a/src/goal_gui.cpp b/src/goal_gui.cpp index 30f1206545..adf3345ba4 100644 --- a/src/goal_gui.cpp +++ b/src/goal_gui.cpp @@ -302,7 +302,7 @@ static const NWidgetPart _nested_goals_list_widgets[] = { EndContainer(), }; -static WindowDesc _goals_list_desc( +static WindowDesc _goals_list_desc(__FILE__, __LINE__, WDP_AUTO, "list_goals", 500, 127, WC_GOALS_LIST, WC_NONE, 0, @@ -512,24 +512,28 @@ static const NWidgetPart _nested_goal_question_widgets_error[] = { static WindowDesc _goal_question_list_desc[] = { { + __FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GOAL_QUESTION, WC_NONE, WDF_CONSTRUCTION, std::begin(_nested_goal_question_widgets_question), std::end(_nested_goal_question_widgets_question), }, { + __FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GOAL_QUESTION, WC_NONE, WDF_CONSTRUCTION, std::begin(_nested_goal_question_widgets_info), std::end(_nested_goal_question_widgets_info), }, { + __FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GOAL_QUESTION, WC_NONE, WDF_CONSTRUCTION, std::begin(_nested_goal_question_widgets_warning), std::end(_nested_goal_question_widgets_warning), }, { + __FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GOAL_QUESTION, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index c17a916233..27c67e3f08 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -141,7 +141,7 @@ static const NWidgetPart _nested_graph_legend_widgets[] = { EndContainer(), }; -static WindowDesc _graph_legend_desc( +static WindowDesc _graph_legend_desc(__FILE__, __LINE__, WDP_AUTO, "graph_legend", 0, 0, WC_GRAPH_LEGEND, WC_NONE, 0, @@ -654,7 +654,7 @@ static const NWidgetPart _nested_operating_profit_widgets[] = { EndContainer(), }; -static WindowDesc _operating_profit_desc( +static WindowDesc _operating_profit_desc(__FILE__, __LINE__, WDP_AUTO, "graph_operating_profit", 0, 0, WC_OPERATING_PROFIT, WC_NONE, 0, @@ -705,7 +705,7 @@ static const NWidgetPart _nested_income_graph_widgets[] = { EndContainer(), }; -static WindowDesc _income_graph_desc( +static WindowDesc _income_graph_desc(__FILE__, __LINE__, WDP_AUTO, "graph_income", 0, 0, WC_INCOME_GRAPH, WC_NONE, 0, @@ -754,7 +754,7 @@ static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = { EndContainer(), }; -static WindowDesc _delivered_cargo_graph_desc( +static WindowDesc _delivered_cargo_graph_desc(__FILE__, __LINE__, WDP_AUTO, "graph_delivered_cargo", 0, 0, WC_DELIVERED_CARGO, WC_NONE, 0, @@ -810,7 +810,7 @@ static const NWidgetPart _nested_performance_history_widgets[] = { EndContainer(), }; -static WindowDesc _performance_history_desc( +static WindowDesc _performance_history_desc(__FILE__, __LINE__, WDP_AUTO, "graph_performance", 0, 0, WC_PERFORMANCE_HISTORY, WC_NONE, 0, @@ -859,7 +859,7 @@ static const NWidgetPart _nested_company_value_graph_widgets[] = { EndContainer(), }; -static WindowDesc _company_value_graph_desc( +static WindowDesc _company_value_graph_desc(__FILE__, __LINE__, WDP_AUTO, "graph_company_value", 0, 0, WC_COMPANY_VALUE, WC_NONE, 0, @@ -1093,7 +1093,7 @@ static const NWidgetPart _nested_cargo_payment_rates_widgets[] = { EndContainer(), }; -static WindowDesc _cargo_payment_rates_desc( +static WindowDesc _cargo_payment_rates_desc(__FILE__, __LINE__, WDP_AUTO, "graph_cargo_payment_rates", 0, 0, WC_PAYMENT_RATES, WC_NONE, 0, @@ -1389,7 +1389,7 @@ static const NWidgetPart _nested_performance_rating_detail_widgets[] = { NWidgetFunction(MakePerformanceDetailPanels), }; -static WindowDesc _performance_rating_detail_desc( +static WindowDesc _performance_rating_detail_desc(__FILE__, __LINE__, WDP_AUTO, "league_details", 0, 0, WC_PERFORMANCE_DETAIL, WC_NONE, 0, diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 3f324dadf8..b3080c8044 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -1101,14 +1101,14 @@ public: }; -static WindowDesc _other_group_desc( +static WindowDesc _other_group_desc(__FILE__, __LINE__, WDP_AUTO, "list_groups", 460, 246, WC_INVALID, WC_NONE, 0, std::begin(_nested_group_widgets), std::end(_nested_group_widgets) ); -static WindowDesc _train_group_desc( +static WindowDesc _train_group_desc(__FILE__, __LINE__, WDP_AUTO, "list_groups_train", 525, 246, WC_TRAINS_LIST, WC_NONE, 0, diff --git a/src/help_gui.cpp b/src/help_gui.cpp index 5c052af917..be28a24de7 100644 --- a/src/help_gui.cpp +++ b/src/help_gui.cpp @@ -205,7 +205,7 @@ static const NWidgetPart _nested_helpwin_widgets[] = { EndContainer(), }; -static WindowDesc _helpwin_desc( +static WindowDesc _helpwin_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_HELPWIN, WC_NONE, 0, diff --git a/src/highscore_gui.cpp b/src/highscore_gui.cpp index 1deb60281c..3849d7b027 100644 --- a/src/highscore_gui.cpp +++ b/src/highscore_gui.cpp @@ -214,14 +214,14 @@ static const NWidgetPart _nested_highscore_widgets[] = { NWidget(WWT_PANEL, COLOUR_BROWN, WID_H_BACKGROUND), SetResize(1, 1), EndContainer(), }; -static WindowDesc _highscore_desc( +static WindowDesc _highscore_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_HIGHSCORE, WC_NONE, 0, std::begin(_nested_highscore_widgets), std::end(_nested_highscore_widgets) ); -static WindowDesc _endgame_desc( +static WindowDesc _endgame_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_ENDSCREEN, WC_NONE, 0, diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 824ce9b172..c71138687d 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -291,7 +291,7 @@ static const NWidgetPart _nested_build_industry_widgets[] = { }; /** Window definition of the dynamic place industries gui */ -static WindowDesc _build_industry_desc( +static WindowDesc _build_industry_desc(__FILE__, __LINE__, WDP_AUTO, "build_industry", 170, 212, WC_BUILD_INDUSTRY, WC_NONE, WDF_CONSTRUCTION, @@ -1201,7 +1201,7 @@ static const NWidgetPart _nested_industry_view_widgets[] = { }; /** Window definition of the view industry gui */ -static WindowDesc _industry_view_desc( +static WindowDesc _industry_view_desc(__FILE__, __LINE__, WDP_AUTO, "view_industry", 260, 120, WC_INDUSTRY_VIEW, WC_NONE, 0, @@ -1865,7 +1865,7 @@ CargoID IndustryDirectoryWindow::produced_cargo_filter = CF_ANY; /** Window definition of the industry directory gui */ -static WindowDesc _industry_directory_desc( +static WindowDesc _industry_directory_desc(__FILE__, __LINE__, WDP_AUTO, "list_industries", 428, 190, WC_INDUSTRY_DIRECTORY, WC_NONE, 0, @@ -1903,7 +1903,7 @@ static const NWidgetPart _nested_industry_cargoes_widgets[] = { }; /** Window description for the industry cargoes window. */ -static WindowDesc _industry_cargoes_desc( +static WindowDesc _industry_cargoes_desc(__FILE__, __LINE__, WDP_AUTO, "industry_cargoes", 300, 210, WC_INDUSTRY_CARGOES, WC_NONE, 0, diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index 4f8dd95db2..62988b577f 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -495,7 +495,7 @@ static const NWidgetPart _nested_select_game_widgets[] = { EndContainer(), }; -static WindowDesc _select_game_desc( +static WindowDesc _select_game_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_SELECT_GAME, WC_NONE, WDF_NO_CLOSE, diff --git a/src/league_gui.cpp b/src/league_gui.cpp index 8775695b16..912cdae5e1 100644 --- a/src/league_gui.cpp +++ b/src/league_gui.cpp @@ -196,7 +196,7 @@ static const NWidgetPart _nested_performance_league_widgets[] = { NWidget(WWT_PANEL, COLOUR_BROWN, WID_PLT_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WidgetDimensions::unscaled.framerect.Vertical()), }; -static WindowDesc _performance_league_desc( +static WindowDesc _performance_league_desc(__FILE__, __LINE__, WDP_AUTO, "performance_league", 0, 0, WC_COMPANY_LEAGUE, WC_NONE, 0, @@ -428,7 +428,7 @@ static const NWidgetPart _nested_script_league_widgets[] = { NWidget(WWT_PANEL, COLOUR_BROWN, WID_SLT_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WidgetDimensions::scaled.framerect.Vertical()), }; -static WindowDesc _script_league_desc( +static WindowDesc _script_league_desc(__FILE__, __LINE__, WDP_AUTO, "script_league", 0, 0, WC_COMPANY_LEAGUE, WC_NONE, 0, diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index e94ba9786c..2c666ef515 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -540,7 +540,7 @@ static const NWidgetPart _nested_linkgraph_legend_widgets[] = { static_assert(WID_LGL_SATURATION_LAST - WID_LGL_SATURATION_FIRST == lengthof(LinkGraphOverlay::LINK_COLOURS[0]) - 1); -static WindowDesc _linkgraph_legend_desc( +static WindowDesc _linkgraph_legend_desc(__FILE__, __LINE__, WDP_AUTO, "toolbar_linkgraph", 0, 0, WC_LINKGRAPH_LEGEND, WC_NONE, 0, diff --git a/src/main_gui.cpp b/src/main_gui.cpp index ec1648b08d..9f35dfeade 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -513,7 +513,7 @@ struct MainWindow : Window }}; }; -static WindowDesc _main_window_desc( +static WindowDesc _main_window_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_MAIN_WINDOW, WC_NONE, WDF_NO_CLOSE, diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index d3cc1df0db..c5f58d7381 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -58,7 +58,7 @@ static const NWidgetPart _nested_land_info_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_LI_BACKGROUND), EndContainer(), }; -static WindowDesc _land_info_desc( +static WindowDesc _land_info_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_LAND_INFO, WC_NONE, 0, @@ -393,7 +393,7 @@ static const NWidgetPart _nested_about_widgets[] = { EndContainer(), }; -static WindowDesc _about_desc( +static WindowDesc _about_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, @@ -651,7 +651,7 @@ static const NWidgetPart _nested_tooltips_widgets[] = { NWidget(WWT_EMPTY, INVALID_COLOUR, WID_TT_BACKGROUND), EndContainer(), }; -static WindowDesc _tool_tips_desc( +static WindowDesc _tool_tips_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, // Coordinates and sizes are not used, WC_TOOLTIPS, WC_NONE, WDF_NO_FOCUS | WDF_NO_CLOSE, @@ -1064,7 +1064,7 @@ static const NWidgetPart _nested_query_string_widgets[] = { EndContainer(), }; -static WindowDesc _query_string_desc( +static WindowDesc _query_string_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_QUERY_STRING, WC_NONE, 0, @@ -1211,7 +1211,7 @@ static const NWidgetPart _nested_query_widgets[] = { EndContainer(), }; -static WindowDesc _query_desc( +static WindowDesc _query_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, WDF_MODAL, diff --git a/src/music_gui.cpp b/src/music_gui.cpp index 188cfbc4f7..0a521e189e 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -641,7 +641,7 @@ static const NWidgetPart _nested_music_track_selection_widgets[] = { EndContainer(), }; -static WindowDesc _music_track_selection_desc( +static WindowDesc _music_track_selection_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_MUSIC_TRACK_SELECTION, WC_NONE, 0, @@ -900,7 +900,7 @@ static const NWidgetPart _nested_music_window_widgets[] = { EndContainer(), }; -static WindowDesc _music_window_desc( +static WindowDesc _music_window_desc(__FILE__, __LINE__, WDP_AUTO, "music", 0, 0, WC_MUSIC_WINDOW, WC_NONE, 0, diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 5bbd6c80b4..24b328d92a 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -508,7 +508,7 @@ static const NWidgetPart _nested_chat_window_widgets[] = { }; /** The description of the chat window. */ -static WindowDesc _chat_window_desc( +static WindowDesc _chat_window_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_SEND_NETWORK_MSG, WC_NONE, 0, diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 672b2bca7e..59b40c4a8b 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -92,7 +92,7 @@ static const NWidgetPart _nested_network_content_download_status_window_widgets[ }; /** Window description for the download window */ -static WindowDesc _network_content_download_status_window_desc( +static WindowDesc _network_content_download_status_window_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, @@ -1109,7 +1109,7 @@ static const NWidgetPart _nested_network_content_list_widgets[] = { }; /** Window description of the content list */ -static WindowDesc _network_content_list_desc( +static WindowDesc _network_content_list_desc(__FILE__, __LINE__, WDP_CENTER, "list_content", 630, 460, WC_NETWORK_WINDOW, WC_NONE, 0, diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index b5bdba28fb..e64f393fc4 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -952,7 +952,7 @@ static const NWidgetPart _nested_network_game_widgets[] = { EndContainer(), }; -static WindowDesc _network_game_window_desc( +static WindowDesc _network_game_window_desc(__FILE__, __LINE__, WDP_CENTER, "list_servers", 1000, 730, WC_NETWORK_WINDOW, WC_NONE, 0, @@ -1219,7 +1219,7 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = { EndContainer(), }; -static WindowDesc _network_start_server_window_desc( +static WindowDesc _network_start_server_window_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_NETWORK_WINDOW, WC_NONE, 0, @@ -1298,7 +1298,7 @@ static const NWidgetPart _nested_client_list_widgets[] = { EndContainer(), }; -static WindowDesc _client_list_desc( +static WindowDesc _client_list_desc(__FILE__, __LINE__, WDP_AUTO, "list_clients", 220, 300, WC_CLIENT_LIST, WC_NONE, 0, @@ -2208,7 +2208,7 @@ static const NWidgetPart _nested_network_join_status_window_widgets[] = { EndContainer(), }; -static WindowDesc _network_join_status_window_desc( +static WindowDesc _network_join_status_window_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, @@ -2330,7 +2330,7 @@ static const NWidgetPart _nested_network_company_password_window_widgets[] = { EndContainer(), }; -static WindowDesc _network_company_password_window_desc( +static WindowDesc _network_company_password_window_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_COMPANY_PASSWORD_WINDOW, WC_NONE, 0, @@ -2439,7 +2439,7 @@ static const NWidgetPart _nested_network_ask_relay_widgets[] = { EndContainer(), }; -static WindowDesc _network_ask_relay_desc( +static WindowDesc _network_ask_relay_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_NETWORK_ASK_RELAY, WC_NONE, WDF_MODAL, @@ -2537,7 +2537,7 @@ static const NWidgetPart _nested_network_ask_survey_widgets[] = { EndContainer(), }; -static WindowDesc _network_ask_survey_desc( +static WindowDesc _network_ask_survey_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_NETWORK_ASK_SURVEY, WC_NONE, WDF_MODAL, diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index db58442914..4fdc4d509b 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -679,14 +679,14 @@ static const NWidgetPart _nested_newgrf_inspect_widgets[] = { EndContainer(), }; -static WindowDesc _newgrf_inspect_chain_desc( +static WindowDesc _newgrf_inspect_chain_desc(__FILE__, __LINE__, WDP_AUTO, "newgrf_inspect_chain", 400, 300, WC_NEWGRF_INSPECT, WC_NONE, 0, std::begin(_nested_newgrf_inspect_chain_widgets), std::end(_nested_newgrf_inspect_chain_widgets) ); -static WindowDesc _newgrf_inspect_desc( +static WindowDesc _newgrf_inspect_desc(__FILE__, __LINE__, WDP_AUTO, "newgrf_inspect", 400, 300, WC_NEWGRF_INSPECT, WC_NONE, 0, @@ -1122,7 +1122,7 @@ static const NWidgetPart _nested_sprite_aligner_widgets[] = { EndContainer(), }; -static WindowDesc _sprite_aligner_desc( +static WindowDesc _sprite_aligner_desc(__FILE__, __LINE__, WDP_AUTO, "sprite_aligner", 400, 300, WC_SPRITE_ALIGNER, WC_NONE, 0, diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 04929fb2b8..9acd9bd3a2 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -540,7 +540,7 @@ static const NWidgetPart _nested_newgrf_parameter_widgets[] = { }; /** Window definition for the change grf parameters window */ -static WindowDesc _newgrf_parameters_desc( +static WindowDesc _newgrf_parameters_desc(__FILE__, __LINE__, WDP_CENTER, "settings_newgrf_config", 500, 208, WC_GRF_PARAMETERS, WC_NONE, 0, @@ -1964,7 +1964,7 @@ static const NWidgetPart _nested_newgrf_widgets[] = { }; /* Window definition of the manage newgrfs window */ -static WindowDesc _newgrf_desc( +static WindowDesc _newgrf_desc(__FILE__, __LINE__, WDP_CENTER, "settings_newgrf", 300, 263, WC_GAME_OPTIONS, WC_NONE, 0, @@ -2048,7 +2048,7 @@ static const NWidgetPart _nested_save_preset_widgets[] = { }; /** Window description of the preset save window. */ -static WindowDesc _save_preset_desc( +static WindowDesc _save_preset_desc(__FILE__, __LINE__, WDP_CENTER, "save_preset", 140, 110, WC_SAVE_PRESET, WC_GAME_OPTIONS, WDF_MODAL, @@ -2193,7 +2193,7 @@ static const NWidgetPart _nested_scan_progress_widgets[] = { }; /** Description of the widgets and other settings of the window. */ -static WindowDesc _scan_progress_desc( +static WindowDesc _scan_progress_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_MODAL_PROGRESS, WC_NONE, 0, diff --git a/src/news_gui.cpp b/src/news_gui.cpp index 2295009fe5..7f461ce406 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -96,7 +96,7 @@ static const NWidgetPart _nested_normal_news_widgets[] = { EndContainer(), }; -static WindowDesc _normal_news_desc( +static WindowDesc _normal_news_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, @@ -123,7 +123,7 @@ static const NWidgetPart _nested_vehicle_news_widgets[] = { EndContainer(), }; -static WindowDesc _vehicle_news_desc( +static WindowDesc _vehicle_news_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, @@ -151,7 +151,7 @@ static const NWidgetPart _nested_company_news_widgets[] = { EndContainer(), }; -static WindowDesc _company_news_desc( +static WindowDesc _company_news_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, @@ -174,7 +174,7 @@ static const NWidgetPart _nested_thin_news_widgets[] = { EndContainer(), }; -static WindowDesc _thin_news_desc( +static WindowDesc _thin_news_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, @@ -200,7 +200,7 @@ static const NWidgetPart _nested_small_news_widgets[] = { EndContainer(), }; -static WindowDesc _small_news_desc( +static WindowDesc _small_news_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, @@ -1227,7 +1227,7 @@ static const NWidgetPart _nested_message_history[] = { EndContainer(), }; -static WindowDesc _message_history_desc( +static WindowDesc _message_history_desc(__FILE__, __LINE__, WDP_AUTO, "list_news", 400, 140, WC_MESSAGE_HISTORY, WC_NONE, 0, diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 0a35a77a15..35133be345 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -718,7 +718,7 @@ static const NWidgetPart _nested_build_object_widgets[] = { EndContainer(), }; -static WindowDesc _build_object_desc( +static WindowDesc _build_object_desc(__FILE__, __LINE__, WDP_AUTO, "build_object", 0, 0, WC_BUILD_OBJECT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, diff --git a/src/order_gui.cpp b/src/order_gui.cpp index aafd21ecc2..0335ff4d68 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -1636,7 +1636,7 @@ static const NWidgetPart _nested_orders_train_widgets[] = { EndContainer(), }; -static WindowDesc _orders_train_desc( +static WindowDesc _orders_train_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_orders_train", 384, 100, WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, @@ -1709,7 +1709,7 @@ static const NWidgetPart _nested_orders_widgets[] = { EndContainer(), }; -static WindowDesc _orders_desc( +static WindowDesc _orders_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_orders", 384, 100, WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, @@ -1736,7 +1736,7 @@ static const NWidgetPart _nested_other_orders_widgets[] = { EndContainer(), }; -static WindowDesc _other_orders_desc( +static WindowDesc _other_orders_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_orders_competitor", 384, 86, WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index dfb59c1474..1beb896ffa 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -336,7 +336,7 @@ static const NWidgetPart _nested_osk_widgets[] = { EndContainer(), }; -static WindowDesc _osk_desc( +static WindowDesc _osk_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_OSK, WC_NONE, 0, diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 70e1699953..65d0da98e6 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -837,7 +837,7 @@ static const NWidgetPart _nested_build_rail_widgets[] = { EndContainer(), }; -static WindowDesc _build_rail_desc( +static WindowDesc _build_rail_desc(__FILE__, __LINE__, WDP_ALIGN_TOOLBAR, "toolbar_rail", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -1629,7 +1629,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { }; /** High level window description of the station-build window (default & newGRF) */ -static WindowDesc _station_builder_desc( +static WindowDesc _station_builder_desc(__FILE__, __LINE__, WDP_AUTO, "build_station_rail", 350, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, @@ -1887,7 +1887,7 @@ static const NWidgetPart _nested_signal_builder_widgets[] = { }; /** Signal selection window description */ -static WindowDesc _signal_builder_desc( +static WindowDesc _signal_builder_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, @@ -1978,7 +1978,7 @@ static const NWidgetPart _nested_build_depot_widgets[] = { EndContainer(), }; -static WindowDesc _build_depot_desc( +static WindowDesc _build_depot_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, @@ -2206,7 +2206,7 @@ static const NWidgetPart _nested_build_waypoint_widgets[] = { EndContainer(), }; -static WindowDesc _build_waypoint_desc( +static WindowDesc _build_waypoint_desc(__FILE__, __LINE__, WDP_AUTO, "build_waypoint", 0, 0, WC_BUILD_WAYPOINT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 1a6e98a6f9..17de83bb9a 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -851,7 +851,7 @@ static const NWidgetPart _nested_build_road_widgets[] = { EndContainer(), }; -static WindowDesc _build_road_desc( +static WindowDesc _build_road_desc(__FILE__, __LINE__, WDP_ALIGN_TOOLBAR, "toolbar_road", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -892,7 +892,7 @@ static const NWidgetPart _nested_build_tramway_widgets[] = { EndContainer(), }; -static WindowDesc _build_tramway_desc( +static WindowDesc _build_tramway_desc(__FILE__, __LINE__, WDP_ALIGN_TOOLBAR, "toolbar_tramway", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -947,7 +947,7 @@ static const NWidgetPart _nested_build_road_scen_widgets[] = { EndContainer(), }; -static WindowDesc _build_road_scen_desc( +static WindowDesc _build_road_scen_desc(__FILE__, __LINE__, WDP_AUTO, "toolbar_road_scen", 0, 0, WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -982,7 +982,7 @@ static const NWidgetPart _nested_build_tramway_scen_widgets[] = { EndContainer(), }; -static WindowDesc _build_tramway_scen_desc( +static WindowDesc _build_tramway_scen_desc(__FILE__, __LINE__, WDP_AUTO, "toolbar_tram_scen", 0, 0, WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, @@ -1080,7 +1080,7 @@ static const NWidgetPart _nested_build_road_depot_widgets[] = { EndContainer(), }; -static WindowDesc _build_road_depot_desc( +static WindowDesc _build_road_depot_desc(__FILE__, __LINE__, WDP_AUTO, nullptr, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, @@ -1679,7 +1679,7 @@ static const NWidgetPart _nested_road_station_picker_widgets[] = { EndContainer(), }; -static WindowDesc _road_station_picker_desc( +static WindowDesc _road_station_picker_desc(__FILE__, __LINE__, WDP_AUTO, "build_station_road", 0, 0, WC_BUS_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, @@ -1764,7 +1764,7 @@ static const NWidgetPart _nested_tram_station_picker_widgets[] = { EndContainer(), }; -static WindowDesc _tram_station_picker_desc( +static WindowDesc _tram_station_picker_desc(__FILE__, __LINE__, WDP_AUTO, "build_station_tram", 0, 0, WC_BUS_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, diff --git a/src/screenshot_gui.cpp b/src/screenshot_gui.cpp index a59fc14407..bcc74baa75 100644 --- a/src/screenshot_gui.cpp +++ b/src/screenshot_gui.cpp @@ -60,7 +60,7 @@ static const NWidgetPart _nested_screenshot[] = { EndContainer(), }; -static WindowDesc _screenshot_window_desc( +static WindowDesc _screenshot_window_desc(__FILE__, __LINE__, WDP_AUTO, "take_a_screenshot", 200, 100, WC_SCREENSHOT, WC_NONE, 0, diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index c2ff57f025..f393917c4e 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -261,7 +261,7 @@ static const NWidgetPart _nested_script_list_widgets[] = { }; /** Window definition for the ai list window. */ -static WindowDesc _script_list_desc( +static WindowDesc _script_list_desc(__FILE__, __LINE__, WDP_CENTER, "settings_script_list", 200, 234, WC_SCRIPT_LIST, WC_NONE, 0, @@ -606,7 +606,7 @@ static const NWidgetPart _nested_script_settings_widgets[] = { }; /** Window definition for the Script settings window. */ -static WindowDesc _script_settings_desc( +static WindowDesc _script_settings_desc(__FILE__, __LINE__, WDP_CENTER, "settings_script", 500, 208, WC_SCRIPT_SETTINGS, WC_NONE, 0, @@ -1193,7 +1193,7 @@ EndContainer(), }; /** Window definition for the Script debug window. */ -static WindowDesc _script_debug_desc( +static WindowDesc _script_debug_desc(__FILE__, __LINE__, WDP_AUTO, "script_debug", 600, 450, WC_SCRIPT_DEBUG, WC_NONE, 0, diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index dc56f92812..3d54c5ee3d 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -928,7 +928,7 @@ static const NWidgetPart _nested_game_options_widgets[] = { EndContainer(), }; -static WindowDesc _game_options_desc( +static WindowDesc _game_options_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, @@ -2655,7 +2655,7 @@ static const NWidgetPart _nested_settings_selection_widgets[] = { EndContainer(), }; -static WindowDesc _settings_selection_desc( +static WindowDesc _settings_selection_desc(__FILE__, __LINE__, WDP_CENTER, "settings", 510, 450, WC_GAME_OPTIONS, WC_NONE, 0, @@ -2954,7 +2954,7 @@ static const NWidgetPart _nested_cust_currency_widgets[] = { EndContainer(), }; -static WindowDesc _cust_currency_desc( +static WindowDesc _cust_currency_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_CUSTOM_CURRENCY, WC_NONE, 0, diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index c45483168a..8eda33bb6b 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -385,7 +385,7 @@ static const NWidgetPart _nested_sign_list_widgets[] = { EndContainer(), }; -static WindowDesc _sign_list_desc( +static WindowDesc _sign_list_desc(__FILE__, __LINE__, WDP_AUTO, "list_signs", 358, 138, WC_SIGN_LIST, WC_NONE, 0, @@ -551,7 +551,7 @@ static const NWidgetPart _nested_query_sign_edit_widgets[] = { EndContainer(), }; -static WindowDesc _query_sign_edit_desc( +static WindowDesc _query_sign_edit_desc(__FILE__, __LINE__, WDP_CENTER, nullptr, 0, 0, WC_QUERY_STRING, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index ae2473f4ec..ed9144e02c 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1978,7 +1978,7 @@ static const NWidgetPart _nested_smallmap_widgets[] = { EndContainer(), }; -static WindowDesc _smallmap_desc( +static WindowDesc _smallmap_desc(__FILE__, __LINE__, WDP_AUTO, "smallmap", 484, 314, WC_SMALLMAP, WC_NONE, 0, diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 6787841420..2eac0f2980 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -762,7 +762,7 @@ static const NWidgetPart _nested_company_stations_widgets[] = { EndContainer(), }; -static WindowDesc _company_stations_desc( +static WindowDesc _company_stations_desc(__FILE__, __LINE__, WDP_AUTO, "list_stations", 358, 162, WC_STATION_LIST, WC_NONE, 0, @@ -2130,7 +2130,7 @@ const StringID StationViewWindow::_group_names[] = { INVALID_STRING_ID }; -static WindowDesc _station_view_desc( +static WindowDesc _station_view_desc(__FILE__, __LINE__, WDP_AUTO, "view_station", 249, 117, WC_STATION_VIEW, WC_NONE, 0, @@ -2387,7 +2387,7 @@ struct SelectStationWindow : Window { } }; -static WindowDesc _select_station_desc( +static WindowDesc _select_station_desc(__FILE__, __LINE__, WDP_AUTO, "build_station_join", 200, 180, WC_SELECT_STATION, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index b1ac784e24..34632838ae 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -226,7 +226,7 @@ static const NWidgetPart _nested_main_status_widgets[] = { EndContainer(), }; -static WindowDesc _main_status_desc( +static WindowDesc _main_status_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_STATUS_BAR, WC_NONE, WDF_NO_FOCUS | WDF_NO_CLOSE, diff --git a/src/story_gui.cpp b/src/story_gui.cpp index c8eed0a98b..4012a9ae48 100644 --- a/src/story_gui.cpp +++ b/src/story_gui.cpp @@ -968,7 +968,7 @@ static const NWidgetPart _nested_story_book_widgets[] = { EndContainer(), }; -static WindowDesc _story_book_desc( +static WindowDesc _story_book_desc(__FILE__, __LINE__, WDP_CENTER, "view_story", 400, 300, WC_STORY_BOOK, WC_NONE, 0, diff --git a/src/subsidy_gui.cpp b/src/subsidy_gui.cpp index 3074431e8f..c45939944f 100644 --- a/src/subsidy_gui.cpp +++ b/src/subsidy_gui.cpp @@ -234,7 +234,7 @@ static const NWidgetPart _nested_subsidies_list_widgets[] = { EndContainer(), }; -static WindowDesc _subsidies_list_desc( +static WindowDesc _subsidies_list_desc(__FILE__, __LINE__, WDP_AUTO, "list_subsidies", 500, 127, WC_SUBSIDIES_LIST, WC_NONE, 0, diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 5889ff19f2..f3e3f4e690 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -351,7 +351,7 @@ static const NWidgetPart _nested_terraform_widgets[] = { EndContainer(), }; -static WindowDesc _terraform_desc( +static WindowDesc _terraform_desc(__FILE__, __LINE__, WDP_MANUAL, "toolbar_landscape", 0, 0, WC_SCEN_LAND_GEN, WC_NONE, WDF_CONSTRUCTION, @@ -735,7 +735,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { }, TerraformToolbarEditorGlobalHotkeys}; }; -static WindowDesc _scen_edit_land_gen_desc( +static WindowDesc _scen_edit_land_gen_desc(__FILE__, __LINE__, WDP_AUTO, "toolbar_landscape_scen", 0, 0, WC_SCEN_LAND_GEN, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index eb4e27274b..bf63a24dea 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -74,7 +74,7 @@ static const NWidgetPart _nested_textfile_widgets[] = { }; /** Window definition for the textfile window */ -static WindowDesc _textfile_desc( +static WindowDesc _textfile_desc(__FILE__, __LINE__, WDP_CENTER, "textfile", 630, 460, WC_TEXTFILE, WC_NONE, 0, diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 2f9b792c18..e8bd258288 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -743,7 +743,7 @@ static const NWidgetPart _nested_timetable_widgets[] = { EndContainer(), }; -static WindowDesc _timetable_desc( +static WindowDesc _timetable_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_timetable", 400, 130, WC_VEHICLE_TIMETABLE, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 5f3f279acf..7df6a2c833 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2237,7 +2237,7 @@ static const NWidgetPart _nested_toolbar_normal_widgets[] = { NWidgetFunction(MakeMainToolbar), }; -static WindowDesc _toolb_normal_desc( +static WindowDesc _toolb_normal_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_MAIN_TOOLBAR, WC_NONE, WDF_NO_FOCUS | WDF_NO_CLOSE, @@ -2577,7 +2577,7 @@ static const NWidgetPart _nested_toolb_scen_widgets[] = { NWidgetFunction(MakeScenarioToolbar), }; -static WindowDesc _toolb_scen_desc( +static WindowDesc _toolb_scen_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_MAIN_TOOLBAR, WC_NONE, WDF_NO_FOCUS | WDF_NO_CLOSE, diff --git a/src/town_gui.cpp b/src/town_gui.cpp index b73db08534..b0b43b297e 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -326,7 +326,7 @@ public: } }; -static WindowDesc _town_authority_desc( +static WindowDesc _town_authority_desc(__FILE__, __LINE__, WDP_AUTO, "view_town_authority", 317, 222, WC_TOWN_AUTHORITY, WC_NONE, 0, @@ -619,7 +619,7 @@ static const NWidgetPart _nested_town_game_view_widgets[] = { EndContainer(), }; -static WindowDesc _town_game_view_desc( +static WindowDesc _town_game_view_desc(__FILE__, __LINE__, WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, WC_TOWN_VIEW, WC_NONE, 0, @@ -650,7 +650,7 @@ static const NWidgetPart _nested_town_editor_view_widgets[] = { EndContainer(), }; -static WindowDesc _town_editor_view_desc( +static WindowDesc _town_editor_view_desc(__FILE__, __LINE__, WDP_AUTO, "view_town_scen", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, WC_TOWN_VIEW, WC_NONE, 0, @@ -1025,7 +1025,7 @@ GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = { &TownRatingSorter, }; -static WindowDesc _town_directory_desc( +static WindowDesc _town_directory_desc(__FILE__, __LINE__, WDP_AUTO, "list_towns", 208, 202, WC_TOWN_DIRECTORY, WC_NONE, 0, @@ -1275,7 +1275,7 @@ public: } }; -static WindowDesc _found_town_desc( +static WindowDesc _found_town_desc(__FILE__, __LINE__, WDP_AUTO, "build_town", 160, 162, WC_FOUND_TOWN, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/transparency_gui.cpp b/src/transparency_gui.cpp index e15726e631..5f1bbabbdf 100644 --- a/src/transparency_gui.cpp +++ b/src/transparency_gui.cpp @@ -148,7 +148,7 @@ static const NWidgetPart _nested_transparency_widgets[] = { EndContainer(), }; -static WindowDesc _transparency_desc( +static WindowDesc _transparency_desc(__FILE__, __LINE__, WDP_MANUAL, "toolbar_transparency", 0, 0, WC_TRANSPARENCY_TOOLBAR, WC_NONE, 0, diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 5ffadd5483..44192b2227 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -316,7 +316,7 @@ static const NWidgetPart _nested_build_trees_widgets[] = { EndContainer(), }; -static WindowDesc _build_trees_desc( +static WindowDesc _build_trees_desc(__FILE__, __LINE__, WDP_AUTO, "build_tree", 0, 0, WC_BUILD_TREES, WC_NONE, WDF_CONSTRUCTION, diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index ced848932e..38f310f155 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1216,7 +1216,7 @@ static const NWidgetPart _nested_vehicle_refit_widgets[] = { EndContainer(), }; -static WindowDesc _vehicle_refit_desc( +static WindowDesc _vehicle_refit_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_refit", 240, 174, WC_VEHICLE_REFIT, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, @@ -2143,14 +2143,14 @@ public: } }; -static WindowDesc _vehicle_list_other_desc( +static WindowDesc _vehicle_list_other_desc(__FILE__, __LINE__, WDP_AUTO, "list_vehicles", 260, 246, WC_INVALID, WC_NONE, 0, std::begin(_nested_vehicle_list), std::end(_nested_vehicle_list) ); -static WindowDesc _vehicle_list_train_desc( +static WindowDesc _vehicle_list_train_desc(__FILE__, __LINE__, WDP_AUTO, "list_vehicles_train", 325, 246, WC_TRAINS_LIST, WC_NONE, 0, @@ -2649,7 +2649,7 @@ struct VehicleDetailsWindow : Window { }; /** Vehicle details window descriptor. */ -static WindowDesc _train_vehicle_details_desc( +static WindowDesc _train_vehicle_details_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_details_train", 405, 178, WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, 0, @@ -2657,7 +2657,7 @@ static WindowDesc _train_vehicle_details_desc( ); /** Vehicle details window descriptor for other vehicles than a train. */ -static WindowDesc _nontrain_vehicle_details_desc( +static WindowDesc _nontrain_vehicle_details_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_details", 405, 113, WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, 0, @@ -3253,7 +3253,7 @@ public: }; /** Vehicle view window descriptor for all vehicles but trains. */ -static WindowDesc _vehicle_view_desc( +static WindowDesc _vehicle_view_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle", 250, 116, WC_VEHICLE_VIEW, WC_NONE, 0, @@ -3265,7 +3265,7 @@ static WindowDesc _vehicle_view_desc( * Vehicle view window descriptor for trains. Only minimum_height and * default_height are different for train view. */ -static WindowDesc _train_view_desc( +static WindowDesc _train_view_desc(__FILE__, __LINE__, WDP_AUTO, "view_vehicle_train", 250, 134, WC_VEHICLE_VIEW, WC_NONE, 0, diff --git a/src/viewport_gui.cpp b/src/viewport_gui.cpp index 0c2b136afb..1f5178aff2 100644 --- a/src/viewport_gui.cpp +++ b/src/viewport_gui.cpp @@ -159,7 +159,7 @@ public: } }; -static WindowDesc _extra_viewport_desc( +static WindowDesc _extra_viewport_desc(__FILE__, __LINE__, WDP_AUTO, "extra_viewport", 300, 268, WC_EXTRA_VIEWPORT, WC_NONE, 0, diff --git a/src/waypoint_gui.cpp b/src/waypoint_gui.cpp index 3ef1fa1f48..071d8bb37c 100644 --- a/src/waypoint_gui.cpp +++ b/src/waypoint_gui.cpp @@ -183,7 +183,7 @@ static const NWidgetPart _nested_waypoint_view_widgets[] = { }; /** The description of the waypoint view. */ -static WindowDesc _waypoint_view_desc( +static WindowDesc _waypoint_view_desc(__FILE__, __LINE__, WDP_AUTO, "view_waypoint", 260, 118, WC_WAYPOINT_VIEW, WC_NONE, 0, diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 5ee04219b5..3b8054233a 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -107,7 +107,7 @@ static const NWidgetPart _nested_dropdown_menu_widgets[] = { EndContainer(), }; -static WindowDesc _dropdown_desc( +static WindowDesc _dropdown_desc(__FILE__, __LINE__, WDP_MANUAL, nullptr, 0, 0, WC_DROPDOWN_MENU, WC_NONE, WDF_NO_FOCUS, diff --git a/src/window.cpp b/src/window.cpp index 5de2f8f6cf..de514ec8d5 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -102,9 +102,11 @@ static std::vector *_window_descs = nullptr; std::string _windows_file; /** Window description constructor. */ -WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16_t def_width_trad, int16_t def_height_trad, +WindowDesc::WindowDesc(const char * const file, const int line, WindowPosition def_pos, const char *ini_key, int16_t def_width_trad, int16_t def_height_trad, WindowClass window_class, WindowClass parent_class, uint32_t flags, const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, HotkeyList *hotkeys) : + file(file), + line(line), default_pos(def_pos), cls(window_class), parent_cls(parent_class), diff --git a/src/window_gui.h b/src/window_gui.h index 53257ca00b..8beb315976 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -95,12 +95,14 @@ struct HotkeyList; */ struct WindowDesc : ZeroedMemoryAllocator { - WindowDesc(WindowPosition default_pos, const char *ini_key, int16_t def_width_trad, int16_t def_height_trad, + WindowDesc(const char * const file, const int line, WindowPosition default_pos, const char *ini_key, int16_t def_width_trad, int16_t def_height_trad, WindowClass window_class, WindowClass parent_class, uint32_t flags, const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, HotkeyList *hotkeys = nullptr); ~WindowDesc(); + const char * const file; ///< Source file of this definition + const int line; ///< Source line of this definition WindowPosition default_pos; ///< Preferred position of the window. @see WindowPosition() WindowClass cls; ///< Class of the window, @see WindowClass. WindowClass parent_cls; ///< Class of the parent window. @see WindowClass From e563057478b1aed01e5ea7605d42300782d01b37 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 19:33:02 +0000 Subject: [PATCH 24/57] Add: WindowDesc unit test to validate ini-key value. ini-key must be present if WWT_DEFSIZEBOX or WWT_STICKYBOX is present. This was previously enforced by a workflow, however that parsed the source code with regex which turned out to be error-prone. --- src/tests/CMakeLists.txt | 1 + src/tests/test_window_desc.cpp | 49 ++++++++++++++++++++++++++++++++++ src/window.cpp | 2 +- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/tests/test_window_desc.cpp diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index ce33de8609..9a01d4e8fe 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -5,4 +5,5 @@ add_test_files( strings_func.cpp test_main.cpp test_script_admin.cpp + test_window_desc.cpp ) diff --git a/src/tests/test_window_desc.cpp b/src/tests/test_window_desc.cpp new file mode 100644 index 0000000000..8421a9dc34 --- /dev/null +++ b/src/tests/test_window_desc.cpp @@ -0,0 +1,49 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file test_window_desc.cpp Test WindowDescs for valid widget parts. */ + +#include "../stdafx.h" + +#include "../3rdparty/catch2/catch.hpp" + +#include "../window_gui.h" + +/** + * List of WindowDescs. Defined in window.cpp but not exposed as this unit-test is the only other place that needs it. + * WindowDesc is a self-registering class so all WindowDescs will be included in the list. + */ +extern std::vector *_window_descs; + +TEST_CASE("WindowDesc - ini_key uniqueness") +{ + std::set seen; + + for (const WindowDesc *window_desc : *_window_descs) { + + if (window_desc->ini_key == nullptr) continue; + + CAPTURE(window_desc->ini_key); + CHECK((seen.find(window_desc->ini_key) == std::end(seen))); + + seen.insert(window_desc->ini_key); + } +} + +TEST_CASE("WindowDesc - ini_key validity") +{ + const WindowDesc *window_desc = GENERATE(from_range(std::begin(*_window_descs), std::end(*_window_descs))); + + bool has_inikey = window_desc->ini_key != nullptr; + bool has_widget = std::any_of(window_desc->nwid_begin, window_desc->nwid_end, [](const NWidgetPart &part) { return part.type == WWT_DEFSIZEBOX || part.type == WWT_STICKYBOX; }); + + INFO(fmt::format("{}:{}", window_desc->file, window_desc->line)); + CAPTURE(has_inikey); + CAPTURE(has_widget); + + CHECK((has_widget == has_inikey)); +} diff --git a/src/window.cpp b/src/window.cpp index de514ec8d5..2047a6efd7 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -96,7 +96,7 @@ SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. * List of all WindowDescs. * This is a pointer to ensure initialisation order with the various static WindowDesc instances. */ -static std::vector *_window_descs = nullptr; +std::vector *_window_descs = nullptr; /** Config file to store WindowDesc */ std::string _windows_file; From cda896bca5f4d67efd8529f438d580308a552ef0 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 19:33:02 +0000 Subject: [PATCH 25/57] Remove: windowdesc-ini-key workflow, as this is now performed more reliably by a unit-test. --- .github/windowdesc-ini-key.py | 50 ------------------------ .github/workflows/windowdesc-ini-key.yml | 24 ------------ 2 files changed, 74 deletions(-) delete mode 100644 .github/windowdesc-ini-key.py delete mode 100644 .github/workflows/windowdesc-ini-key.yml diff --git a/.github/windowdesc-ini-key.py b/.github/windowdesc-ini-key.py deleted file mode 100644 index 36b20f9948..0000000000 --- a/.github/windowdesc-ini-key.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Script to scan the OpenTTD source-tree for ini_key issues in WindowDesc entries. -""" - -import glob -import os -import re -import sys - - -def scan_source_files(path, ini_keys=None): - if ini_keys is None: - ini_keys = set() - - errors = [] - - for new_path in glob.glob(f"{path}/*.cpp"): - if os.path.isdir(new_path): - errors.append(scan_source_files(new_path, ini_keys)) - continue - - with open(new_path) as fp: - output = fp.read() - - for (name, ini_key, widgets) in re.findall(r"^static WindowDesc ([a-zA-Z0-9_]*).*?, (?:\"(.*?)\")?.*?,(?:\s+.*?,){6}\s+[^\s]+\((.*?)\)", output, re.S|re.M): - if ini_key: - if ini_key in ini_keys: - errors.append(f"{new_path}: {name} ini_key is a duplicate") - ini_keys.add(ini_key) - widget = re.findall("static const (?:struct )?NWidgetPart " + widgets + ".*?(?:WWT_(DEFSIZE|STICKY)BOX.*?)?;", output, re.S)[0] - if widget and not ini_key: - errors.append(f"{new_path}: {name} has WWT_DEFSIZEBOX/WWT_STICKYBOX without ini_key") - if ini_key and not widget: - errors.append(f"{new_path}: {name} has ini_key without WWT_DEFSIZEBOX/WWT_STICKYBOX") - - return errors - - -def main(): - errors = scan_source_files("src") - - if errors: - print("\n".join(errors)) - sys.exit(1) - - print("OK") - - -if __name__ == "__main__": - main() diff --git a/.github/workflows/windowdesc-ini-key.yml b/.github/workflows/windowdesc-ini-key.yml deleted file mode 100644 index b69172d5af..0000000000 --- a/.github/workflows/windowdesc-ini-key.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: WindowDesc ini_key - -on: - pull_request: - branches: - - master - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} - -jobs: - windowdesc-ini-key: - name: WindowDesc ini_key issues - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Check for ini_key issues in WindowDesc entries - shell: bash - run: | - python3 .github/windowdesc-ini-key.py From d4a77411a5d50e7cef3a532d0a83bc2efa67a1a4 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 3 Nov 2023 08:17:26 +0000 Subject: [PATCH 26/57] Fix: Some NWidget lists were not properly closed. (#11425) --- src/bootstrap_gui.cpp | 1 + src/league_gui.cpp | 2 ++ src/misc_gui.cpp | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp index 62745270ce..03f64de705 100644 --- a/src/bootstrap_gui.cpp +++ b/src/bootstrap_gui.cpp @@ -34,6 +34,7 @@ /** Widgets for the background window to prevent smearing. */ static const struct NWidgetPart _background_widgets[] = { NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1), + EndContainer(), }; /** diff --git a/src/league_gui.cpp b/src/league_gui.cpp index 912cdae5e1..3998f2e571 100644 --- a/src/league_gui.cpp +++ b/src/league_gui.cpp @@ -194,6 +194,7 @@ static const NWidgetPart _nested_performance_league_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_PLT_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WidgetDimensions::unscaled.framerect.Vertical()), + EndContainer(), }; static WindowDesc _performance_league_desc(__FILE__, __LINE__, @@ -426,6 +427,7 @@ static const NWidgetPart _nested_script_league_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_SLT_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WidgetDimensions::scaled.framerect.Vertical()), + EndContainer(), }; static WindowDesc _script_league_desc(__FILE__, __LINE__, diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index c5f58d7381..0780d3b876 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -648,7 +648,7 @@ void HideFillingPercent(TextEffectID *te_id) } static const NWidgetPart _nested_tooltips_widgets[] = { - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_TT_BACKGROUND), EndContainer(), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_TT_BACKGROUND), }; static WindowDesc _tool_tips_desc(__FILE__, __LINE__, From e8db1371350f360acc30663ff58d157e961ec27e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 23:23:50 +0000 Subject: [PATCH 27/57] Codechange: Move test for Container WidgetType to helper function. --- src/widget.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index fa91b1f66d..fc50a8da7d 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -3233,6 +3233,17 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg return nwid_begin; } +/** + * Test if WidgetType is a container widget. + * @param tp WidgetType to test. + * @return True iff WidgetType is a container widget. + */ +bool IsContainerWidgetType(WidgetType tp) +{ + return tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL || tp == NWID_MATRIX + || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET || tp == NWID_SELECTION; +} + /** * Build a nested widget tree by recursively filling containers with nested widgets read from their parts. * @param nwid_begin Pointer to beginning of nested widget parts. @@ -3259,9 +3270,7 @@ static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NW if (sub_widget == nullptr) break; /* If sub-widget is a container, recursively fill that container. */ - WidgetType tp = sub_widget->type; - if (fill_sub && (tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL || tp == NWID_MATRIX - || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET || tp == NWID_SELECTION)) { + if (fill_sub && IsContainerWidgetType(sub_widget->type)) { NWidgetBase *sub_ptr = sub_widget; nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &sub_ptr, biggest_index); } From ce6e7394910c5e6267f785cf1797e9d31fb0e11d Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 23:25:28 +0000 Subject: [PATCH 28/57] Codechange: Add unit-test to check if nested widget parts of properly closed. Properly closed means exactly one EndContainer for every Container widget. --- src/tests/test_window_desc.cpp | 26 ++++++++++++++++++++++++++ src/widget_type.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/tests/test_window_desc.cpp b/src/tests/test_window_desc.cpp index 8421a9dc34..64f95c58b5 100644 --- a/src/tests/test_window_desc.cpp +++ b/src/tests/test_window_desc.cpp @@ -47,3 +47,29 @@ TEST_CASE("WindowDesc - ini_key validity") CHECK((has_widget == has_inikey)); } + +/** + * Test if a NWidgetTree is properly closed, meaning the number of container-type parts matches the number of + * EndContainer() parts. + * @param nwid_begin Pointer to beginning of nested widget parts. + * @param nwid_end Pointer to ending of nested widget parts. + * @return True iff nested tree is properly closed. + */ +static bool IsNWidgetTreeClosed(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end) +{ + int depth = 0; + for (; nwid_begin < nwid_end; ++nwid_begin) { + if (IsContainerWidgetType(nwid_begin->type)) ++depth; + if (nwid_begin->type == WPT_ENDCONTAINER) --depth; + } + return depth == 0; +} + +TEST_CASE("WindowDesc - NWidgetParts properly closed") +{ + const WindowDesc *window_desc = GENERATE(from_range(std::begin(*_window_descs), std::end(*_window_descs))); + + INFO(fmt::format("{}:{}", window_desc->file, window_desc->line)); + + CHECK(IsNWidgetTreeClosed(window_desc->nwid_begin, window_desc->nwid_end)); +} diff --git a/src/widget_type.h b/src/widget_type.h index baa9623053..a0c8d1dce0 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -1294,6 +1294,7 @@ static inline NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr) return part; } +bool IsContainerWidgetType(WidgetType tp); NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetContainer *container); NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetStacked **shade_select); From 4c58df75fda28a5c3d1b1d5bcd9d8f0ac7f29c60 Mon Sep 17 00:00:00 2001 From: translators Date: Fri, 3 Nov 2023 18:38:51 +0000 Subject: [PATCH 29/57] Update: Translations from eints english (au): 1 change by krysclarke russian: 1 change by Ln-Wolf dutch: 3 changes by Afoklala portuguese: 1 change by azulcosta --- src/lang/dutch.txt | 3 +++ src/lang/english_AU.txt | 1 + src/lang/portuguese.txt | 1 + src/lang/russian.txt | 1 + 4 files changed, 6 insertions(+) diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 1734ccd0e9..9b393a2e1b 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -533,6 +533,7 @@ STR_ABOUT_MENU_ABOUT_OPENTTD :Over 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite-uitlijner STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Selectiekaders in-uitschakelen STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Kleuren van vuile blokken in-uitschakelen +STR_ABOUT_MENU_TOGGLE_WIDGET_OUTLINES :Widgetkaders in-uitschakelen # Place in highscore window ###length 15 @@ -3383,6 +3384,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Opslaan STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Sla de huidige voorkeursinstelling op onder de huidige gekozen naam # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Grafische basisinstellingen wijzigen STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}NewGRF-parameters wijzigen STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Sluiten STR_NEWGRF_PARAMETERS_RESET :{BLACK}Terugstellen @@ -5187,6 +5189,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Kan geen STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Voertuigen kunnen alleen wachten op stations STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Dit voertuig stopt niet op dit station STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... dienstregeling is niet compleet +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... dienstregeling is nog niet gestart # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... te veel bordjes diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index eb1e3b6991..2aed159f88 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -5189,6 +5189,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Can't ti STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehicles can only wait at stations STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}This vehicle is not stopping at this station STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... timetable is incomplete +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... timetable has not started yet # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... too many signs diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 7682b7bcac..ede0f03a08 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -5190,6 +5190,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Impossí STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Veículos apenas podem esperar em estações. STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Este veículo não pára nesta estação. STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... horário incompleto +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... o horário ainda não começou # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... demasiados sinais diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 8b9389ca34..6a7384795b 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -5376,6 +5376,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Не у STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Транспорт может ждать только на станции STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Это транспортное средство не останавливается на этой станции STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... график движения неполный +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... график движения не установлен # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... слишком много табличек From 7d4a91ef9ec0b43dffce4475008ed92b245abebb Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 3 Nov 2023 21:21:00 +0000 Subject: [PATCH 30/57] Cleanup: Remove some unused functions. (#11429) These were picked up with cppcheck. --- src/articulated_vehicles.cpp | 14 ------------ src/articulated_vehicles.h | 1 - src/group.h | 1 - src/group_cmd.cpp | 13 ----------- src/newgrf_text.cpp | 7 ------ src/newgrf_text.h | 1 - src/object_gui.cpp | 10 --------- src/order_base.h | 3 --- src/order_cmd.cpp | 25 --------------------- src/pathfinder/yapf/yapf_road.cpp | 6 ------ src/road.cpp | 36 ------------------------------- src/strings.cpp | 8 ------- src/strings_func.h | 2 -- src/vehicle.cpp | 26 ---------------------- src/vehicle_base.h | 4 ---- 15 files changed, 157 deletions(-) diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp index 44a45ac7fc..cfaab25986 100644 --- a/src/articulated_vehicles.cpp +++ b/src/articulated_vehicles.cpp @@ -225,20 +225,6 @@ CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial return union_mask; } -/** - * Ands the refit_masks of all articulated parts. - * @param engine the first part - * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask - * @return bit mask of CargoIDs which are a refit option for every articulated part (with default capacity > 0) - */ -CargoTypes GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type) -{ - CargoTypes union_mask, intersection_mask; - GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask); - return intersection_mask; -} - - /** * Tests if all parts of an articulated vehicle are refitted to the same cargo. * Note: Vehicles not carrying anything are ignored diff --git a/src/articulated_vehicles.h b/src/articulated_vehicles.h index a98833b003..819c27d3c1 100644 --- a/src/articulated_vehicles.h +++ b/src/articulated_vehicles.h @@ -18,7 +18,6 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine); void AddArticulatedParts(Vehicle *first); void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask); CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type); -CargoTypes GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type); bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type); bool IsArticulatedVehicleRefittable(EngineID engine); bool IsArticulatedEngine(EngineID engine_type); diff --git a/src/group.h b/src/group.h index ca867985bc..05a203a53c 100644 --- a/src/group.h +++ b/src/group.h @@ -110,7 +110,6 @@ Money GetGroupProfitLastYearMinAge(CompanyID company, GroupID id_g, VehicleType void SetTrainGroupID(Train *v, GroupID grp); void UpdateTrainGroupID(Train *v); -void RemoveVehicleFromGroup(const Vehicle *v); void RemoveAllGroupsForCompany(const CompanyID company); bool GroupIsInGroup(GroupID search, GroupID group); diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index e202177884..4fded9ebbf 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -714,19 +714,6 @@ CommandCost CmdSetGroupFlag(DoCommandFlag flags, GroupID group_id, GroupFlags fl return CommandCost(); } -/** - * Decrease the num_vehicle variable before delete an front engine from a group - * @note Called in CmdSellRailWagon and DeleteLasWagon, - * @param v FrontEngine of the train we want to remove. - */ -void RemoveVehicleFromGroup(const Vehicle *v) -{ - if (!v->IsPrimaryVehicle()) return; - - if (!IsDefaultGroupID(v->group_id)) GroupStatistics::CountVehicle(v, -1); -} - - /** * Affect the groupID of a train to new_g. * @note called in CmdAddVehicleGroup and CmdMoveRailVehicle diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index a4b984ca88..40c4d87156 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -744,8 +744,6 @@ struct TextRefStack { this->grffile = grffile; this->used = true; } - - void RewindStack() { this->position = 0; } }; /** The stack that is used for TTDP compatible string code parsing */ @@ -819,11 +817,6 @@ void StopTextRefStackUsage() _newgrf_textrefstack.used = false; } -void RewindTextRefStack() -{ - _newgrf_textrefstack.RewindStack(); -} - /** * FormatString for NewGRF specific "magic" string control codes * @param scc the string control code that has been read diff --git a/src/newgrf_text.h b/src/newgrf_text.h index c3dfa08cee..66f591f588 100644 --- a/src/newgrf_text.h +++ b/src/newgrf_text.h @@ -45,7 +45,6 @@ bool CheckGrfLangID(byte lang_id, byte grf_version); void StartTextRefStackUsage(const struct GRFFile *grffile, byte numEntries, const uint32_t *values = nullptr); void StopTextRefStackUsage(); -void RewindTextRefStack(); bool UsingNewGRFTextStack(); struct TextRefStack *CreateTextRefStackBackup(); void RestoreTextRefStackBackup(struct TextRefStack *backup); diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 35133be345..756cf2e317 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -87,16 +87,6 @@ class BuildObjectWindow : public Window { return objclass->GetSpec(_selected_object_index)->IsAvailable(); } - /** - * Calculate the number of columns of the #WID_BO_SELECT_MATRIX widget. - * @return Number of columns in the matrix. - */ - uint GetMatrixColumnCount() - { - const NWidgetBase *matrix = this->GetWidget(WID_BO_SELECT_MATRIX); - return 1 + (matrix->current_x - matrix->smallest_x) / matrix->resize_x; - } - public: BuildObjectWindow(WindowDesc *desc, WindowNumber number) : Window(desc), info_height(1), filter_editbox(EDITBOX_MAX_SIZE * MAX_CHAR_LENGTH, EDITBOX_MAX_SIZE) { diff --git a/src/order_base.h b/src/order_base.h index c607d97942..577dbe4c47 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -350,9 +350,6 @@ public: */ inline uint GetNumVehicles() const { return this->num_vehicles; } - bool IsVehicleInSharedOrdersList(const Vehicle *v) const; - int GetPositionInSharedOrderList(const Vehicle *v) const; - /** * Adds the given vehicle to this shared order list. * @note This is supposed to be called after the vehicle has been inserted diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index e20eac5056..fc32913bdc 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -571,31 +571,6 @@ void OrderList::RemoveVehicle(Vehicle *v) if (v == this->first_shared) this->first_shared = v->NextShared(); } -/** - * Checks whether a vehicle is part of the shared vehicle chain. - * @param v is the vehicle to search in the shared vehicle chain. - */ -bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const -{ - for (const Vehicle *v_shared = this->first_shared; v_shared != nullptr; v_shared = v_shared->NextShared()) { - if (v_shared == v) return true; - } - - return false; -} - -/** - * Gets the position of the given vehicle within the shared order vehicle list. - * @param v is the vehicle of which to get the position - * @return position of v within the shared vehicle chain. - */ -int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const -{ - int count = 0; - for (const Vehicle *v_shared = v->PreviousShared(); v_shared != nullptr; v_shared = v_shared->PreviousShared()) count++; - return count; -} - /** * Checks whether all orders of the list have a filled timetable. * @return whether all orders have a filled timetable. diff --git a/src/pathfinder/yapf/yapf_road.cpp b/src/pathfinder/yapf/yapf_road.cpp index 13854dbfcc..86749c4f23 100644 --- a/src/pathfinder/yapf/yapf_road.cpp +++ b/src/pathfinder/yapf/yapf_road.cpp @@ -427,12 +427,6 @@ public: return next_trackdir; } - static uint stDistanceToTile(const RoadVehicle *v, TileIndex tile) - { - Tpf pf; - return pf.DistanceToTile(v, tile); - } - inline uint DistanceToTile(const RoadVehicle *v, TileIndex dst_tile) { /* handle special case - when current tile is the destination tile */ diff --git a/src/road.cpp b/src/road.cpp index d2b4144fdd..bf607fdb36 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -270,39 +270,3 @@ RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels) /* No matching label was found, so it is invalid */ return INVALID_ROADTYPE; } - -/** - * Returns the available RoadSubTypes for the provided RoadType - * If the given company is valid then will be returned a list of the available sub types at the current date, while passing - * a deity company will make all the sub types available - * @param rt the RoadType to filter - * @param c the company ID to check the roadtype against - * @param any_date whether to return only currently introduced roadtypes or also future ones - * @returns the existing RoadSubTypes - */ -RoadTypes ExistingRoadTypes(CompanyID c) -{ - /* Check only players which can actually own vehicles, editor and gamescripts are considered deities */ - if (c < OWNER_END) { - const Company *company = Company::GetIfValid(c); - if (company != nullptr) return company->avail_roadtypes; - } - - RoadTypes known_roadtypes = ROADTYPES_NONE; - - /* Find used roadtypes */ - for (Engine *e : Engine::IterateType(VEH_ROAD)) { - /* Check if the roadtype can be used in the current climate */ - if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; - - /* Check whether available for all potential companies */ - if (e->company_avail != MAX_UVALUE(CompanyMask)) continue; - - known_roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes; - } - - /* Get the date introduced roadtypes as well. */ - known_roadtypes = AddDateIntroducedRoadTypes(known_roadtypes, CalendarTime::MAX_DATE); - - return known_roadtypes; -} diff --git a/src/strings.cpp b/src/strings.cpp index 0eb4393dc6..56f7ed452f 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1957,14 +1957,6 @@ const char *GetCurrentLocale(const char *param) const char *GetCurrentLocale(const char *param); #endif /* !(defined(_WIN32) || defined(__APPLE__)) */ -bool StringIDSorter(const StringID &a, const StringID &b) -{ - std::string stra = GetString(a); - std::string strb = GetString(b); - - return StrNaturalCompare(stra, strb) < 0; -} - /** * Get the language with the given NewGRF language ID. * @param newgrflangid NewGRF languages ID to check. diff --git a/src/strings_func.h b/src/strings_func.h index 03fb1becb2..38417a85b7 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -110,8 +110,6 @@ extern TextDirection _current_text_dir; ///< Text direction of the currently sel void InitializeLanguagePacks(); const char *GetCurrentLanguageIsoCode(); -bool StringIDSorter(const StringID &a, const StringID &b); - /** * A searcher for missing glyphs. */ diff --git a/src/vehicle.cpp b/src/vehicle.cpp index d995547d63..2fc8ee6cc1 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2353,32 +2353,6 @@ void Vehicle::HandleLoading(bool mode) this->IncrementImplicitOrderIndex(); } -/** - * Get a map of cargoes and free capacities in the consist. - * @param capacities Map to be filled with cargoes and capacities. - */ -void Vehicle::GetConsistFreeCapacities(std::map &capacities) const -{ - for (const Vehicle *v = this; v != nullptr; v = v->Next()) { - if (v->cargo_cap == 0) continue; - auto pair = capacities.find(v->cargo_type); - if (pair == capacities.end()) { - capacities[v->cargo_type] = v->cargo_cap - v->cargo.StoredCount(); - } else { - pair->second += v->cargo_cap - v->cargo.StoredCount(); - } - } -} - -uint Vehicle::GetConsistTotalCapacity() const -{ - uint result = 0; - for (const Vehicle *v = this; v != nullptr; v = v->Next()) { - result += v->cargo_cap; - } - return result; -} - /** * Send this vehicle to the depot using the given command(s). * @param flags the command flags (like execute and such). diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 62de9a368a..74369a856c 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -391,10 +391,6 @@ public: void HandleLoading(bool mode = false); - void GetConsistFreeCapacities(std::map &capacities) const; - - uint GetConsistTotalCapacity() const; - /** * Marks the vehicles to be redrawn and updates cached variables * From c294eaacc1b365dfc1ef177a865c5d4c7e69d657 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Fri, 3 Nov 2023 00:40:17 +0100 Subject: [PATCH 31/57] Fix: char_traits::find needs to return nullptr if nothing was found. --- src/string.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/string.cpp b/src/string.cpp index 7e8870b795..7e54b63912 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -343,12 +343,12 @@ struct CaseInsensitiveCharTraits : public std::char_traits { return 0; } - static const char *find(const char *s, int n, char a) + static const char *find(const char *s, size_t n, char a) { - while (n-- > 0 && toupper(*s) != toupper(a)) { - ++s; + for (; n > 0; --n, ++s) { + if (toupper(*s) == toupper(a)) return s; } - return s; + return nullptr; } }; From 86e28e79fbc59e8a61106b76e026aba324374684 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Fri, 3 Nov 2023 20:43:18 +0100 Subject: [PATCH 32/57] Fix #11402: Make string filter locale-aware. --- src/os/macosx/string_osx.cpp | 25 ++++++++++ src/os/macosx/string_osx.h | 1 + src/os/windows/win32.cpp | 39 +++++++++++++++ src/os/windows/win32.h | 1 + src/script/script_gui.cpp | 2 +- src/string.cpp | 92 ++++++++++++++++++++++++++++++++++++ src/string_func.h | 2 + src/stringfilter.cpp | 13 +++-- src/stringfilter_type.h | 3 +- 9 files changed, 173 insertions(+), 5 deletions(-) diff --git a/src/os/macosx/string_osx.cpp b/src/os/macosx/string_osx.cpp index 66e17e18f4..cd281257b0 100644 --- a/src/os/macosx/string_osx.cpp +++ b/src/os/macosx/string_osx.cpp @@ -336,6 +336,31 @@ int MacOSStringCompare(std::string_view s1, std::string_view s2) return (int)CFStringCompareWithOptionsAndLocale(cf1.get(), cf2.get(), CFRangeMake(0, CFStringGetLength(cf1.get())), flags, _osx_locale.get()) + 2; } +/** + * Search if a string is contained in another string using the current locale. + * + * @param str String to search in. + * @param value String to search for. + * @param case_insensitive Search case-insensitive. + * @return 1 if value was found, 0 if it was not found, or -1 if not supported by the OS. + */ +int MacOSStringContains(const std::string_view str, const std::string_view value, bool case_insensitive) +{ + static bool supported = MacOSVersionIsAtLeast(10, 5, 0); + if (!supported) return -1; + + CFStringCompareFlags flags = kCFCompareLocalized | kCFCompareWidthInsensitive; + if (case_insensitive) flags |= kCFCompareCaseInsensitive; + + CFAutoRelease cf_str(CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)str.data(), str.size(), kCFStringEncodingUTF8, false)); + CFAutoRelease cf_value(CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)value.data(), value.size(), kCFStringEncodingUTF8, false)); + + /* If any CFString could not be created (e.g., due to UTF8 invalid chars), return OS unsupported functionality */ + if (cf_str == nullptr || cf_value == nullptr) return -1; + + return CFStringFindWithOptionsAndLocale(cf_str.get(), cf_value.get(), CFRangeMake(0, CFStringGetLength(cf_str.get())), flags, _osx_locale.get(), nullptr) ? 1 : 0; +} + /* virtual */ void OSXStringIterator::SetString(const char *s) { diff --git a/src/os/macosx/string_osx.h b/src/os/macosx/string_osx.h index 8fd9d988dc..8d475882e2 100644 --- a/src/os/macosx/string_osx.h +++ b/src/os/macosx/string_osx.h @@ -84,6 +84,7 @@ public: void MacOSResetScriptCache(FontSize size); void MacOSSetCurrentLocaleName(const char *iso_code); int MacOSStringCompare(std::string_view s1, std::string_view s2); +int MacOSStringContains(const std::string_view str, const std::string_view value, bool case_insensitive); void MacOSRegisterExternalFont(const char *file_path); diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 3611dfe1af..0b732ca431 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -19,6 +19,7 @@ #define NO_SHOBJIDL_SORTDIRECTION // Avoid multiple definition of SORT_ASCENDING #include /* SHGetFolderPath */ #include +#include #include "win32.h" #include "../../fios.h" #include "../../core/alloc_func.hpp" @@ -601,6 +602,44 @@ int OTTDStringCompare(std::string_view s1, std::string_view s2) return CompareString(MAKELCID(_current_language->winlangid, SORT_DEFAULT), NORM_IGNORECASE, s1_buf, -1, s2_buf, -1); } +/** + * Search if a string is contained in another string using the current locale. + * + * @param str String to search in. + * @param value String to search for. + * @param case_insensitive Search case-insensitive. + * @return 1 if value was found, 0 if it was not found, or -1 if not supported by the OS. + */ +int Win32StringContains(const std::string_view str, const std::string_view value, bool case_insensitive) +{ + typedef int (WINAPI *PFNFINDNLSSTRINGEX)(LPCWSTR, DWORD, LPCWSTR, int, LPCWSTR, int, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM); + static PFNFINDNLSSTRINGEX _FindNLSStringEx = nullptr; + static bool first_time = true; + + if (first_time) { + static DllLoader _kernel32(L"Kernel32.dll"); + _FindNLSStringEx = _kernel32.GetProcAddress("FindNLSStringEx"); + first_time = false; + } + + if (_FindNLSStringEx != nullptr) { + int len_str = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0); + int len_value = MultiByteToWideChar(CP_UTF8, 0, value.data(), (int)value.size(), nullptr, 0); + + if (len_str != 0 && len_value != 0) { + std::wstring str_str(len_str, L'\0'); // len includes terminating null + std::wstring str_value(len_value, L'\0'); + + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), str_str.data(), len_str); + MultiByteToWideChar(CP_UTF8, 0, value.data(), (int)value.size(), str_value.data(), len_value); + + return _FindNLSStringEx(_cur_iso_locale, FIND_FROMSTART | (case_insensitive ? LINGUISTIC_IGNORECASE : 0), str_str.data(), -1, str_value.data(), -1, nullptr, nullptr, nullptr, 0) >= 0 ? 1 : 0; + } + } + + return -1; // Failure indication. +} + #ifdef _MSC_VER /* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ const DWORD MS_VC_EXCEPTION = 0x406D1388; diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h index ab19a7d1ae..561d471bac 100644 --- a/src/os/windows/win32.h +++ b/src/os/windows/win32.h @@ -60,5 +60,6 @@ wchar_t *convert_to_fs(const std::string_view name, wchar_t *utf16_buf, size_t b void Win32SetCurrentLocaleName(const char *iso_code); int OTTDStringCompare(std::string_view s1, std::string_view s2); +int Win32StringContains(const std::string_view str, const std::string_view value, bool case_insensitive); #endif /* WIN32_H */ diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index f393917c4e..39cf1a00a1 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -1139,7 +1139,7 @@ CompanyID ScriptDebugWindow::script_debug_company = INVALID_COMPANY; std::string ScriptDebugWindow::break_string; bool ScriptDebugWindow::break_check_enabled = true; bool ScriptDebugWindow::case_sensitive_break_check = false; -StringFilter ScriptDebugWindow::break_string_filter(&ScriptDebugWindow::case_sensitive_break_check); +StringFilter ScriptDebugWindow::break_string_filter(&ScriptDebugWindow::case_sensitive_break_check, false); /** Make a number of rows with buttons for each company for the Script debug window. */ NWidgetBase *MakeCompanyButtonRowsScriptDebug(int *biggest_index) diff --git a/src/string.cpp b/src/string.cpp index 7e54b63912..020fd2fd47 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -635,6 +635,98 @@ int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garb return StrCompareIgnoreCase(s1, s2); } +#ifdef WITH_ICU_I18N + +#include + +/** + * Search if a string is contained in another string using the current locale. + * + * @param str String to search in. + * @param value String to search for. + * @param case_insensitive Search case-insensitive. + * @return 1 if value was found, 0 if it was not found, or -1 if not supported by the OS. + */ +static int ICUStringContains(const std::string_view str, const std::string_view value, bool case_insensitive) +{ + if (_current_collator) { + std::unique_ptr coll(dynamic_cast(_current_collator->clone())); + if (coll) { + UErrorCode status = U_ZERO_ERROR; + coll->setStrength(case_insensitive ? icu::Collator::SECONDARY : icu::Collator::TERTIARY); + coll->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_OFF, status); + + auto u_str = icu::UnicodeString::fromUTF8(icu::StringPiece(str.data(), str.size())); + auto u_value = icu::UnicodeString::fromUTF8(icu::StringPiece(value.data(), value.size())); + icu::StringSearch u_searcher(u_value, u_str, coll.get(), nullptr, status); + if (U_SUCCESS(status)) { + auto pos = u_searcher.first(status); + if (U_SUCCESS(status)) return pos != USEARCH_DONE ? 1 : 0; + } + } + } + + return -1; +} +#endif /* WITH_ICU_I18N */ + +/** + * Checks if a string is contained in another string with a locale-aware comparison that is case sensitive. + * + * @param str The string to search in. + * @param value The string to search for. + * @return True if a match was found. + */ +[[nodiscard]] bool StrNaturalContains(const std::string_view str, const std::string_view value) +{ +#ifdef WITH_ICU_I18N + int res_u = ICUStringContains(str, value, false); + if (res_u >= 0) return res_u > 0; +#endif /* WITH_ICU_I18N */ + +#if defined(_WIN32) && !defined(STRGEN) && !defined(SETTINGSGEN) + int res = Win32StringContains(str, value, false); + if (res >= 0) return res > 0; +#endif + +#if defined(WITH_COCOA) && !defined(STRGEN) && !defined(SETTINGSGEN) + int res = MacOSStringContains(str, value, false); + if (res >= 0) return res > 0; +#endif + + return str.find(value) != std::string_view::npos; +} + +/** + * Checks if a string is contained in another string with a locale-aware comparison that is case insensitive. + * + * @param str The string to search in. + * @param value The string to search for. + * @return True if a match was found. + */ +[[nodiscard]] bool StrNaturalContainsIgnoreCase(const std::string_view str, const std::string_view value) +{ +#ifdef WITH_ICU_I18N + int res_u = ICUStringContains(str, value, true); + if (res_u >= 0) return res_u > 0; +#endif /* WITH_ICU_I18N */ + +#if defined(_WIN32) && !defined(STRGEN) && !defined(SETTINGSGEN) + int res = Win32StringContains(str, value, true); + if (res >= 0) return res > 0; +#endif + +#if defined(WITH_COCOA) && !defined(STRGEN) && !defined(SETTINGSGEN) + int res = MacOSStringContains(str, value, true); + if (res >= 0) return res > 0; +#endif + + CaseInsensitiveStringView ci_str{ str.data(), str.size() }; + CaseInsensitiveStringView ci_value{ value.data(), value.size() }; + return ci_str.find(ci_value) != CaseInsensitiveStringView::npos; +} + + #ifdef WITH_UNISCRIBE /* static */ std::unique_ptr StringIterator::Create() diff --git a/src/string_func.h b/src/string_func.h index 21e24b5114..876659c43d 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -39,6 +39,8 @@ void StrTrimInPlace(std::string &str); [[nodiscard]] int StrCompareIgnoreCase(const std::string_view str1, const std::string_view str2); [[nodiscard]] bool StrEqualsIgnoreCase(const std::string_view str1, const std::string_view str2); [[nodiscard]] int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front = false); +[[nodiscard]] bool StrNaturalContains(const std::string_view str, const std::string_view value); +[[nodiscard]] bool StrNaturalContainsIgnoreCase(const std::string_view str, const std::string_view value); /** Case insensitive comparator for strings, for example for use in std::map. */ struct CaseInsensitiveComparator { diff --git a/src/stringfilter.cpp b/src/stringfilter.cpp index 87a8bd5f3f..16800c2440 100644 --- a/src/stringfilter.cpp +++ b/src/stringfilter.cpp @@ -118,9 +118,16 @@ void StringFilter::AddLine(const char *str) bool match_case = this->case_sensitive != nullptr && *this->case_sensitive; for (WordState &ws : this->word_index) { if (!ws.match) { - if ((match_case ? strstr(str, ws.start) : strcasestr(str, ws.start)) != nullptr) { - ws.match = true; - this->word_matches++; + if (this->locale_aware) { + if (match_case ? StrNaturalContains(str, ws.start) : StrNaturalContainsIgnoreCase(str, ws.start)) { + ws.match = true; + this->word_matches++; + } + } else { + if ((match_case ? strstr(str, ws.start) : strcasestr(str, ws.start)) != nullptr) { + ws.match = true; + this->word_matches++; + } } } } diff --git a/src/stringfilter_type.h b/src/stringfilter_type.h index 1d3098abad..ec7d545fd8 100644 --- a/src/stringfilter_type.h +++ b/src/stringfilter_type.h @@ -40,13 +40,14 @@ private: uint word_matches; ///< Summary of filter state: Number of words matched. const bool *case_sensitive; ///< Match case-sensitively (usually a static variable). + bool locale_aware; ///< Match words using the current locale. public: /** * Constructor for filter. * @param case_sensitive Pointer to a (usually static) variable controlling the case-sensitivity. nullptr means always case-insensitive. */ - StringFilter(const bool *case_sensitive = nullptr) : filter_buffer(nullptr), word_matches(0), case_sensitive(case_sensitive) {} + StringFilter(const bool *case_sensitive = nullptr, bool locale_aware = true) : filter_buffer(nullptr), word_matches(0), case_sensitive(case_sensitive), locale_aware(locale_aware) {} ~StringFilter() { free(this->filter_buffer); } void SetFilterTerm(const char *str); From db6b32e421b4a7e5ea26cd63af424c59185db5cf Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 3 Nov 2023 23:15:37 +0000 Subject: [PATCH 33/57] Codechange: Avoid pointers and lengthof in ExpensesList. (#11427) Use std::initializer_list which allows iteration. --- src/company_gui.cpp | 61 +++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/src/company_gui.cpp b/src/company_gui.cpp index e35cc5e4fc..0df7e23cd4 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -55,7 +55,7 @@ static void DoSelectCompanyManagerFace(Window *parent); static void ShowCompanyInfrastructure(CompanyID company); /** List of revenues. */ -static ExpensesType _expenses_list_revenue[] = { +static const std::initializer_list _expenses_list_revenue = { EXPENSES_TRAIN_REVENUE, EXPENSES_ROADVEH_REVENUE, EXPENSES_AIRCRAFT_REVENUE, @@ -63,7 +63,7 @@ static ExpensesType _expenses_list_revenue[] = { }; /** List of operating expenses. */ -static ExpensesType _expenses_list_operating_costs[] = { +static const std::initializer_list _expenses_list_operating_costs = { EXPENSES_TRAIN_RUN, EXPENSES_ROADVEH_RUN, EXPENSES_AIRCRAFT_RUN, @@ -73,7 +73,7 @@ static ExpensesType _expenses_list_operating_costs[] = { }; /** List of capital expenses. */ -static ExpensesType _expenses_list_capital_costs[] = { +static const std::initializer_list _expenses_list_capital_costs = { EXPENSES_CONSTRUCTION, EXPENSES_NEW_VEHICLES, EXPENSES_OTHER, @@ -81,25 +81,24 @@ static ExpensesType _expenses_list_capital_costs[] = { /** Expense list container. */ struct ExpensesList { - const ExpensesType *et; ///< Expenses items. - const uint length; ///< Number of items in list. + const StringID title; ///< StringID of list title. + const std::initializer_list &items; ///< List of expenses types. - ExpensesList(ExpensesType *et, int length) : et(et), length(length) + ExpensesList(StringID title, const std::initializer_list &list) : title(title), items(list) { } uint GetHeight() const { /* Add up the height of all the lines. */ - return this->length * FONT_HEIGHT_NORMAL; + return static_cast(this->items.size()) * FONT_HEIGHT_NORMAL; } /** Compute width of the expenses categories in pixels. */ uint GetListWidth() const { uint width = 0; - for (uint i = 0; i < this->length; i++) { - ExpensesType et = this->et[i]; + for (const ExpensesType &et : this->items) { width = std::max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width); } return width; @@ -107,10 +106,10 @@ struct ExpensesList { }; /** Types of expense lists */ -static const ExpensesList _expenses_list_types[] = { - ExpensesList(_expenses_list_revenue, lengthof(_expenses_list_revenue)), - ExpensesList(_expenses_list_operating_costs, lengthof(_expenses_list_operating_costs)), - ExpensesList(_expenses_list_capital_costs, lengthof(_expenses_list_capital_costs)), +static const std::initializer_list _expenses_list_types = { + { STR_FINANCES_REVENUE_TITLE, _expenses_list_revenue }, + { STR_FINANCES_OPERATING_EXPENSES_TITLE, _expenses_list_operating_costs }, + { STR_FINANCES_CAPITAL_EXPENSES_TITLE, _expenses_list_capital_costs }, }; /** @@ -122,9 +121,9 @@ static uint GetTotalCategoriesHeight() /* There's an empty line and blockspace on the year row */ uint total_height = FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide; - for (uint i = 0; i < lengthof(_expenses_list_types); i++) { + for (const ExpensesList &list : _expenses_list_types) { /* Title + expense list + total line + total + blockspace after category */ - total_height += FONT_HEIGHT_NORMAL + _expenses_list_types[i].GetHeight() + WidgetDimensions::scaled.vsep_normal + FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide; + total_height += FONT_HEIGHT_NORMAL + list.GetHeight() + WidgetDimensions::scaled.vsep_normal + FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide; } /* Total income */ @@ -142,11 +141,11 @@ static uint GetMaxCategoriesWidth() uint max_width = 0; /* Loop through categories to check max widths. */ - for (uint i = 0; i < lengthof(_expenses_list_types); i++) { + for (const ExpensesList &list : _expenses_list_types) { /* Title of category */ - max_width = std::max(max_width, GetStringBoundingBox(STR_FINANCES_REVENUE_TITLE + i).width); + max_width = std::max(max_width, GetStringBoundingBox(list.title).width); /* Entries in category */ - max_width = std::max(max_width, _expenses_list_types[i].GetListWidth() + WidgetDimensions::scaled.hsep_indent); + max_width = std::max(max_width, list.GetListWidth() + WidgetDimensions::scaled.hsep_indent); } return max_width; @@ -155,15 +154,13 @@ static uint GetMaxCategoriesWidth() /** * Draw a category of expenses (revenue, operating expenses, capital expenses). */ -static void DrawCategory(const Rect &r, int start_y, ExpensesList list) +static void DrawCategory(const Rect &r, int start_y, const ExpensesList &list) { Rect tr = r.Indent(WidgetDimensions::scaled.hsep_indent, _current_text_dir == TD_RTL); tr.top = start_y; - ExpensesType et; - for (uint i = 0; i < list.length; i++) { - et = list.et[i]; + for (const ExpensesType &et : list.items) { DrawString(tr, STR_FINANCES_SECTION_CONSTRUCTION + et); tr.top += FONT_HEIGHT_NORMAL; } @@ -179,14 +176,14 @@ static void DrawCategories(const Rect &r) /* Start with an empty space in the year row, plus the blockspace under the year. */ int y = r.top + FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide; - for (uint i = 0; i < lengthof(_expenses_list_types); i++) { + for (const ExpensesList &list : _expenses_list_types) { /* Draw category title and advance y */ - DrawString(r.left, r.right, y, (STR_FINANCES_REVENUE_TITLE + i), TC_FROMSTRING, SA_LEFT); + DrawString(r.left, r.right, y, list.title, TC_FROMSTRING, SA_LEFT); y += FONT_HEIGHT_NORMAL; /* Draw category items and advance y */ - DrawCategory(r, y, _expenses_list_types[i]); - y += _expenses_list_types[i].GetHeight(); + DrawCategory(r, y, list); + y += list.GetHeight(); /* Advance y by the height of the horizontal line between amounts and subtotal */ y += WidgetDimensions::scaled.vsep_normal; @@ -229,14 +226,12 @@ static void DrawPrice(Money amount, int left, int right, int top, TextColour col * Draw a category of expenses/revenues in the year column. * @return The income sum of the category. */ -static Money DrawYearCategory(const Rect &r, int start_y, ExpensesList list, const Expenses &tbl) +static Money DrawYearCategory(const Rect &r, int start_y, const ExpensesList &list, const Expenses &tbl) { int y = start_y; - ExpensesType et; Money sum = 0; - for (uint i = 0; i < list.length; i++) { - et = list.et[i]; + for (const ExpensesType &et : list.items) { Money cost = tbl[et]; sum += cost; if (cost != 0) DrawPrice(cost, r.left, r.right, y, TC_BLACK); @@ -271,11 +266,11 @@ static void DrawYearColumn(const Rect &r, TimerGameCalendar::Year year, const Ex y += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide; /* Categories */ - for (uint i = 0; i < lengthof(_expenses_list_types); i++) { + for (const ExpensesList &list : _expenses_list_types) { y += FONT_HEIGHT_NORMAL; - sum += DrawYearCategory(r, y, _expenses_list_types[i], tbl); + sum += DrawYearCategory(r, y, list, tbl); /* Expense list + expense category title + expense category total + blockspace after category */ - y += _expenses_list_types[i].GetHeight() + WidgetDimensions::scaled.vsep_normal + FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide; + y += list.GetHeight() + WidgetDimensions::scaled.vsep_normal + FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide; } /* Total income. */ From c059ce0c97b653914e94808ef2e2a8c9e0ff75ad Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 4 Nov 2023 11:39:18 +0100 Subject: [PATCH 34/57] Fix cda6f24f: don't ignore binary-dir if it happens to be working-dir (#11431) Some of our code ignores the SP_WORKING_DIR for some actions, which means that if, for example, your SP_BINARY_DIR is the same as your SP_WORKING_DIR, neither is scanned. Instead, only add SP_WORKING_DIR if it is unique. --- src/fileio.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fileio.cpp b/src/fileio.cpp index aef3c1844e..b0edd86b5c 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -87,6 +87,8 @@ static void FillValidSearchPaths(bool only_local_path) std::set seen{}; for (Searchpath sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) { + if (sp == SP_WORKING_DIR) continue; + if (only_local_path) { switch (sp) { case SP_WORKING_DIR: // Can be influence by "-c" option. @@ -105,6 +107,13 @@ static void FillValidSearchPaths(bool only_local_path) _valid_searchpaths.emplace_back(sp); } } + + /* The working-directory is special, as it is controlled by _do_scan_working_directory. + * Only add the search path if it isn't already in the set. To preserve the same order + * as the enum, insert it in the front. */ + if (IsValidSearchPath(SP_WORKING_DIR) && seen.count(_searchpaths[SP_WORKING_DIR]) == 0) { + _valid_searchpaths.insert(_valid_searchpaths.begin(), SP_WORKING_DIR); + } } /** From bbd64bbe2bbf37cdc34b859c35a6361f1489fd1d Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 4 Nov 2023 14:42:47 +0000 Subject: [PATCH 35/57] Fix #9545: Crash when all cargo types are disabled. (#11432) This is not a very useful state, but it's nice to not crash. Some parts of the game don't (yet) check for cargo types being redefined, that is out-of-scope here. --- src/graph_gui.cpp | 5 +++-- src/linkgraph/linkgraph_gui.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 27c67e3f08..c84eaf8b08 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -363,7 +363,6 @@ protected: if (this->num_on_x_axis == 0) return; assert(this->num_on_x_axis > 0); - assert(this->num_dataset > 0); /* draw text strings on the y axis */ int64_t y_label = interval.highest; @@ -923,6 +922,8 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { return; } + size->height = FONT_HEIGHT_SMALL + WidgetDimensions::scaled.framerect.Vertical(); + for (const CargoSpec *cs : _sorted_standard_cargo_specs) { SetDParam(0, cs->name); Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO); @@ -1077,7 +1078,7 @@ static const NWidgetPart _nested_cargo_payment_rates_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_CPR_DISABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0), NWidget(NWID_SPACER), SetMinimalSize(0, 4), NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_BROWN, WID_CPR_MATRIX), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR), + NWidget(WWT_MATRIX, COLOUR_BROWN, WID_CPR_MATRIX), SetFill(1, 0), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_CPR_MATRIX_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_CPR_MATRIX_SCROLLBAR), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index 2c666ef515..2fb08618d2 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -501,7 +501,8 @@ NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index) spc->SetResize(0, 0); col->Add(spc); } - panel->Add(col); + /* If there are no cargo specs defined, then col won't have been created so don't add it. */ + if (col != nullptr) panel->Add(col); *biggest_index = WID_LGL_CARGO_LAST; return panel; } From 071fdab236339f4bc2a7069051736b645789b935 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sat, 4 Nov 2023 15:20:21 +0100 Subject: [PATCH 36/57] Codechange: Replicate cursor screen backup to chat message display, removing explicit memory management. Incidentally, this makes Blitter::GetBytesPerPixel unneeed. --- src/blitter/32bpp_anim.hpp | 1 - src/blitter/32bpp_base.hpp | 1 - src/blitter/40bpp_anim.hpp | 1 - src/blitter/8bpp_base.hpp | 1 - src/blitter/base.hpp | 5 ----- src/blitter/null.hpp | 1 - src/network/network_chat_gui.cpp | 10 ++++------ 7 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/blitter/32bpp_anim.hpp b/src/blitter/32bpp_anim.hpp index 125295c41e..b5b19d784e 100644 --- a/src/blitter/32bpp_anim.hpp +++ b/src/blitter/32bpp_anim.hpp @@ -48,7 +48,6 @@ public: Blitter::PaletteAnimation UsePaletteAnimation() override; const char *GetName() override { return "32bpp-anim"; } - int GetBytesPerPixel() override { return 6; } void PostResize() override; /** diff --git a/src/blitter/32bpp_base.hpp b/src/blitter/32bpp_base.hpp index a1e1002cb8..f5d8a30c4e 100644 --- a/src/blitter/32bpp_base.hpp +++ b/src/blitter/32bpp_base.hpp @@ -30,7 +30,6 @@ public: size_t BufferSize(uint width, uint height) override; void PaletteAnimate(const Palette &palette) override; Blitter::PaletteAnimation UsePaletteAnimation() override; - int GetBytesPerPixel() override { return 4; } /** * Look up the colour in the current palette. diff --git a/src/blitter/40bpp_anim.hpp b/src/blitter/40bpp_anim.hpp index ecc7eb110d..fac3d64d3c 100644 --- a/src/blitter/40bpp_anim.hpp +++ b/src/blitter/40bpp_anim.hpp @@ -33,7 +33,6 @@ public: bool NeedsAnimationBuffer() override; const char *GetName() override { return "40bpp-anim"; } - int GetBytesPerPixel() override { return 5; } template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); diff --git a/src/blitter/8bpp_base.hpp b/src/blitter/8bpp_base.hpp index 1d29333984..5a76d79521 100644 --- a/src/blitter/8bpp_base.hpp +++ b/src/blitter/8bpp_base.hpp @@ -28,7 +28,6 @@ public: size_t BufferSize(uint width, uint height) override; void PaletteAnimate(const Palette &palette) override; Blitter::PaletteAnimation UsePaletteAnimation() override; - int GetBytesPerPixel() override { return 1; } }; #endif /* BLITTER_8BPP_BASE_HPP */ diff --git a/src/blitter/base.hpp b/src/blitter/base.hpp index 1555d040f1..e55f9294e4 100644 --- a/src/blitter/base.hpp +++ b/src/blitter/base.hpp @@ -198,11 +198,6 @@ public: */ virtual const char *GetName() = 0; - /** - * Get how many bytes are needed to store a pixel. - */ - virtual int GetBytesPerPixel() = 0; - /** * Post resize event */ diff --git a/src/blitter/null.hpp b/src/blitter/null.hpp index 26e807c061..abf2a5b59f 100644 --- a/src/blitter/null.hpp +++ b/src/blitter/null.hpp @@ -32,7 +32,6 @@ public: Blitter::PaletteAnimation UsePaletteAnimation() override { return Blitter::PALETTE_ANIMATION_NONE; }; const char *GetName() override { return "null"; } - int GetBytesPerPixel() override { return 0; } }; /** Factory for the blitter that does nothing. */ diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 24b328d92a..cdb2d1fba1 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -58,7 +58,7 @@ static std::chrono::steady_clock::time_point _chatmessage_dirty_time; * the left and pixels from the bottom. The height is the maximum height. */ static PointDimension _chatmsg_box; -static uint8_t *_chatmessage_backup = nullptr; ///< Backup in case text is moved. +static ReusableBuffer _chatmessage_backup; ///< Backup in case text is moved. /** * Test if there are any chat messages to display. @@ -103,7 +103,6 @@ void NetworkReInitChatBoxSize() { _chatmsg_box.y = 3 * FONT_HEIGHT_NORMAL; _chatmsg_box.height = MAX_CHAT_MESSAGES * (FONT_HEIGHT_NORMAL + ScaleGUITrad(NETWORK_CHAT_LINE_SPACING)) + ScaleGUITrad(4); - _chatmessage_backup = ReallocT(_chatmessage_backup, static_cast(_chatmsg_box.width) * _chatmsg_box.height * BlitterFactory::GetCurrentBlitter()->GetBytesPerPixel()); } /** Initialize all buffers of the chat visualisation. */ @@ -156,7 +155,7 @@ void NetworkUndrawChatMessage() _chatmessage_visible = false; /* Put our 'shot' back to the screen */ - blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height); + blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup.GetBuffer(), width, height); /* And make sure it is updated next time */ VideoDriver::GetInstance()->MakeDirty(x, y, width, height); @@ -208,10 +207,9 @@ void NetworkDrawChatMessage() } if (width <= 0 || height <= 0) return; - assert(blitter->BufferSize(width, height) <= static_cast(_chatmsg_box.width) * _chatmsg_box.height * blitter->GetBytesPerPixel()); - /* Make a copy of the screen as it is before painting (for undraw) */ - blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height); + uint8_t *buffer = _chatmessage_backup.Allocate(BlitterFactory::GetCurrentBlitter()->BufferSize(width, height)); + blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), buffer, width, height); _cur_dpi = &_screen; // switch to _screen painting From 01728177e7bf1f4b0131ad7eccd2fa76abc6d641 Mon Sep 17 00:00:00 2001 From: translators Date: Sat, 4 Nov 2023 18:37:37 +0000 Subject: [PATCH 37/57] Update: Translations from eints english (us): 3 changes by 2TallTyler french: 2 changes by Lishouuu --- src/lang/english_US.txt | 3 +++ src/lang/french.txt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 25247bc434..71bb571f1c 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -533,6 +533,7 @@ STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle coloring of dirty blocks +STR_ABOUT_MENU_TOGGLE_WIDGET_OUTLINES :Toggle widget outlines # Place in highscore window ###length 15 @@ -3383,6 +3384,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Save STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Save the preset to the current selected name # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Change base graphics parameters STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Change NewGRF parameters STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Close STR_NEWGRF_PARAMETERS_RESET :{BLACK}Reset @@ -5187,6 +5189,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Can't ti STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehicles can only wait at stations STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}This vehicle is not stopping at this station STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... timetable is incomplete +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... timetable has not started yet # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... too many signs diff --git a/src/lang/french.txt b/src/lang/french.txt index f690e21da6..493d63b711 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -3385,6 +3385,7 @@ STR_SAVE_PRESET_SAVE :{BLACK}Sauvegar STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Sauvegarder la présélection sous le nom actuellement sélectionné # NewGRF parameters window +STR_BASEGRF_PARAMETERS_CAPTION :{WHITE}Modifier les paramètres des graphiques de base STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Modifier les paramètres NewGRF STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Fermer STR_NEWGRF_PARAMETERS_RESET :{BLACK}Réinitialiser @@ -5189,6 +5190,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Impossib STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Les véhicules ne peuvent attendre qu'aux stations STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Ce véhicule ne s'arrête pas à cette station STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... l'horaire est incomplet +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... cet horaire n'a pas encore démarré # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... trop de panneaux From ef385499c7833feafafbd3a197ba014aa062255b Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 5 Nov 2023 14:09:47 +0000 Subject: [PATCH 38/57] Codechange: Remove ineffective NWidgetParts. (#11443) --- src/network/network_content_gui.cpp | 2 +- src/object_gui.cpp | 2 +- src/rail_gui.cpp | 28 ++++++++++++++-------------- src/road_gui.cpp | 4 ++-- src/signs_gui.cpp | 4 +--- src/story_gui.cpp | 2 +- 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 59b40c4a8b..3673c94acb 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -1064,7 +1064,7 @@ static const NWidgetPart _nested_network_content_list_widgets[] = { NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0), diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 756cf2e317..9f22b22735 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -689,7 +689,7 @@ static const NWidgetPart _nested_build_object_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BO_SELECT_SCROLL), NWidget(NWID_HORIZONTAL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BO_SELECT_MATRIX), SetFill(0, 1), SetPIP(0, 2, 0), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BO_SELECT_MATRIX), SetPIP(0, 2, 0), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BO_SELECT_IMAGE), SetMinimalSize(66, 60), SetDataTip(0x0, STR_OBJECT_BUILD_TOOLTIP), SetFill(0, 0), SetResize(0, 0), SetScrollbar(WID_BO_SELECT_SCROLL), EndContainer(), diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 65d0da98e6..a4a749fe44 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1606,7 +1606,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { /* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BRAS_MATRIX_SCROLL), NWidget(NWID_HORIZONTAL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRAS_MATRIX), SetScrollbar(WID_BRAS_MATRIX_SCROLL), SetPIP(0, 2, 0), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRAS_MATRIX), SetPIP(0, 2, 0), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRAS_IMAGE), SetMinimalSize(66, 60), SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BRAS_MATRIX_SCROLL), EndContainer(), @@ -1842,36 +1842,36 @@ static const NWidgetPart _nested_signal_builder_widgets[] = { NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_SEMAPHORE_NORM_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_SEMAPHORE_ENTRY_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_SEMAPHORE_EXIT_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_SEMAPHORE_COMBO_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP), EndContainer(), EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_ELECTRIC_NORM_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_ELECTRIC_ENTRY_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_ELECTRIC_EXIT_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BS_ELECTRIC_COMBO_SEL), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP), EndContainer(), EndContainer(), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), - NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_JUST_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetTextStyle(TC_ORANGE), SetFill(1, 1), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), @@ -2192,7 +2192,7 @@ static const NWidgetPart _nested_build_waypoint_widgets[] = { EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BRW_SCROLL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT_MATRIX), SetPIP(0, 2, 0), SetPadding(3), SetScrollbar(WID_BRW_SCROLL), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT_MATRIX), SetPIP(0, 2, 0), SetPadding(3), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRW_WAYPOINT), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), SetScrollbar(WID_BRW_SCROLL), EndContainer(), EndContainer(), EndContainer(), diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 17de83bb9a..d8a136cbc0 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -1657,7 +1657,7 @@ static const NWidgetPart _nested_road_station_picker_widgets[] = { NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_MATRIX), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BROS_MATRIX_SCROLL), NWidget(NWID_HORIZONTAL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BROS_MATRIX), SetScrollbar(WID_BROS_MATRIX_SCROLL), SetPIP(0, 2, 0), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BROS_MATRIX), SetPIP(0, 2, 0), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_IMAGE), SetMinimalSize(66, 60), SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BROS_MATRIX_SCROLL), EndContainer(), @@ -1742,7 +1742,7 @@ static const NWidgetPart _nested_tram_station_picker_widgets[] = { NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_MATRIX), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BROS_MATRIX_SCROLL), NWidget(NWID_HORIZONTAL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BROS_MATRIX), SetScrollbar(WID_BROS_MATRIX_SCROLL), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BROS_MATRIX), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_IMAGE), SetMinimalSize(66, 60), SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BROS_MATRIX_SCROLL), EndContainer(), diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 8eda33bb6b..271894f91b 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -377,9 +377,7 @@ static const NWidgetPart _nested_sign_list_widgets[] = { EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), - NWidget(NWID_VERTICAL), SetFill(0, 1), - NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SIL_SCROLLBAR), - EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SIL_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), diff --git a/src/story_gui.cpp b/src/story_gui.cpp index 4012a9ae48..5ceefed8e2 100644 --- a/src/story_gui.cpp +++ b/src/story_gui.cpp @@ -955,7 +955,7 @@ static const NWidgetPart _nested_story_book_widgets[] = { NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), - NWidget(NWID_HORIZONTAL), SetFill(1, 1), + NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_SB_PAGE_PANEL), SetResize(1, 1), SetScrollbar(WID_SB_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SB_SCROLLBAR), EndContainer(), From b5861fd8f3fc51624c2df87ff305d3b7f59f3798 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 5 Nov 2023 15:43:56 +0000 Subject: [PATCH 39/57] Fix: Using MIN_YEAR for a date is probably wrong, Use MIN_DATE instead. (#11444) Even with strong types ... --- src/table/roadtypes.h | 2 +- src/timer/timer_game_calendar.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/table/roadtypes.h b/src/table/roadtypes.h index f4148cf85f..7d5e321a77 100644 --- a/src/table/roadtypes.h +++ b/src/table/roadtypes.h @@ -82,7 +82,7 @@ static const RoadTypeInfo _original_roadtypes[] = { 0x01, /* introduction date */ - static_cast(CalendarTime::MIN_YEAR), + CalendarTime::MIN_DATE, /* roadtypes required for this to be introduced */ ROADTYPES_NONE, diff --git a/src/timer/timer_game_calendar.h b/src/timer/timer_game_calendar.h index a4ea3f27a3..e62f745615 100644 --- a/src/timer/timer_game_calendar.h +++ b/src/timer/timer_game_calendar.h @@ -178,6 +178,9 @@ public: /** The date of the first day of the original base year. */ static constexpr TimerGameCalendar::Date DAYS_TILL_ORIGINAL_BASE_YEAR = TimerGameCalendar::DateAtStartOfYear(ORIGINAL_BASE_YEAR); + /** The absolute minimum date. */ + static constexpr TimerGameCalendar::Date MIN_DATE = 0; + /** The date of the last day of the max year. */ static constexpr TimerGameCalendar::Date MAX_DATE = TimerGameCalendar::DateAtStartOfYear(CalendarTime::MAX_YEAR + 1) - 1; From af4c7799feb438378b589e7b981f154a1a30a8bd Mon Sep 17 00:00:00 2001 From: translators Date: Sun, 5 Nov 2023 18:37:09 +0000 Subject: [PATCH 40/57] Update: Translations from eints korean: 1 change by telk5093 finnish: 1 change by hpiirai portuguese (brazilian): 1 change by pasantoro --- src/lang/brazilian_portuguese.txt | 1 + src/lang/finnish.txt | 1 + src/lang/korean.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index d65902b572..c78d558080 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -5190,6 +5190,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Impossí STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Veículos só podem aguardar em estações STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Esse veículo não pára nesta estação STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... horário incompleto +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... o plano de horário ainda não começou # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... existem placas demais diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index a54fbe8b31..6eff0ad21f 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -5189,6 +5189,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Ei voi a STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Kulkuneuvo voi odottaa vain asemalla STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Tämä kulkuneuvo ei pysähdy tällä asemalla STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}… aikataulu on puutteellinen +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}… aikataulu ei ole vielä alkanut # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... liian monta kylttiä. diff --git a/src/lang/korean.txt b/src/lang/korean.txt index cfa679c383..482c1e7912 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -5190,6 +5190,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}차량 STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}차량은 정거장에서만 기다릴 수 있습니다 STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}이 차량은 이 정거장에 서지 않습니다 STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... 시간표가 모두 작성되지 않았습니다 +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... 시간표가 아직 시작되지 않았습니다 # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... 팻말 수가 너무 많습니다 From 46f63074dad2f8462909f53b2de8cca6b018ba24 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 11:15:41 +0000 Subject: [PATCH 41/57] Add: MockFontCache for testing GUI code that only needs to know font sizes. --- src/fontcache.h | 3 +-- src/tests/CMakeLists.txt | 1 + src/tests/mock_fontcache.h | 45 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/tests/mock_fontcache.h diff --git a/src/fontcache.h b/src/fontcache.h index 79af2e2992..f52df8d8b1 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -19,9 +19,8 @@ static const GlyphID SPRITE_GLYPH = 1U << 30; /** Font cache for basic fonts. */ class FontCache { -private: - static FontCache *caches[FS_END]; ///< All the font caches. protected: + static FontCache *caches[FS_END]; ///< All the font caches. FontCache *parent; ///< The parent of this font cache. const FontSize fs; ///< The size of the font. int height; ///< The height of the font. diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 9a01d4e8fe..ad7701b26b 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,6 +1,7 @@ add_test_files( landscape_partial_pixel_z.cpp math_func.cpp + mock_fontcache.h string_func.cpp strings_func.cpp test_main.cpp diff --git a/src/tests/mock_fontcache.h b/src/tests/mock_fontcache.h new file mode 100644 index 0000000000..c9eb326029 --- /dev/null +++ b/src/tests/mock_fontcache.h @@ -0,0 +1,45 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file mock_fontcache.h Mock font cache implementation definition. */ + +#ifndef MOCK_FONTCACHE_H +#define MOCK_FONTCACHE_H + +#include "../stdafx.h" + +#include "../fontcache.h" +#include "../string_func.h" + +/** Font cache for mocking basic use of fonts. */ +class MockFontCache : public FontCache { +public: + MockFontCache(FontSize fs) : FontCache(fs) + { + this->height = FontCache::GetDefaultFontHeight(this->fs); + } + + void SetUnicodeGlyph(char32_t, SpriteID) override {} + void InitializeUnicodeGlyphMap() override {} + void ClearFontCache() override {} + const Sprite *GetGlyph(GlyphID) override { return nullptr; } + uint GetGlyphWidth(GlyphID) override { return this->height / 2; } + bool GetDrawGlyphShadow() override { return false; } + GlyphID MapCharToGlyph(char32_t key) override { return key; } + const void *GetFontTable(uint32_t, size_t &length) override { length = 0; return nullptr; } + std::string GetFontName() override { return "mock"; } + bool IsBuiltInFont() override { return true; } + + static void InitializeFontCaches() + { + for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) { + if (FontCache::caches[fs] == nullptr) new MockFontCache(fs); /* FontCache inserts itself into to the cache. */ + } + } +}; + +#endif /* MOCK_FONTCACHE_H */ From 05436d9c2f4e188ad16f0c1efd21c8dd67b8ec78 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 3 Nov 2023 18:48:34 +0000 Subject: [PATCH 42/57] Add: Expose minimal parts of SpriteCache internals. These parts are needed to be able to mock the SpriteCache for unit-tests. --- src/CMakeLists.txt | 1 + src/spritecache.cpp | 20 +++---------------- src/spritecache_internal.h | 41 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 src/spritecache_internal.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c084c913f..dfa123509b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -398,6 +398,7 @@ add_files( sprite.h spritecache.cpp spritecache.h + spritecache_internal.h station.cpp station_base.h station_cmd.cpp diff --git a/src/spritecache.cpp b/src/spritecache.cpp index ef5e547c29..43d8a95894 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -19,6 +19,8 @@ #include "core/math_func.hpp" #include "core/mem_func.hpp" #include "video/video_driver.hpp" +#include "spritecache.h" +#include "spritecache_internal.h" #include "table/sprites.h" #include "table/strings.h" @@ -29,17 +31,6 @@ /* Default of 4MB spritecache */ uint _sprite_cache_size = 4; -struct SpriteCache { - void *ptr; - size_t file_pos; - SpriteFile *file; ///< The file the sprite in this entry can be found in. - uint32_t id; - int16_t lru; - SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble. - bool warned; ///< True iff the user has been warned about incorrect use of this sprite - byte control_flags; ///< Control flags, see SpriteCacheCtrlFlags -}; - static uint _spritecache_items = 0; static SpriteCache *_spritecache = nullptr; @@ -50,12 +41,7 @@ static inline SpriteCache *GetSpriteCache(uint index) return &_spritecache[index]; } -static inline bool IsMapgenSpriteID(SpriteID sprite) -{ - return IsInsideMM(sprite, SPR_MAPGEN_BEGIN, SPR_MAPGEN_END); -} - -static SpriteCache *AllocateSpriteCache(uint index) +SpriteCache *AllocateSpriteCache(uint index) { if (index >= _spritecache_items) { /* Add another 1024 items to the 'pool' */ diff --git a/src/spritecache_internal.h b/src/spritecache_internal.h new file mode 100644 index 0000000000..4268c1217d --- /dev/null +++ b/src/spritecache_internal.h @@ -0,0 +1,41 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file spritecache_internal.h Internal functions to cache sprites in memory. */ + +#ifndef SPRITECACHE_INTERNAL_H +#define SPRITECACHE_INTERNAL_H + +#include "stdafx.h" + +#include "core/math_func.hpp" +#include "gfx_type.h" +#include "spriteloader/spriteloader.hpp" + +#include "table/sprites.h" + +/* These declarations are internal to spritecache but need to be exposed for unit-tests. */ + +struct SpriteCache { + void *ptr; + size_t file_pos; + SpriteFile *file; ///< The file the sprite in this entry can be found in. + uint32_t id; + int16_t lru; + SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble. + bool warned; ///< True iff the user has been warned about incorrect use of this sprite + byte control_flags; ///< Control flags, see SpriteCacheCtrlFlags +}; + +static inline bool IsMapgenSpriteID(SpriteID sprite) +{ + return IsInsideMM(sprite, SPR_MAPGEN_BEGIN, SPR_MAPGEN_END); +} + +SpriteCache *AllocateSpriteCache(uint index); + +#endif /* SPRITECACHE_INTERNAL_H */ From 1c94fb0389b291e4cf4be2b9ba1c8e435dd1765d Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 15:06:56 +0000 Subject: [PATCH 43/57] Add: Mock sprite cache intialization. This fills up the sprite cache with SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT zero-size sprites, to allow GetSpriteSize() calls to continue from unit-tests. --- src/spritecache.cpp | 3 +-- src/spritecache_internal.h | 1 + src/tests/CMakeLists.txt | 2 ++ src/tests/mock_spritecache.cpp | 49 ++++++++++++++++++++++++++++++++++ src/tests/mock_spritecache.h | 15 +++++++++++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/tests/mock_spritecache.cpp create mode 100644 src/tests/mock_spritecache.h diff --git a/src/spritecache.cpp b/src/spritecache.cpp index 43d8a95894..2cb32eb6c8 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -102,7 +102,6 @@ static uint _allocated_sprite_cache_size = 0; static int _compact_cache_counter; static void CompactSpriteCache(); -static void *AllocSprite(size_t mem_req); /** * Skip the given amount of sprite graphics data. @@ -831,7 +830,7 @@ static void DeleteEntryFromSpriteCache() DeleteEntryFromSpriteCache(best); } -static void *AllocSprite(size_t mem_req) +void *AllocSprite(size_t mem_req) { mem_req += sizeof(MemBlock); diff --git a/src/spritecache_internal.h b/src/spritecache_internal.h index 4268c1217d..6664f980b2 100644 --- a/src/spritecache_internal.h +++ b/src/spritecache_internal.h @@ -36,6 +36,7 @@ static inline bool IsMapgenSpriteID(SpriteID sprite) return IsInsideMM(sprite, SPR_MAPGEN_BEGIN, SPR_MAPGEN_END); } +void *AllocSprite(size_t mem_req); SpriteCache *AllocateSpriteCache(uint index); #endif /* SPRITECACHE_INTERNAL_H */ diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index ad7701b26b..18390c1eb8 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -2,6 +2,8 @@ add_test_files( landscape_partial_pixel_z.cpp math_func.cpp mock_fontcache.h + mock_spritecache.cpp + mock_spritecache.h string_func.cpp strings_func.cpp test_main.cpp diff --git a/src/tests/mock_spritecache.cpp b/src/tests/mock_spritecache.cpp new file mode 100644 index 0000000000..5a5910cfdd --- /dev/null +++ b/src/tests/mock_spritecache.cpp @@ -0,0 +1,49 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file mock_spritecache.cpp Mock sprite cache implementation. */ + +#include "../stdafx.h" + +#include "../blitter/factory.hpp" +#include "../core/math_func.hpp" +#include "../spritecache.h" +#include "../spritecache_internal.h" +#include "../table/sprites.h" + +static bool MockLoadNextSprite(int load_index) +{ + static Sprite *sprite = (Sprite *)AllocSprite(sizeof(*sprite)); + + bool is_mapgen = IsMapgenSpriteID(load_index); + + SpriteCache *sc = AllocateSpriteCache(load_index); + sc->file = nullptr; + sc->file_pos = 0; + sc->ptr = sprite; + sc->lru = 0; + sc->id = 0; + sc->type = is_mapgen ? SpriteType::MapGen : SpriteType::Normal; + sc->warned = false; + sc->control_flags = 0; + + /* Fill with empty sprites up until the default sprite count. */ + return (uint)load_index < SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT; +} + +void MockGfxLoadSprites() +{ + /* Force blitter 'null'. This is necessary for GfxInitSpriteMem() to function. */ + BlitterFactory::SelectBlitter("null"); + + GfxInitSpriteMem(); + + int load_index = 0; + while (MockLoadNextSprite(load_index)) { + load_index++; + } +} diff --git a/src/tests/mock_spritecache.h b/src/tests/mock_spritecache.h new file mode 100644 index 0000000000..6d715cf699 --- /dev/null +++ b/src/tests/mock_spritecache.h @@ -0,0 +1,15 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file mock_spritecache.h Mock sprite cache definition. */ + +#ifndef MOCK_SPRITECACHE_H +#define MOCK_SPRITECACHE_H + +void MockGfxLoadSprites(); + +#endif /* MOCK_SPRITECACHE_H */ From b1eb5533ebb800f8951cbc5914e041a0e2d8338d Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 2 Nov 2023 11:16:37 +0000 Subject: [PATCH 44/57] Add: WindowDesc unit test to validate NWidgetPart lists. --- src/tests/CMakeLists.txt | 1 + src/tests/mock_environment.h | 39 ++++++++++++++++++++++++++++++++++ src/tests/test_window_desc.cpp | 23 ++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/tests/mock_environment.h diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 18390c1eb8..b8380bed24 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,6 +1,7 @@ add_test_files( landscape_partial_pixel_z.cpp math_func.cpp + mock_environment.h mock_fontcache.h mock_spritecache.cpp mock_spritecache.h diff --git a/src/tests/mock_environment.h b/src/tests/mock_environment.h new file mode 100644 index 0000000000..470914d002 --- /dev/null +++ b/src/tests/mock_environment.h @@ -0,0 +1,39 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file mock_environment.h Singleton instance to create a mock FontCache/SpriteCache environment. */ + +#ifndef MOCK_ENVIRONMENT_H +#define MOCK_ENVIRONMENT_H + +#include "mock_fontcache.h" +#include "mock_spritecache.h" + +/** Singleton class to set up the mock environemnt once. */ +class MockEnvironment { +public: + static MockEnvironment &Instance() + { + static MockEnvironment instance; + return instance; + } + + MockEnvironment(MockEnvironment const &) = delete; + void operator=(MockEnvironment const &) = delete; + +private: + MockEnvironment() + { + /* Mock SpriteCache initialization is needed for some widget generators. */ + MockGfxLoadSprites(); + + /* Mock FontCache initialization is needed for some NWidgetParts. */ + MockFontCache::InitializeFontCaches(); + } +}; + +#endif /* MOCK_ENVIRONMENT_H */ diff --git a/src/tests/test_window_desc.cpp b/src/tests/test_window_desc.cpp index 64f95c58b5..1a5be4a1c6 100644 --- a/src/tests/test_window_desc.cpp +++ b/src/tests/test_window_desc.cpp @@ -11,6 +11,8 @@ #include "../3rdparty/catch2/catch.hpp" +#include "mock_environment.h" + #include "../window_gui.h" /** @@ -19,6 +21,13 @@ */ extern std::vector *_window_descs; + +class WindowDescTestsFixture { +private: + MockEnvironment &mock = MockEnvironment::Instance(); +}; + + TEST_CASE("WindowDesc - ini_key uniqueness") { std::set seen; @@ -73,3 +82,17 @@ TEST_CASE("WindowDesc - NWidgetParts properly closed") CHECK(IsNWidgetTreeClosed(window_desc->nwid_begin, window_desc->nwid_end)); } + +TEST_CASE_METHOD(WindowDescTestsFixture, "WindowDesc - NWidgetPart validity") +{ + const WindowDesc *window_desc = GENERATE(from_range(std::begin(*_window_descs), std::end(*_window_descs))); + + INFO(fmt::format("{}:{}", window_desc->file, window_desc->line)); + + int biggest_index = -1; + NWidgetStacked *shade_select = nullptr; + NWidgetBase *root = nullptr; + + REQUIRE_NOTHROW(root = MakeWindowNWidgetTree(window_desc->nwid_begin, window_desc->nwid_end, &biggest_index, &shade_select)); + CHECK((root != nullptr)); +} From a9aaa2a18330a5b51d07207a541cda3b1854f12d Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 1 Nov 2023 14:16:38 +0000 Subject: [PATCH 45/57] Codechange: Don't be lenient with invalid NWidgetPart lists. Some NWidgetPart combinations were ignored but it was not clear that they do nothing. Instead, assert if NWidgetPart is incorrectly applied. --- src/widget.cpp | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index fc50a8da7d..bbec61be07 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -3117,64 +3117,60 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg case WPT_RESIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != nullptr) { - assert(nwid_begin->u.xy.x >= 0 && nwid_begin->u.xy.y >= 0); - nwrb->SetResize(nwid_begin->u.xy.x, nwid_begin->u.xy.y); - } + if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_RESIZE requires NWidgetResizeBase"); + assert(nwid_begin->u.xy.x >= 0 && nwid_begin->u.xy.y >= 0); + nwrb->SetResize(nwid_begin->u.xy.x, nwid_begin->u.xy.y); break; } case WPT_MINSIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != nullptr) { - assert(nwid_begin->u.xy.x >= 0 && nwid_begin->u.xy.y >= 0); - nwrb->SetMinimalSize(nwid_begin->u.xy.x, nwid_begin->u.xy.y); - } + if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_MINSIZE requires NWidgetResizeBase"); + assert(nwid_begin->u.xy.x >= 0 && nwid_begin->u.xy.y >= 0); + nwrb->SetMinimalSize(nwid_begin->u.xy.x, nwid_begin->u.xy.y); break; } case WPT_MINTEXTLINES: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != nullptr) { - assert(nwid_begin->u.text_lines.size >= FS_BEGIN && nwid_begin->u.text_lines.size < FS_END); - nwrb->SetMinimalTextLines(nwid_begin->u.text_lines.lines, nwid_begin->u.text_lines.spacing, nwid_begin->u.text_lines.size); - } + if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_MINTEXTLINES requires NWidgetResizeBase"); + assert(nwid_begin->u.text_lines.size >= FS_BEGIN && nwid_begin->u.text_lines.size < FS_END); + nwrb->SetMinimalTextLines(nwid_begin->u.text_lines.lines, nwid_begin->u.text_lines.spacing, nwid_begin->u.text_lines.size); break; } case WPT_TEXTSTYLE: { NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != nullptr) { - nwc->SetTextStyle(nwid_begin->u.text_style.colour, nwid_begin->u.text_style.size); - } + if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_TEXTSTYLE requires NWidgetCore"); + nwc->SetTextStyle(nwid_begin->u.text_style.colour, nwid_begin->u.text_style.size); break; } case WPT_ALIGNMENT: { NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != nullptr) { - nwc->SetAlignment(nwid_begin->u.align.align); - } + if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_ALIGNMENT requires NWidgetCore"); + nwc->SetAlignment(nwid_begin->u.align.align); break; } case WPT_FILL: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != nullptr) nwrb->SetFill(nwid_begin->u.xy.x, nwid_begin->u.xy.y); + if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_FILL requires NWidgetResizeBase"); + nwrb->SetFill(nwid_begin->u.xy.x, nwid_begin->u.xy.y); break; } case WPT_DATATIP: { NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != nullptr) { - nwc->widget_data = nwid_begin->u.data_tip.data; - nwc->tool_tip = nwid_begin->u.data_tip.tooltip; - } + if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_DATATIP requires NWidgetCore"); + nwc->widget_data = nwid_begin->u.data_tip.data; + nwc->tool_tip = nwid_begin->u.data_tip.tooltip; break; } case WPT_PADDING: - if (*dest != nullptr) (*dest)->SetPadding(nwid_begin->u.padding); + if (unlikely(*dest == nullptr)) throw std::runtime_error("WPT_PADDING requires NWidgetBase"); + (*dest)->SetPadding(nwid_begin->u.padding); break; case WPT_PIPSPACE: { @@ -3183,14 +3179,15 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg NWidgetBackground *nwb = dynamic_cast(*dest); if (nwb != nullptr) nwb->SetPIP(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post); + + if (unlikely(nwc == nullptr && nwb == nullptr)) throw std::runtime_error("WPT_PIPSPACE requires NWidgetPIPContainer or NWidgetBackground"); break; } case WPT_SCROLLBAR: { NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != nullptr) { - nwc->scrollbar_index = nwid_begin->u.widget.index; - } + if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_SCROLLBAR requires NWidgetCore"); + nwc->scrollbar_index = nwid_begin->u.widget.index; break; } @@ -3307,7 +3304,10 @@ NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *biggest_index = -1; if (container == nullptr) container = new NWidgetVertical(); NWidgetBase *cont_ptr = container; - MakeWidgetTree(nwid_begin, nwid_end, &cont_ptr, biggest_index); + [[maybe_unused]] const NWidgetPart *nwid_part = MakeWidgetTree(nwid_begin, nwid_end, &cont_ptr, biggest_index); +#ifdef WITH_ASSERT + if (unlikely(nwid_part != nwid_end)) throw std::runtime_error("Did not consume all NWidgetParts"); +#endif return container; } From 43aa91a7f5e20e904e207f616a919879ca0e9f49 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 5 Nov 2023 20:09:11 +0000 Subject: [PATCH 46/57] Fix #11437: Flipped shorter rail vehicles disappear in windows. (#11446) Mixed signed/unsigned strikes again, causing an incorrect sprite offset for shortened vehicles. --- src/train_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 47cd1af9d9..2a162426c8 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -469,7 +469,7 @@ int Train::GetDisplayImageWidth(Point *offset) const if (offset != nullptr) { if (HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS)) { - offset->x = ScaleSpriteTrad((this->gcache.cached_veh_length - VEHICLE_LENGTH / 2) * reference_width / VEHICLE_LENGTH); + offset->x = ScaleSpriteTrad(((int)this->gcache.cached_veh_length - (int)VEHICLE_LENGTH / 2) * reference_width / (int)VEHICLE_LENGTH); } else { offset->x = ScaleSpriteTrad(reference_width) / 2; } From ac54bd7e583efa67a0adc4880db1e2ca9239c85c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 27 Oct 2023 19:00:51 +0100 Subject: [PATCH 47/57] Codechange: Apply PIP during AssignSizePosition() instead of SetupSmallestSize(). --- src/widget.cpp | 42 ++++++++++++++++++------------------------ src/widget_type.h | 2 ++ 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index bbec61be07..f53389cd58 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1511,6 +1511,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) this->fill_y = 1; // smallest common child fill step. this->resize_x = 0; // smallest non-zero child widget resize step. this->resize_y = 1; // smallest common child resize step. + this->gaps = 0; /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ uint longest = 0; // Longest child found. @@ -1520,7 +1521,9 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) longest = std::max(longest, child_wid->smallest_x); max_vert_fill = std::max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST)); this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical()); + this->gaps++; } + if (this->gaps > 0) this->gaps--; // Number of gaps is number of widgets less one. /* 1b. Make the container higher if needed to accommodate all children nicely. */ [[maybe_unused]] uint max_smallest = this->smallest_y + 3 * max_vert_fill; // Upper limit to computing smallest height. uint cur_height = this->smallest_y; @@ -1546,15 +1549,8 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) if (child_wid->fill_x == 1) child_wid->smallest_x = longest; } } - /* 3. Move PIP space to the children, compute smallest, fill, and resize values of the container. */ - if (this->head != nullptr) this->head->padding.left += this->pip_pre; + /* 3. Compute smallest, fill, and resize values of the container. */ for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { - if (child_wid->next != nullptr) { - child_wid->padding.right += this->pip_inter; - } else { - child_wid->padding.right += this->pip_post; - } - this->smallest_x += child_wid->smallest_x + child_wid->padding.Horizontal(); if (child_wid->fill_x > 0) { if (this->fill_x == 0 || this->fill_x > child_wid->fill_x) this->fill_x = child_wid->fill_x; @@ -1566,8 +1562,8 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) } this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); } - /* We need to zero the PIP settings so we can re-initialize the tree. */ - this->pip_pre = this->pip_inter = this->pip_post = 0; + /* 4. Increase by required PIP space. */ + this->smallest_x += this->pip_pre + this->gaps * this->pip_inter + this->pip_post; } void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) @@ -1578,6 +1574,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint uint additional_length = given_width; if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { /* For EQUALSIZE containers this does not sum to smallest_x during initialisation */ + additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post; for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal(); } @@ -1657,7 +1654,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint assert(num_changing_childs == 0); /* Third loop: Compute position and call the child. */ - uint position = rtl ? this->current_x : 0; // Place to put next child relative to origin of the container. + uint position = rtl ? this->current_x - this->pip_pre : this->pip_pre; // Place to put next child relative to origin of the container. NWidgetBase *child_wid = this->head; while (child_wid != nullptr) { uint child_width = child_wid->current_x; @@ -1665,7 +1662,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint uint child_y = y + child_wid->padding.top; child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl); - uint padded_child_width = child_width + child_wid->padding.Horizontal(); + uint padded_child_width = child_width + child_wid->padding.Horizontal() + this->pip_inter; position = rtl ? position - padded_child_width : position + padded_child_width; child_wid = child_wid->next; @@ -1696,6 +1693,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) this->fill_y = 0; // smallest non-zero child widget fill step. this->resize_x = 1; // smallest common child resize step. this->resize_y = 0; // smallest non-zero child widget resize step. + this->gaps = 0; /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ uint highest = 0; // Highest child found. @@ -1705,7 +1703,9 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) highest = std::max(highest, child_wid->smallest_y); max_hor_fill = std::max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST)); this->smallest_x = std::max(this->smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal()); + this->gaps++; } + if (this->gaps > 0) this->gaps--; // Number of gaps is number of widgets less one. /* 1b. Make the container wider if needed to accommodate all children nicely. */ [[maybe_unused]] uint max_smallest = this->smallest_x + 3 * max_hor_fill; // Upper limit to computing smallest height. uint cur_width = this->smallest_x; @@ -1731,15 +1731,8 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) if (child_wid->fill_y == 1) child_wid->smallest_y = highest; } } - /* 3. Move PIP space to the child, compute smallest, fill, and resize values of the container. */ - if (this->head != nullptr) this->head->padding.top += this->pip_pre; + /* 3. Compute smallest, fill, and resize values of the container. */ for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { - if (child_wid->next != nullptr) { - child_wid->padding.bottom += this->pip_inter; - } else { - child_wid->padding.bottom += this->pip_post; - } - this->smallest_y += child_wid->smallest_y + child_wid->padding.Vertical(); if (child_wid->fill_y > 0) { if (this->fill_y == 0 || this->fill_y > child_wid->fill_y) this->fill_y = child_wid->fill_y; @@ -1751,8 +1744,8 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) } this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); } - /* We need to zero the PIP settings so we can re-initialize the tree. */ - this->pip_pre = this->pip_inter = this->pip_post = 0; + /* 4. Increase by required PIP space. */ + this->smallest_y += this->pip_pre + this->gaps * this->pip_inter + this->pip_post; } void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) @@ -1763,6 +1756,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g uint additional_length = given_height; if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { /* For EQUALSIZE containers this does not sum to smallest_y during initialisation */ + additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post; for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { additional_length -= child_wid->smallest_y + child_wid->padding.Vertical(); } @@ -1833,13 +1827,13 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g assert(num_changing_childs == 0); /* Third loop: Compute position and call the child. */ - uint position = 0; // Place to put next child relative to origin of the container. + uint position = this->pip_pre; // Place to put next child relative to origin of the container. for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left); uint child_height = child_wid->current_y; child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl); - position += child_height + child_wid->padding.Vertical(); + position += child_height + child_wid->padding.Vertical() + this->pip_inter; } } diff --git a/src/widget_type.h b/src/widget_type.h index a0c8d1dce0..d6caaa7fee 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -492,6 +492,8 @@ protected: uint8_t uz_pip_pre; ///< Unscaled space before first widget. uint8_t uz_pip_inter; ///< Unscaled space between widgets. uint8_t uz_pip_post; ///< Unscaled space after last widget. + + uint8_t gaps; ///< Number of gaps between widgets. }; /** From 6317967dba9cb0d27b1c1c625fa5db8ebd20cbbf Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 27 Oct 2023 20:01:54 +0100 Subject: [PATCH 48/57] Codechange: Add ability to allocate PIP-space dynamically by ratio. This can be used to space out, centre, start-align, or end-align widgets without additional spacers. --- src/widget.cpp | 83 +++++++++++++++++++++++++++++++++++++++++++---- src/widget_type.h | 25 ++++++++++++++ 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index f53389cd58..be40716e46 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1498,6 +1498,22 @@ void NWidgetPIPContainer::SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip this->pip_post = ScaleGUITrad(this->uz_pip_post); } +/** + * Set additional pre/inter/post space for the container. + * + * @param pip_ratio_pre Ratio of additional space in front of the first child widget (above + * for the vertical container, at the left for the horizontal container). + * @param pip_ratio_inter Ratio of additional space between two child widgets. + * @param pip_ratio_post Ratio of additional space after the last child widget (below for the + * vertical container, at the right for the horizontal container). + */ +void NWidgetPIPContainer::SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post) +{ + this->pip_ratio_pre = pip_ratio_pre; + this->pip_ratio_inter = pip_ratio_inter; + this->pip_ratio_post = pip_ratio_post; +} + /** Horizontal container widget. */ NWidgetHorizontal::NWidgetHorizontal(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_HORIZONTAL, flags) { @@ -1562,6 +1578,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) } this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); } + if (this->fill_x == 0 && this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post > 0) this->fill_x = 1; /* 4. Increase by required PIP space. */ this->smallest_x += this->pip_pre + this->gaps * this->pip_inter + this->pip_post; } @@ -1572,7 +1589,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint /* Compute additional width given to us. */ uint additional_length = given_width; - if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { + if (this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post != 0 || (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE))) { /* For EQUALSIZE containers this does not sum to smallest_x during initialisation */ additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post; for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { @@ -1653,8 +1670,21 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint } assert(num_changing_childs == 0); + uint pre = this->pip_pre; + uint inter = this->pip_inter; + + if (additional_length > 0) { + /* Allocate remaining space by pip ratios. If this doesn't round exactly, the unused space will fall into pip_post + * which is never explicitly needed. */ + int r = this->pip_ratio_pre + this->gaps * this->pip_ratio_inter + this->pip_ratio_post; + if (r > 0) { + pre += this->pip_ratio_pre * additional_length / r; + if (this->gaps > 0) inter += this->pip_ratio_inter * additional_length / r; + } + } + /* Third loop: Compute position and call the child. */ - uint position = rtl ? this->current_x - this->pip_pre : this->pip_pre; // Place to put next child relative to origin of the container. + uint position = rtl ? this->current_x - pre : pre; // Place to put next child relative to origin of the container. NWidgetBase *child_wid = this->head; while (child_wid != nullptr) { uint child_width = child_wid->current_x; @@ -1662,7 +1692,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint uint child_y = y + child_wid->padding.top; child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl); - uint padded_child_width = child_width + child_wid->padding.Horizontal() + this->pip_inter; + uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter; position = rtl ? position - padded_child_width : position + padded_child_width; child_wid = child_wid->next; @@ -1744,6 +1774,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) } this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); } + if (this->fill_y == 0 && this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post > 0) this->fill_y = 1; /* 4. Increase by required PIP space. */ this->smallest_y += this->pip_pre + this->gaps * this->pip_inter + this->pip_post; } @@ -1754,7 +1785,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g /* Compute additional height given to us. */ uint additional_length = given_height; - if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { + if (this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post != 0 || (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE))) { /* For EQUALSIZE containers this does not sum to smallest_y during initialisation */ additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post; for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { @@ -1826,14 +1857,27 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g } assert(num_changing_childs == 0); + uint pre = this->pip_pre; + uint inter = this->pip_inter; + + if (additional_length > 0) { + /* Allocate remaining space by pip ratios. If this doesn't round exactly, the unused space will fall into pip_post + * which is never explicitly needed. */ + int r = this->pip_ratio_pre + this->gaps * this->pip_ratio_inter + this->pip_ratio_post; + if (r > 0) { + pre += this->pip_ratio_pre * additional_length / r; + if (this->gaps > 0) inter += this->pip_ratio_inter * additional_length / r; + } + } + /* Third loop: Compute position and call the child. */ - uint position = this->pip_pre; // Place to put next child relative to origin of the container. + uint position = pre; // Place to put next child relative to origin of the container. for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left); uint child_height = child_wid->current_y; child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl); - position += child_height + child_wid->padding.Vertical() + this->pip_inter; + position += child_height + child_wid->padding.Vertical() + inter; } } @@ -2170,6 +2214,24 @@ void NWidgetBackground::SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_p this->child->SetPIP(pip_pre, pip_inter, pip_post); } +/** + * Set additional pre/inter/post space ratios for the background widget. + * + * @param pip_ratio_pre Ratio of additional space in front of the first child widget (above + * for the vertical container, at the left for the horizontal container). + * @param pip_ratio_inter Ratio of additional space between two child widgets. + * @param pip_ratio_post Ratio of additional space after the last child widget (below for the + * vertical container, at the right for the horizontal container). + * @note Using this function implies that the widget has (or will have) child widgets. + */ +void NWidgetBackground::SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post) +{ + if (this->child == nullptr) { + this->child = new NWidgetVertical(); + } + this->child->SetPIPRatio(pip_ratio_pre, pip_ratio_inter, pip_ratio_post); +} + void NWidgetBackground::AdjustPaddingForZoom() { if (child != nullptr) child->AdjustPaddingForZoom(); @@ -3178,6 +3240,15 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg break; } + case WPT_PIPRATIO: { + NWidgetPIPContainer *nwc = dynamic_cast(*dest); + if (nwc != nullptr) nwc->SetPIPRatio(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post); + + NWidgetBackground *nwb = dynamic_cast(*dest); + if (nwb != nullptr) nwb->SetPIPRatio(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post); + break; + } + case WPT_SCROLLBAR: { NWidgetCore *nwc = dynamic_cast(*dest); if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_SCROLLBAR requires NWidgetCore"); diff --git a/src/widget_type.h b/src/widget_type.h index d6caaa7fee..9898520611 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -87,6 +87,7 @@ enum WidgetType { WPT_DATATIP, ///< Widget part for specifying data and tooltip. WPT_PADDING, ///< Widget part for specifying a padding. WPT_PIPSPACE, ///< Widget part for specifying pre/inter/post space for containers. + WPT_PIPRATIO, ///< Widget part for specifying pre/inter/post ratio for containers. WPT_TEXTSTYLE, ///< Widget part for specifying text colour. WPT_ALIGNMENT, ///< Widget part for specifying text/image alignment. WPT_ENDCONTAINER, ///< Widget part to denote end of a container. @@ -482,12 +483,16 @@ public: void AdjustPaddingForZoom() override; void SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_post); + void SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_rato_post); protected: NWidContainerFlags flags; ///< Flags of the container. uint8_t pip_pre; ///< Amount of space before first widget. uint8_t pip_inter; ///< Amount of space between widgets. uint8_t pip_post; ///< Amount of space after last widget. + uint8_t pip_ratio_pre; ///< Ratio of remaining space before first widget. + uint8_t pip_ratio_inter; ///< Ratio of remaining space between widgets. + uint8_t pip_ratio_post; ///< Ratio of remaining space after last widget. uint8_t uz_pip_pre; ///< Unscaled space before first widget. uint8_t uz_pip_inter; ///< Unscaled space between widgets. @@ -598,6 +603,7 @@ public: void Add(NWidgetBase *nwid); void SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_post); + void SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post); void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w, bool init_array) override; @@ -1228,6 +1234,25 @@ static inline NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post) return part; } +/** + * Widget part function for setting a pre/inter/post ratio. + * @param pre The ratio of space before the first widget. + * @param inter The ratio of space between widgets. + * @param post The ratio of space after the last widget. + * @ingroup NestedWidgetParts + */ +static inline NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post) +{ + NWidgetPart part; + + part.type = WPT_PIPRATIO; + part.u.pip.pre = ratio_pre; + part.u.pip.inter = ratio_inter; + part.u.pip.post = ratio_post; + + return part; +} + /** * Attach a scrollbar to a widget. * The scrollbar is controlled when using the mousewheel on the widget. From 3cab980b30ae6757699ae7b83010ac5a663f2c25 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 27 Oct 2023 23:32:02 +0100 Subject: [PATCH 49/57] Codechange: Skip invisible (zero-size) widgets in PIP Containers. This gets rid of doubled-up spacing where an invisible child widget would be. --- src/widget.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/widget.cpp b/src/widget.cpp index be40716e46..8e5ccdccb1 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1537,7 +1537,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) longest = std::max(longest, child_wid->smallest_x); max_vert_fill = std::max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST)); this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical()); - this->gaps++; + if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) this->gaps++; } if (this->gaps > 0) this->gaps--; // Number of gaps is number of widgets less one. /* 1b. Make the container higher if needed to accommodate all children nicely. */ @@ -1593,7 +1593,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint /* For EQUALSIZE containers this does not sum to smallest_x during initialisation */ additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post; for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { - additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal(); + if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal(); } } else { additional_length -= this->smallest_x; @@ -1692,8 +1692,10 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint uint child_y = y + child_wid->padding.top; child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl); - uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter; - position = rtl ? position - padded_child_width : position + padded_child_width; + if (child_wid->current_x != 0) { + uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter; + position = rtl ? position - padded_child_width : position + padded_child_width; + } child_wid = child_wid->next; } @@ -1733,7 +1735,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) highest = std::max(highest, child_wid->smallest_y); max_hor_fill = std::max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST)); this->smallest_x = std::max(this->smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal()); - this->gaps++; + if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) this->gaps++; } if (this->gaps > 0) this->gaps--; // Number of gaps is number of widgets less one. /* 1b. Make the container wider if needed to accommodate all children nicely. */ @@ -1789,7 +1791,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g /* For EQUALSIZE containers this does not sum to smallest_y during initialisation */ additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post; for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { - additional_length -= child_wid->smallest_y + child_wid->padding.Vertical(); + if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) additional_length -= child_wid->smallest_y + child_wid->padding.Vertical(); } } else { additional_length -= this->smallest_y; @@ -1877,7 +1879,9 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g uint child_height = child_wid->current_y; child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl); - position += child_height + child_wid->padding.Vertical() + inter; + if (child_wid->current_y != 0) { + position += child_height + child_wid->padding.Vertical() + inter; + } } } From 665902f5ba45ff987e388c47c5ca4f67aa2b119e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 3 Nov 2023 02:25:05 +0000 Subject: [PATCH 50/57] Codechange: Add widget dimensions to standardise picker winodws. --- src/widget.cpp | 2 ++ src/window_gui.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/widget.cpp b/src/widget.cpp index 8e5ccdccb1..95d177484a 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -151,7 +151,9 @@ const WidgetDimensions WidgetDimensions::unscaled = { {WD_CAPTIONTEXT_LEFT, WD_CAPTIONTEXT_TOP, WD_CAPTIONTEXT_RIGHT, WD_CAPTIONTEXT_BOTTOM}, ///< captiontext {WD_DROPDOWNTEXT_LEFT, WD_DROPDOWNTEXT_TOP, WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_BOTTOM}, ///< dropdowntext {20, 10, 20, 10}, ///< modalpopup + {3, 3, 3, 3}, ///< picker 1, ///< pressed + 1, ///< vsep_picker WD_PAR_VSEP_NORMAL, ///< vsep_normal WD_PAR_VSEP_WIDE, ///< vsep_wide 2, ///< hsep_normal diff --git a/src/window_gui.h b/src/window_gui.h index 8beb315976..e444c6ea89 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -50,8 +50,10 @@ struct WidgetDimensions { RectPadding captiontext; ///< Offsets of text within a caption. RectPadding dropdowntext; ///< Offsets of text within a dropdown widget. RectPadding modalpopup; ///< Padding for a modal popup. + RectPadding picker; ///< Padding for a picker (dock, station, etc) window. int pressed; ///< Offset for contents of depressed widget. + int vsep_picker; ///< Vertical spacing of picker-window widgets. int vsep_normal; ///< Normal vertical spacing. int vsep_wide; ///< Wide vertical spacing. int hsep_normal; ///< Normal horizontal spacing. From d380f2f3a200e38bb7bf2499854fa030356713b6 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 31 Oct 2023 19:25:12 +0000 Subject: [PATCH 51/57] Codechange: Simplify layout of depot pickers. --- src/dock_gui.cpp | 10 +++------- src/rail_gui.cpp | 25 +++++++------------------ src/road_gui.cpp | 20 ++++++++------------ 3 files changed, 18 insertions(+), 37 deletions(-) diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index c433117a92..7e03a93d5c 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -581,13 +581,9 @@ static const NWidgetPart _nested_build_docks_depot_widgets[] = { NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_DEPOT_BUILD_SHIP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BDD_BACKGROUND), - NWidget(NWID_HORIZONTAL), SetPadding(3), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, 2, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_X), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_Y), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1), SetPadding(WidgetDimensions::unscaled.picker), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BDD_X), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BDD_Y), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), EndContainer(), EndContainer(), }; diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index a4a749fe44..29d73102d0 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1954,27 +1954,16 @@ static const NWidgetPart _nested_build_depot_widgets[] = { NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(NWID_HORIZONTAL_LTR), - NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), + NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1), SetPadding(WidgetDimensions::unscaled.picker), + NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), + NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 3), EndContainer(), }; diff --git a/src/road_gui.cpp b/src/road_gui.cpp index d8a136cbc0..383b3c6395 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -1063,19 +1063,15 @@ static const NWidgetPart _nested_build_road_depot_widgets[] = { NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_HORIZONTAL), SetPadding(3), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(NWID_VERTICAL), SetPIP(0, 2, 0), - NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, 2, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, 2, 0), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), - EndContainer(), + NWidget(NWID_HORIZONTAL_LTR), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 1), SetPadding(WidgetDimensions::unscaled.picker), + NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + EndContainer(), + NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), - NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), EndContainer(), }; From 403375096867cc9a0b40a5200f8c0067202788e6 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 4 Nov 2023 14:30:16 +0000 Subject: [PATCH 52/57] Codechange: Remove redundant NWID_VERTICAL in Industry Directory layout. --- src/industry_gui.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index c71138687d..d7dc90c769 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1224,19 +1224,18 @@ static const NWidgetPart _nested_industry_directory_widgets[] = { EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), - NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_ID_FILTER), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_ACC_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_PROD_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), - NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), - EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_ID_FILTER), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_ACC_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_PROD_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), + NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_VSCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_ID_SCROLLBAR), From 6b9dc8cfcf8fce79c93f8f14b2244f1d2d5305b2 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 4 Nov 2023 14:32:39 +0000 Subject: [PATCH 53/57] Codechange: Don't filter industry list by cargo type every 3-sec refresh. The 3-sec refresh is to update the list sorting. The filter only needs to be applied once rebuilding the list. --- src/industry_gui.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index d7dc90c769..40c602b446 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1422,18 +1422,18 @@ protected: this->industries.shrink_to_fit(); this->industries.RebuildDone(); - } - auto filter = std::make_pair(this->cargo_filter[this->accepted_cargo_filter_criteria], - this->cargo_filter[this->produced_cargo_filter_criteria]); + auto filter = std::make_pair(this->cargo_filter[this->accepted_cargo_filter_criteria], + this->cargo_filter[this->produced_cargo_filter_criteria]); + + this->industries.Filter(filter); - this->industries.Filter(filter); + this->hscroll->SetCount(this->GetIndustryListWidth()); + } IndustryDirectoryWindow::produced_cargo_filter = this->cargo_filter[this->produced_cargo_filter_criteria]; this->industries.Sort(); - this->vscroll->SetCount(this->industries.size()); // Update scrollbar as well. - this->SetDirty(); } From 8ff6562b2f0cf869f8620d52e58dd99c28254bba Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 4 Nov 2023 14:33:18 +0000 Subject: [PATCH 54/57] Codechange: Reduce variable scope. --- src/industry_gui.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 40c602b446..c7a826a020 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1669,16 +1669,15 @@ public: break; case WID_ID_INDUSTRY_LIST: { - int n = 0; Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); if (this->industries.empty()) { DrawString(ir, STR_INDUSTRY_DIRECTORY_NONE); break; } - TextColour tc; + int n = 0; const CargoID acf_cid = this->cargo_filter[this->accepted_cargo_filter_criteria]; for (uint i = this->vscroll->GetPosition(); i < this->industries.size(); i++) { - tc = TC_FROMSTRING; + TextColour tc = TC_FROMSTRING; if (acf_cid != CF_ANY && acf_cid != CF_NONE) { Industry *ind = const_cast(this->industries[i]); if (IndustryTemporarilyRefusesCargo(ind, acf_cid)) { From badce415ea7b58921129fdb57d25dcd6d1b5290c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 4 Nov 2023 14:44:19 +0000 Subject: [PATCH 55/57] Change: Add horizontal scrollbar to Industry Directory window. This list could be very wide depending on industries and language. --- src/industry_gui.cpp | 44 ++++++++++++++++++++++++++++------- src/widgets/industry_widget.h | 3 ++- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index c7a826a020..c4fa764e11 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -1237,10 +1237,11 @@ static const NWidgetPart _nested_industry_directory_widgets[] = { NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_VSCROLLBAR), EndContainer(), EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_ID_SCROLLBAR), - NWidget(WWT_RESIZEBOX, COLOUR_BROWN), - EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_ID_VSCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HSCROLLBAR, COLOUR_BROWN, WID_ID_HSCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), }; @@ -1316,6 +1317,7 @@ protected: GUIIndustryList industries; Scrollbar *vscroll; + Scrollbar *hscroll; CargoID cargo_filter[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE StringID cargo_filter_texts[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID @@ -1404,6 +1406,19 @@ protected: this->industries.SetFilterState(is_filtering_necessary); } + /** + * Get the width needed to draw the longest industry line. + * @return Returns width of the longest industry line, including padding. + */ + uint GetIndustryListWidth() const + { + uint width = 0; + for (const Industry *i : this->industries) { + width = std::max(width, GetStringBoundingBox(this->GetIndustryString(i)).width); + } + return width + WidgetDimensions::scaled.framerect.Horizontal(); + } + /** (Re)Build industries list */ void BuildSortIndustriesList() { @@ -1429,6 +1444,7 @@ protected: this->industries.Filter(filter); this->hscroll->SetCount(this->GetIndustryListWidth()); + this->vscroll->SetCount(this->industries.size()); // Update scrollbar as well. } IndustryDirectoryWindow::produced_cargo_filter = this->cargo_filter[this->produced_cargo_filter_criteria]; @@ -1620,7 +1636,8 @@ public: IndustryDirectoryWindow(WindowDesc *desc, WindowNumber) : Window(desc), industry_editbox(MAX_FILTER_LENGTH * MAX_CHAR_LENGTH, MAX_FILTER_LENGTH) { this->CreateNestedTree(); - this->vscroll = this->GetScrollbar(WID_ID_SCROLLBAR); + this->vscroll = this->GetScrollbar(WID_ID_VSCROLLBAR); + this->hscroll = this->GetScrollbar(WID_ID_HSCROLLBAR); this->industries.SetListing(this->last_sorting); this->industries.SetSortFuncs(IndustryDirectoryWindow::sorter_funcs); @@ -1670,6 +1687,19 @@ public: case WID_ID_INDUSTRY_LIST: { Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); + + /* Setup a clipping rectangle... */ + DrawPixelInfo tmp_dpi; + if (!FillDrawPixelInfo(&tmp_dpi, ir.left, ir.top, ir.Width(), ir.Height())) return; + /* ...but keep coordinates relative to the window. */ + tmp_dpi.left += ir.left; + tmp_dpi.top += ir.top; + + AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi); + + ir.left -= this->hscroll->GetPosition(); + ir.right += this->hscroll->GetCapacity() - this->hscroll->GetPosition(); + if (this->industries.empty()) { DrawString(ir, STR_INDUSTRY_DIRECTORY_NONE); break; @@ -1718,9 +1748,6 @@ public: case WID_ID_INDUSTRY_LIST: { Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE); - for (uint i = 0; i < this->industries.size(); i++) { - d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); - } resize->height = d.height; d.height *= 5; d.width += padding.width; @@ -1794,6 +1821,7 @@ public: void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_ID_INDUSTRY_LIST); + this->hscroll->SetCapacityFromWidget(this, WID_ID_INDUSTRY_LIST); } void OnEditboxChanged(int wid) override diff --git a/src/widgets/industry_widget.h b/src/widgets/industry_widget.h index 9f5762a534..ee74d90d54 100644 --- a/src/widgets/industry_widget.h +++ b/src/widgets/industry_widget.h @@ -39,7 +39,8 @@ enum IndustryDirectoryWidgets { WID_ID_FILTER_BY_PROD_CARGO, ///< Produced cargo filter dropdown list. WID_ID_FILTER, ///< Textbox to filter industry name. WID_ID_INDUSTRY_LIST, ///< Industry list. - WID_ID_SCROLLBAR, ///< Scrollbar of the list. + WID_ID_HSCROLLBAR, ///< Horizontal scrollbar of the list. + WID_ID_VSCROLLBAR, ///< Vertical scrollbar of the list. }; /** Widgets of the #IndustryCargoesWindow class */ From 737775f83427353764511bc6218379331fe5eefc Mon Sep 17 00:00:00 2001 From: translators Date: Mon, 6 Nov 2023 18:38:37 +0000 Subject: [PATCH 56/57] Update: Translations from eints korean: 14 changes by telk5093 polish: 1 change by pAter-exe --- src/lang/korean.txt | 28 ++++++++++++++-------------- src/lang/polish.txt | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 482c1e7912..5f39f87721 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -96,28 +96,28 @@ STR_CARGO_SINGULAR_FIZZY_DRINK :{G=f}탄산음 STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :승객{NBSP}{COMMA}명 STR_QUANTITY_COAL :석탄 {WEIGHT_LONG} -STR_QUANTITY_MAIL :우편 {COMMA}{NBSP}자루 +STR_QUANTITY_MAIL :우편 {COMMA}자루 STR_QUANTITY_OIL :석유 {VOLUME_LONG} -STR_QUANTITY_LIVESTOCK :가축 {COMMA}{NBSP}마리 -STR_QUANTITY_GOODS :상품 {COMMA}{NBSP}상자 +STR_QUANTITY_LIVESTOCK :가축 {COMMA}마리 +STR_QUANTITY_GOODS :상품 {COMMA}상자 STR_QUANTITY_GRAIN :곡물 {WEIGHT_LONG} STR_QUANTITY_WOOD :목재 {WEIGHT_LONG} STR_QUANTITY_IRON_ORE :철광석 {WEIGHT_LONG} STR_QUANTITY_STEEL :철 {WEIGHT_LONG} -STR_QUANTITY_VALUABLES :귀금속 {COMMA}{NBSP}자루 +STR_QUANTITY_VALUABLES :귀금속 {COMMA}자루 STR_QUANTITY_COPPER_ORE :구리 광석 {WEIGHT_LONG} STR_QUANTITY_MAIZE :옥수수 {WEIGHT_LONG} STR_QUANTITY_FRUIT :과일 {WEIGHT_LONG} -STR_QUANTITY_DIAMONDS :다이아몬드 {COMMA}{NBSP}자루 +STR_QUANTITY_DIAMONDS :다이아몬드 {COMMA}자루 STR_QUANTITY_FOOD :식품 {WEIGHT_LONG} STR_QUANTITY_PAPER :종이 {WEIGHT_LONG} -STR_QUANTITY_GOLD :금 {COMMA}{NBSP}자루 +STR_QUANTITY_GOLD :금 {COMMA}자루 STR_QUANTITY_WATER :물 {VOLUME_LONG} STR_QUANTITY_WHEAT :밀 {WEIGHT_LONG} STR_QUANTITY_RUBBER :고무 {VOLUME_LONG} STR_QUANTITY_SUGAR :설탕 {WEIGHT_LONG} -STR_QUANTITY_TOYS :장난감 {COMMA}{NBSP}상자 -STR_QUANTITY_SWEETS :사탕 {COMMA}{NBSP}자루 +STR_QUANTITY_TOYS :장난감 {COMMA}상자 +STR_QUANTITY_SWEETS :사탕 {COMMA}자루 STR_QUANTITY_COLA :콜라 {VOLUME_LONG} STR_QUANTITY_CANDYFLOSS :솜사탕 {WEIGHT_LONG} STR_QUANTITY_BUBBLES :거품 {COMMA}개 @@ -165,11 +165,11 @@ STR_ABBREV_ALL :모두 # 'Mode' of transport for cargoes STR_PASSENGERS :{G=m}{COMMA}명 -STR_BAGS :{G=f}{COMMA}{NBSP}자루 -STR_TONS :{G=m}{COMMA}{NBSP}톤 -STR_LITERS :{G=f}{COMMA}{NBSP}리터 -STR_ITEMS :{G=m}{COMMA}{NBSP}마리 -STR_CRATES :{G=f}{COMMA}{NBSP}상자 +STR_BAGS :{G=f}{COMMA}자루 +STR_TONS :{G=m}{COMMA}톤 +STR_LITERS :{G=f}{COMMA}리터 +STR_ITEMS :{G=m}{COMMA}마리 +STR_CRATES :{G=f}{COMMA}상자 STR_COLOUR_DEFAULT :기본 ###length 17 @@ -1780,7 +1780,7 @@ STR_CONFIG_SETTING_SERVINT_AIRCRAFT :항공기에 STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :항공기에 따로 점검 기간이 설정되어있지 않은 경우에 사용할 기본 점검 기간을 설정합니다. STR_CONFIG_SETTING_SERVINT_SHIPS :선박에 대한 기본 점검 기준: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :선박에 따로 점검 기간이 설정되어있지 않은 경우에 사용할 기본 점검 기간을 설정합니다. -STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}일/% +STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}일/% ###setting-zero-is-special STR_CONFIG_SETTING_SERVINT_DISABLED :사용 안 함 diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 1b5d60ed86..4508e39e0f 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -5575,6 +5575,7 @@ STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Nie moż STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Pojazdy mogą czekać tylko na stacjach STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Ten pojazd nie zatrzymuje się na tej stacji. STR_ERROR_TIMETABLE_INCOMPLETE :{WHITE}... rozkład jazdy jest niekompletny +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... rozkład jazdy jeszcze się nie rozpoczął # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... zbyt wiele napisów From ab535c0a8665e6380c5037d7b6f0a507fc91d36a Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 6 Nov 2023 20:29:35 +0000 Subject: [PATCH 57/57] Codechange: Add base() method to StrongType to allow access to the base type without casting. (#11445) This removes the ability to explicitly cast to the base type, but the requirement to use .base() means the conversion is still explicit. --- src/build_vehicle_gui.cpp | 4 ++-- src/cheat_gui.cpp | 4 ++-- src/company_cmd.cpp | 2 +- src/company_gui.cpp | 2 +- src/core/format.hpp | 2 +- src/core/math_func.hpp | 4 ++-- src/core/strong_typedef_type.hpp | 8 ++++---- src/date_gui.cpp | 4 ++-- src/disaster_vehicle.cpp | 6 +++--- src/economy.cpp | 2 +- src/engine.cpp | 14 ++++++------- src/genworld_gui.cpp | 2 +- src/industry_cmd.cpp | 2 +- src/landscape.cpp | 6 +++--- src/linkgraph/flowmapper.cpp | 2 +- src/linkgraph/linkgraph.cpp | 2 +- src/linkgraph/linkgraph.h | 4 ++-- src/linkgraph/linkgraphschedule.cpp | 4 ++-- src/map.cpp | 2 +- src/map_func.h | 28 +++++++++++++------------- src/misc/dbg_helpers.cpp | 2 +- src/misc/endian_buffer.hpp | 2 +- src/misc_gui.cpp | 6 +++--- src/network/core/network_game_info.cpp | 8 ++++---- src/network/network_admin.cpp | 8 ++++---- src/newgrf.cpp | 13 ++++++------ src/newgrf_engine.cpp | 12 +++++------ src/newgrf_house.cpp | 2 +- src/newgrf_industries.cpp | 12 +++++------ src/newgrf_object.cpp | 4 ++-- src/newgrf_railtype.cpp | 8 ++++---- src/newgrf_roadtype.cpp | 8 ++++---- src/newgrf_town.cpp | 4 ++-- src/news_func.h | 2 +- src/object_cmd.cpp | 2 +- src/openttd.cpp | 4 ++-- src/order_cmd.cpp | 2 +- src/pathfinder/yapf/yapf_node.hpp | 4 ++-- src/pathfinder/yapf/yapf_node_rail.hpp | 2 +- src/rail.cpp | 2 +- src/rail_cmd.cpp | 4 ++-- src/road.cpp | 4 ++-- src/saveload/afterload.cpp | 2 +- src/saveload/oldloader_sl.cpp | 6 +++--- src/script/api/script_basestation.cpp | 2 +- src/script/api/script_bridge.cpp | 4 ++-- src/script/api/script_client.cpp | 2 +- src/script/api/script_date.cpp | 6 +++--- src/script/api/script_date.hpp | 2 +- src/script/api/script_depotlist.cpp | 4 ++-- src/script/api/script_engine.cpp | 4 ++-- src/script/api/script_industry.cpp | 8 ++++---- src/script/api/script_map.hpp | 2 +- src/script/api/script_road.cpp | 4 ++-- src/script/api/script_story_page.cpp | 2 +- src/script/api/script_tilelist.cpp | 8 ++++---- src/script/api/script_tunnel.cpp | 2 +- src/script/api/script_vehicle.cpp | 8 ++++---- src/script/squirrel_helper.hpp | 2 +- src/settings_internal.h | 8 ++++---- src/station_cmd.cpp | 6 +++--- src/story.cpp | 2 +- src/strings_func.h | 4 ++-- src/strings_internal.h | 2 +- src/timer/timer_game_calendar.cpp | 8 ++++---- src/timer/timer_game_calendar.h | 4 ++-- src/timetable_cmd.cpp | 2 +- src/toolbar_gui.cpp | 2 +- src/town_cmd.cpp | 6 +++--- src/tree_cmd.cpp | 2 +- src/vehicle.cpp | 2 +- src/window_func.h | 8 ++++---- src/window_gui.h | 4 ++-- 73 files changed, 174 insertions(+), 173 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index af8b927863..cfedffa181 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1186,7 +1186,7 @@ struct BuildVehicleWindow : Window { { this->vehicle_type = type; this->listview_mode = tile == INVALID_TILE; - this->window_number = this->listview_mode ? (int)type : static_cast(tile); + this->window_number = this->listview_mode ? (int)type : tile.base(); this->sel_engine = INVALID_ENGINE; @@ -1917,7 +1917,7 @@ void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number. * As it always is a low value, it won't collide with any real tile * number. */ - uint num = (tile == INVALID_TILE) ? (int)type : static_cast(tile); + uint num = (tile == INVALID_TILE) ? (int)type : tile.base(); assert(IsCompanyBuildableVehicleType(type)); diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 2b69bbceb9..57899b9cc0 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -102,7 +102,7 @@ static int32_t ClickChangeDateCheat(int32_t new_value, int32_t) { /* Don't allow changing to an invalid year, or the current year. */ auto new_year = Clamp(TimerGameCalendar::Year(new_value), CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR); - if (new_year == TimerGameCalendar::year) return static_cast(TimerGameCalendar::year); + if (new_year == TimerGameCalendar::year) return TimerGameCalendar::year.base(); TimerGameCalendar::YearMonthDay ymd; TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd); @@ -122,7 +122,7 @@ static int32_t ClickChangeDateCheat(int32_t new_value, int32_t) InvalidateWindowClassesData(WC_TRUCK_STATION, 0); InvalidateWindowClassesData(WC_BUILD_OBJECT, 0); ResetSignalVariant(); - return static_cast(TimerGameCalendar::year); + return TimerGameCalendar::year.base(); } /** diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 02663c301e..0e13ea05e5 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -389,7 +389,7 @@ set_name:; SetDParam(1, STR_NEWS_COMPANY_LAUNCH_DESCRIPTION); SetDParamStr(2, cni->company_name); SetDParam(3, t->index); - AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NT_COMPANY_INFO, NF_COMPANY, NR_TILE, static_cast(c->last_build_coordinate), NR_NONE, UINT32_MAX, cni); + AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NT_COMPANY_INFO, NF_COMPANY, NR_TILE, c->last_build_coordinate.base(), NR_NONE, UINT32_MAX, cni); } return; } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 0df7e23cd4..986336b444 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -432,7 +432,7 @@ struct CompanyFinancesWindow : Window { auto age = std::min(TimerGameCalendar::year - c->inaugurated_year, TimerGameCalendar::Year(2)); int wid_offset = widget - WID_CF_EXPS_PRICE1; if (wid_offset <= age) { - DrawYearColumn(r, TimerGameCalendar::year - (age - wid_offset), c->yearly_expenses[static_cast(age - wid_offset)]); + DrawYearColumn(r, TimerGameCalendar::year - (age - wid_offset), c->yearly_expenses[(age - wid_offset).base()]); } break; } diff --git a/src/core/format.hpp b/src/core/format.hpp index 97abe7951c..a94c1580eb 100644 --- a/src/core/format.hpp +++ b/src/core/format.hpp @@ -37,7 +37,7 @@ struct fmt::formatter::value, int> = 0> constexpr To ClampTo(From value) { - return ClampTo(static_cast(value)); + return ClampTo(value.base()); } /** @@ -268,7 +268,7 @@ template ) { - return (size_t)(static_cast(x) - min) < (max - min); + return (size_t)(x.base() - min) < (max - min); } else { return (size_t)(x - min) < (max - min); } diff --git a/src/core/strong_typedef_type.hpp b/src/core/strong_typedef_type.hpp index f5715ed586..e1baeee311 100644 --- a/src/core/strong_typedef_type.hpp +++ b/src/core/strong_typedef_type.hpp @@ -160,10 +160,10 @@ namespace StrongType { constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; } constexpr Typedef &operator =(const TBaseType &rhs) { this->value = rhs; return *this; } - /* Only allow explicit conversions to BaseType. */ - explicit constexpr operator TBaseType () const { return this->value; } + /* Only allow conversion to BaseType via method. */ + constexpr TBaseType base() const { return this->value; } - /* Only allow TProperties classes access to the internal value. Everyone else needs to do an explicit cast. */ + /* Only allow TProperties classes access to the internal value. Everyone else needs to call .base(). */ friend struct Compare; friend struct Integer; template friend struct Compatible; @@ -171,7 +171,7 @@ namespace StrongType { /* GCC / MSVC don't pick up on the "friend struct" above, where CLang does. * As in our CI we compile for all three targets, it is sufficient to have one * that errors on this; but nobody should be using "value" directly. Instead, - * use a static_cast<> to convert to the base type. */ + * use base() to convert to the base type. */ #ifdef __clang__ protected: #endif /* __clang__ */ diff --git a/src/date_gui.cpp b/src/date_gui.cpp index c93dabe1e9..c81252f70f 100644 --- a/src/date_gui.cpp +++ b/src/date_gui.cpp @@ -90,9 +90,9 @@ struct SetDateWindow : Window { case WID_SD_YEAR: for (TimerGameCalendar::Year i = this->min_year; i <= this->max_year; i++) { SetDParam(0, i); - list.push_back(std::make_unique(STR_JUST_INT, static_cast(i), false)); + list.push_back(std::make_unique(STR_JUST_INT, i.base(), false)); } - selected = static_cast(this->date.year); + selected = this->date.year.base(); break; } diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index fed432fdc4..6d3ffc9e75 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -358,7 +358,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v) return true; } else { /* Target a vehicle */ - RoadVehicle *u = RoadVehicle::Get(static_cast(v->dest_tile)); + RoadVehicle *u = RoadVehicle::Get(v->dest_tile.base()); assert(u != nullptr && u->type == VEH_ROAD && u->IsFrontEngine()); uint dist = Delta(v->x_pos, u->x_pos) + Delta(v->y_pos, u->y_pos); @@ -437,7 +437,7 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16_t image_override, b if (v->state == 2) { if (GB(v->tick_counter, 0, 2) == 0) { - Industry *i = Industry::Get(static_cast(v->dest_tile)); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid + Industry *i = Industry::Get(v->dest_tile.base()); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid int x = TileX(i->location.tile) * TILE_SIZE; int y = TileY(i->location.tile) * TILE_SIZE; uint32_t r = Random(); @@ -455,7 +455,7 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16_t image_override, b v->state = 2; v->age = 0; - Industry *i = Industry::Get(static_cast(v->dest_tile)); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid + Industry *i = Industry::Get(v->dest_tile.base()); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid DestructIndustry(i); SetDParam(0, i->town->index); diff --git a/src/economy.cpp b/src/economy.cpp index bc2bd93878..53bd70c6a8 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -928,7 +928,7 @@ void StartupEconomy() if (_settings_game.economy.inflation) { /* Apply inflation that happened before our game start year. */ - int months = static_cast(std::min(TimerGameCalendar::year, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR) * 12; + int months = (std::min(TimerGameCalendar::year, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR).base() * 12; for (int i = 0; i < months; i++) { AddInflation(false); } diff --git a/src/engine.cpp b/src/engine.cpp index d5138ad2cc..bbccfa6ffd 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -439,7 +439,7 @@ uint Engine::GetDisplayMaxTractiveEffort() const TimerGameCalendar::Date Engine::GetLifeLengthInDays() const { /* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */ - return static_cast(this->info.lifelength + _settings_game.vehicle.extend_vehicle_life) * CalendarTime::DAYS_IN_LEAP_YEAR; + return (this->info.lifelength + _settings_game.vehicle.extend_vehicle_life).base() * CalendarTime::DAYS_IN_LEAP_YEAR; } /** @@ -664,7 +664,7 @@ void SetYearEngineAgingStops() /* Base year ending date on half the model life */ TimerGameCalendar::YearMonthDay ymd; - TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (static_cast(ei->lifelength) * CalendarTime::DAYS_IN_LEAP_YEAR) / 2, &ymd); + TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2, &ymd); _year_engine_aging_stops = std::max(_year_engine_aging_stops, ymd.year); } @@ -690,7 +690,7 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se SavedRandomSeeds saved_seeds; SaveRandomSeeds(&saved_seeds); SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^ - static_cast(ei->base_intro) ^ + ei->base_intro.base() ^ e->type ^ e->GetGRFID()); uint32_t r = Random(); @@ -700,7 +700,7 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se * Note: TTDP uses fixed 1922 */ e->intro_date = ei->base_intro <= TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (TimerGameCalendar::Date)GB(r, 0, 9) + ei->base_intro; if (e->intro_date <= TimerGameCalendar::date) { - e->age = static_cast(aging_date - e->intro_date) >> 5; + e->age = (aging_date - e->intro_date).base() >> 5; e->company_avail = MAX_UVALUE(CompanyMask); e->flags |= ENGINE_AVAILABLE; } @@ -712,8 +712,8 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se } SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^ - (re->index << 16) ^ (static_cast(re->info.base_intro) << 12) ^ (re->info.decay_speed << 8) ^ - (static_cast(re->info.lifelength) << 4) ^ re->info.retire_early ^ + (re->index << 16) ^ (re->info.base_intro.base() << 12) ^ (re->info.decay_speed << 8) ^ + (re->info.lifelength.base() << 4) ^ re->info.retire_early ^ e->type ^ e->GetGRFID()); @@ -724,7 +724,7 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se r = Random(); e->reliability_final = GB(r, 16, 14) + 0x3FFF; e->duration_phase_1 = GB(r, 0, 5) + 7; - e->duration_phase_2 = GB(r, 5, 4) + static_cast(ei->base_life) * 12 - 96; + e->duration_phase_2 = GB(r, 5, 4) + ei->base_life.base() * 12 - 96; e->duration_phase_3 = GB(r, 9, 7) + 120; RestoreRandomSeeds(saved_seeds); diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 5b9e36f3d3..693d7f60c1 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -962,7 +962,7 @@ struct GenerateLandscapeWindow : public Window { /* An empty string means revert to the default */ switch (this->widget_id) { case WID_GL_HEIGHTMAP_HEIGHT_TEXT: value = MAP_HEIGHT_LIMIT_AUTO_MINIMUM; break; - case WID_GL_START_DATE_TEXT: value = static_cast(CalendarTime::DEF_START_YEAR); break; + case WID_GL_START_DATE_TEXT: value = CalendarTime::DEF_START_YEAR.base(); break; case WID_GL_SNOW_COVERAGE_TEXT: value = DEF_SNOW_COVERAGE; break; case WID_GL_DESERT_COVERAGE_TEXT: value = DEF_DESERT_COVERAGE; break; case WID_GL_TOWN_PULLDOWN: value = 1; break; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 7f9f6c546d..6c42240ba3 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -153,7 +153,7 @@ Industry::~Industry() for (TileIndex tile_cur : this->location) { if (IsTileType(tile_cur, MP_INDUSTRY)) { if (GetIndustryIndex(tile_cur) == this->index) { - DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, static_cast(tile_cur)); + DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur.base()); /* MakeWaterKeepingClass() can also handle 'land' */ MakeWaterKeepingClass(tile_cur, OWNER_NONE); diff --git a/src/landscape.cpp b/src/landscape.cpp index 87c2c73943..b534c8345a 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -787,7 +787,7 @@ void RunTileLoop() _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile); /* Get the next tile in sequence using a Galois LFSR. */ - tile = (static_cast(tile) >> 1) ^ (-(int32_t)(static_cast(tile) & 1) & feedback); + tile = (tile.base() >> 1) ^ (-(int32_t)(tile.base() & 1) & feedback); } _cur_tileloop_tile = tile; @@ -939,7 +939,7 @@ static void CreateDesertOrRainForest(uint desert_tropic_line) const TileIndexDiffC *data; for (TileIndex tile = 0; tile != Map::Size(); ++tile) { - if ((static_cast(tile) % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + if ((tile.base() % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); if (!IsValidTile(tile)) continue; @@ -960,7 +960,7 @@ static void CreateDesertOrRainForest(uint desert_tropic_line) } for (TileIndex tile = 0; tile != Map::Size(); ++tile) { - if ((static_cast(tile) % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + if ((tile.base() % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); if (!IsValidTile(tile)) continue; diff --git a/src/linkgraph/flowmapper.cpp b/src/linkgraph/flowmapper.cpp index dfbce810a1..2fdd0a61f9 100644 --- a/src/linkgraph/flowmapper.cpp +++ b/src/linkgraph/flowmapper.cpp @@ -52,7 +52,7 @@ void FlowMapper::Run(LinkGraphJob &job) const * LinkGraph::Monthly(). */ auto runtime = job.JoinDate() - job.Settings().recalc_time / CalendarTime::SECONDS_PER_DAY - job.LastCompression() + 1; for (auto &it : flows) { - it.second.ScaleToMonthly(static_cast(runtime)); + it.second.ScaleToMonthly(runtime.base()); } } /* Clear paths. */ diff --git a/src/linkgraph/linkgraph.cpp b/src/linkgraph/linkgraph.cpp index b573df0913..1dcb2eecff 100644 --- a/src/linkgraph/linkgraph.cpp +++ b/src/linkgraph/linkgraph.cpp @@ -65,7 +65,7 @@ void LinkGraph::ShiftDates(TimerGameCalendar::Date interval) void LinkGraph::Compress() { - this->last_compression = static_cast(TimerGameCalendar::date + this->last_compression) / 2; + this->last_compression = (TimerGameCalendar::date + this->last_compression).base() / 2; for (NodeID node1 = 0; node1 < this->Size(); ++node1) { this->nodes[node1].supply /= 2; for (BaseEdge &edge : this->nodes[node1].edges) { diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index ff1778e0c7..12f32a2885 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -185,7 +185,7 @@ public: */ inline static uint Scale(uint val, TimerGameCalendar::Date target_age, TimerGameCalendar::Date orig_age) { - return val > 0 ? std::max(1U, val * static_cast(target_age) / static_cast(orig_age)) : 0; + return val > 0 ? std::max(1U, val * target_age.base() / orig_age.base()) : 0; } /** Bare constructor, only for save/load. */ @@ -248,7 +248,7 @@ public: */ inline uint Monthly(uint base) const { - return base * 30 / static_cast(TimerGameCalendar::date - this->last_compression + 1); + return base * 30 / (TimerGameCalendar::date - this->last_compression + 1).base(); } NodeID AddNode(const Station *st); diff --git a/src/linkgraph/linkgraphschedule.cpp b/src/linkgraph/linkgraphschedule.cpp index 3f3fed8168..0e2f03785c 100644 --- a/src/linkgraph/linkgraphschedule.cpp +++ b/src/linkgraph/linkgraphschedule.cpp @@ -178,7 +178,7 @@ void StateGameLoop_LinkGraphPauseControl() } } else if (_pause_mode == PM_UNPAUSED && TimerGameCalendar::date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 && - static_cast(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) / 2 && + TimerGameCalendar::date.base() % (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) / 2 && LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) { /* Perform check two TimerGameCalendar::date_fract ticks before we would join, to make * sure it also works in multiplayer. */ @@ -205,7 +205,7 @@ void AfterLoad_LinkGraphPauseControl() void OnTick_LinkGraph() { if (TimerGameCalendar::date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return; - TimerGameCalendar::Date offset = static_cast(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY); + TimerGameCalendar::Date offset = TimerGameCalendar::date.base() % (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY); if (offset == 0) { LinkGraphSchedule::instance.SpawnNext(); } else if (offset == (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) / 2) { diff --git a/src/map.cpp b/src/map.cpp index 2fea8ae36c..f9a8ff5db9 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -83,7 +83,7 @@ TileIndex TileAdd(TileIndex tile, TileIndexDiff add, if (x >= Map::SizeX() || y >= Map::SizeY()) { std::string message = fmt::format("TILE_ADD({}) when adding 0x{:04X} and 0x{%04X} failed", - exp, (uint32_t)tile, add); + exp, tile, add); #if !defined(_MSC_VER) fmt::print(stderr, "{}:{} {}\n", file, line, message); #else diff --git a/src/map_func.h b/src/map_func.h index 89507a9c70..d4b3de70bc 100644 --- a/src/map_func.h +++ b/src/map_func.h @@ -77,7 +77,7 @@ public: /** * Implicit conversion to the uint for bounds checking. */ - debug_inline constexpr operator uint() const { return static_cast(tile); } + debug_inline constexpr operator uint() const { return tile.base(); } /** * The type (bits 4..7), bridges (2..3), rainforest/desert (0..1) @@ -88,7 +88,7 @@ public: */ debug_inline byte &type() { - return base_tiles[static_cast(tile)].type; + return base_tiles[tile.base()].type; } /** @@ -100,7 +100,7 @@ public: */ debug_inline byte &height() { - return base_tiles[static_cast(tile)].height; + return base_tiles[tile.base()].height; } /** @@ -112,7 +112,7 @@ public: */ debug_inline byte &m1() { - return base_tiles[static_cast(tile)].m1; + return base_tiles[tile.base()].m1; } /** @@ -124,7 +124,7 @@ public: */ debug_inline uint16_t &m2() { - return base_tiles[static_cast(tile)].m2; + return base_tiles[tile.base()].m2; } /** @@ -136,7 +136,7 @@ public: */ debug_inline byte &m3() { - return base_tiles[static_cast(tile)].m3; + return base_tiles[tile.base()].m3; } /** @@ -148,7 +148,7 @@ public: */ debug_inline byte &m4() { - return base_tiles[static_cast(tile)].m4; + return base_tiles[tile.base()].m4; } /** @@ -160,7 +160,7 @@ public: */ debug_inline byte &m5() { - return base_tiles[static_cast(tile)].m5; + return base_tiles[tile.base()].m5; } /** @@ -172,7 +172,7 @@ public: */ debug_inline byte &m6() { - return extended_tiles[static_cast(tile)].m6; + return extended_tiles[tile.base()].m6; } /** @@ -184,7 +184,7 @@ public: */ debug_inline byte &m7() { - return extended_tiles[static_cast(tile)].m7; + return extended_tiles[tile.base()].m7; } /** @@ -196,7 +196,7 @@ public: */ debug_inline uint16_t &m8() { - return extended_tiles[static_cast(tile)].m8; + return extended_tiles[tile.base()].m8; } }; @@ -316,7 +316,7 @@ public: */ static inline TileIndex WrapToMap(TileIndex tile) { - return static_cast(tile) & Map::tile_mask; + return tile.base() & Map::tile_mask; } /** @@ -426,7 +426,7 @@ debug_inline static TileIndex TileVirtXY(uint x, uint y) */ debug_inline static uint TileX(TileIndex tile) { - return static_cast(tile) & Map::MaxX(); + return tile.base() & Map::MaxX(); } /** @@ -436,7 +436,7 @@ debug_inline static uint TileX(TileIndex tile) */ debug_inline static uint TileY(TileIndex tile) { - return static_cast(tile) >> Map::LogX(); + return tile.base() >> Map::LogX(); } /** diff --git a/src/misc/dbg_helpers.cpp b/src/misc/dbg_helpers.cpp index 8c18d7b77c..b2e743c7ea 100644 --- a/src/misc/dbg_helpers.cpp +++ b/src/misc/dbg_helpers.cpp @@ -63,7 +63,7 @@ std::string ValueStr(SignalType t) std::string TileStr(TileIndex tile) { std::stringstream ss; - ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << static_cast(tile); // 0x%04X + ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << tile.base(); // 0x%04X ss << " (" << TileX(tile) << ", " << TileY(tile) << ")"; return ss.str(); } diff --git a/src/misc/endian_buffer.hpp b/src/misc/endian_buffer.hpp index 8422ebb4d3..17cb576878 100644 --- a/src/misc/endian_buffer.hpp +++ b/src/misc/endian_buffer.hpp @@ -53,7 +53,7 @@ public: if constexpr (std::is_enum_v) { this->Write(static_cast>(data)); } else if constexpr (std::is_base_of_v) { - this->Write(static_cast(data)); + this->Write(data.base()); } else { this->Write(data); } diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 0780d3b876..49dd4cc552 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -207,7 +207,7 @@ public: /* Location */ std::stringstream tile_ss; - tile_ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << static_cast(tile); // 0x%.4X + tile_ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << tile.base(); // 0x%.4X SetDParam(0, TileX(tile)); SetDParam(1, TileY(tile)); @@ -332,12 +332,12 @@ public: bool IsNewGRFInspectable() const override { - return ::IsNewGRFInspectable(GetGrfSpecFeature(this->tile), static_cast(this->tile)); + return ::IsNewGRFInspectable(GetGrfSpecFeature(this->tile), this->tile.base()); } void ShowNewGRFInspectWindow() const override { - ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), static_cast(this->tile)); + ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile.base()); } void OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) override diff --git a/src/network/core/network_game_info.cpp b/src/network/core/network_game_info.cpp index 817eb518b8..ecf6569d86 100644 --- a/src/network/core/network_game_info.cpp +++ b/src/network/core/network_game_info.cpp @@ -227,8 +227,8 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, bool } /* NETWORK_GAME_INFO_VERSION = 3 */ - p->Send_uint32(static_cast(info->game_date)); - p->Send_uint32(static_cast(info->start_date)); + p->Send_uint32(info->game_date.base()); + p->Send_uint32(info->start_date.base()); /* NETWORK_GAME_INFO_VERSION = 2 */ p->Send_uint8 (info->companies_max); @@ -321,8 +321,8 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo } case 3: - info->game_date = Clamp(p->Recv_uint32(), 0, static_cast(CalendarTime::MAX_DATE)); - info->start_date = Clamp(p->Recv_uint32(), 0, static_cast(CalendarTime::MAX_DATE)); + info->game_date = Clamp(p->Recv_uint32(), 0, CalendarTime::MAX_DATE.base()); + info->start_date = Clamp(p->Recv_uint32(), 0, CalendarTime::MAX_DATE.base()); FALLTHROUGH; case 2: diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index 3e633f9b34..3df0182937 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -178,7 +178,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome() p->Send_string(""); // Used to be map-name. p->Send_uint32(_settings_game.game_creation.generation_seed); p->Send_uint8 (_settings_game.game_creation.landscape); - p->Send_uint32(static_cast(TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1))); + p->Send_uint32(TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1).base()); p->Send_uint16(Map::SizeX()); p->Send_uint16(Map::SizeY()); @@ -208,7 +208,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate() { Packet *p = new Packet(ADMIN_PACKET_SERVER_DATE); - p->Send_uint32(static_cast(TimerGameCalendar::date)); + p->Send_uint32(TimerGameCalendar::date.base()); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; @@ -244,7 +244,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkC p->Send_string(cs == nullptr ? "" : const_cast(cs->client_address).GetHostname()); p->Send_string(ci->client_name); p->Send_uint8 (0); // Used to be language - p->Send_uint32(static_cast(ci->join_date)); + p->Send_uint32(ci->join_date.base()); p->Send_uint8 (ci->client_playas); this->SendPacket(p); @@ -329,7 +329,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company p->Send_string(GetString(STR_PRESIDENT_NAME)); p->Send_uint8 (c->colour); p->Send_bool (NetworkCompanyIsPassworded(c->index)); - p->Send_uint32(static_cast(c->inaugurated_year)); + p->Send_uint32(c->inaugurated_year.base()); p->Send_bool (c->is_ai); p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 604fe777e8..5bf37d1554 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -6512,18 +6512,18 @@ bool GetGlobalVariable(byte param, uint32_t *value, const GRFFile *grffile) { switch (param) { case 0x00: // current date - *value = static_cast(std::max(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0))); + *value = std::max(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0)).base(); return true; case 0x01: // current year - *value = static_cast(Clamp(TimerGameCalendar::year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR); + *value = (Clamp(TimerGameCalendar::year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR).base(); return true; case 0x02: { // detailed date information: month of year (bit 0-7), day of month (bit 8-12), leap year (bit 15), day of year (bit 16-24) TimerGameCalendar::YearMonthDay ymd; TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd); TimerGameCalendar::Date start_of_year = TimerGameCalendar::ConvertYMDToDate(ymd.year, 0, 1); - *value = ymd.month | (ymd.day - 1) << 8 | (TimerGameCalendar::IsLeapYear(ymd.year) ? 1 << 15 : 0) | static_cast(TimerGameCalendar::date - start_of_year) << 16; + *value = ymd.month | (ymd.day - 1) << 8 | (TimerGameCalendar::IsLeapYear(ymd.year) ? 1 << 15 : 0) | (TimerGameCalendar::date - start_of_year).base() << 16; return true; } @@ -6629,11 +6629,11 @@ bool GetGlobalVariable(byte param, uint32_t *value, const GRFFile *grffile) return true; case 0x23: // long format date - *value = static_cast(TimerGameCalendar::date); + *value = TimerGameCalendar::date.base(); return true; case 0x24: // long format year - *value = static_cast(TimerGameCalendar::year); + *value = TimerGameCalendar::year.base(); return true; default: return false; @@ -6646,6 +6646,7 @@ static uint32_t GetParamVal(byte param, uint32_t *cond_val) uint32_t value; if (GetGlobalVariable(param - 0x80, &value, _cur.grffile)) return value; + /* Non-common variable */ switch (param) { case 0x84: { // GRF loading stage @@ -7228,7 +7229,7 @@ static uint32_t GetPatchVariable(uint8_t param) { switch (param) { /* start year - 1920 */ - case 0x0B: return static_cast(std::max(_settings_game.game_creation.starting_year, CalendarTime::ORIGINAL_BASE_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR); + case 0x0B: return (std::max(_settings_game.game_creation.starting_year, CalendarTime::ORIGINAL_BASE_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR).base(); /* freight trains weight factor */ case 0x0E: return _settings_game.vehicle.freight_trains; diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 27321ec496..df3be19561 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -557,7 +557,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec } case 0x48: return v->GetEngine()->flags; // Vehicle Type Info - case 0x49: return static_cast(v->build_year); + case 0x49: return v->build_year.base(); case 0x4A: switch (v->type) { @@ -582,7 +582,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec } case 0x4B: // Long date of last service - return static_cast(v->date_of_last_service_newgrf); + return v->date_of_last_service_newgrf.base(); case 0x4C: // Current maximum speed in NewGRF units if (!v->IsPrimaryVehicle()) return 0; @@ -814,7 +814,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec case 0x41: return GB(ClampTo(v->age), 8, 8); case 0x42: return ClampTo(v->max_age); case 0x43: return GB(ClampTo(v->max_age), 8, 8); - case 0x44: return static_cast(Clamp(v->build_year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR); + case 0x44: return (Clamp(v->build_year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR).base(); case 0x45: return v->unitnumber; case 0x46: return v->GetEngine()->grf_prop.local_id; case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8); @@ -957,11 +957,11 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec } } case 0x48: return Engine::Get(this->self_type)->flags; // Vehicle Type Info - case 0x49: return static_cast(TimerGameCalendar::year); // 'Long' format build year - case 0x4B: return static_cast(TimerGameCalendar::date); // Long date of last service + case 0x49: return TimerGameCalendar::year.base(); // 'Long' format build year + case 0x4B: return TimerGameCalendar::date.base(); // Long date of last service case 0x92: return ClampTo(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date of last service case 0x93: return GB(ClampTo(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8); - case 0xC4: return static_cast(Clamp(TimerGameCalendar::year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR); // Build year + case 0xC4: return (Clamp(TimerGameCalendar::year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR).base(); // Build year case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id; case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8); case 0xDA: return INVALID_VEHICLE; // Next vehicle diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index feab4c4fc0..63e7c44d69 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -301,7 +301,7 @@ static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex tile, Ho case 0x40: return (IsTileType(this->tile, MP_HOUSE) ? GetHouseBuildingStage(this->tile) : 0) | TileHash2Bit(TileX(this->tile), TileY(this->tile)) << 2; /* Building age. */ - case 0x41: return static_cast(IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile) : 0); + case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile).base() : 0; /* Town zone */ case 0x42: return GetTownRadiusGroup(this->town, this->tile); diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index b25691267c..2f37abf5d4 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -162,8 +162,8 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo /* Variables available during construction check. */ switch (variable) { - case 0x80: return static_cast(this->tile); - case 0x81: return GB(static_cast(this->tile), 8, 8); + case 0x80: return this->tile.base(); + case 0x81: return GB(this->tile.base(), 8, 8); /* Pointer to the town the industry is associated with */ case 0x82: return this->industry->town->index; @@ -247,7 +247,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo return this->industry->founder | (is_ai ? 0x10000 : 0) | (colours << 24); } - case 0x46: return static_cast(this->industry->construction_date); // Date when built - long format - (in days) + case 0x46: return this->industry->construction_date.base(); // Date when built - long format - (in days) /* Override flags from GS */ case 0x47: return this->industry->ctlflags; @@ -338,7 +338,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo if (!IsValidCargoID(cargo)) return 0; auto it = this->industry->GetCargoAccepted(cargo); if (it == std::end(this->industry->accepted)) return 0; // invalid cargo - if (variable == 0x6E) return static_cast(it->last_accepted); + if (variable == 0x6E) return it->last_accepted.base(); if (variable == 0x6F) return it->waiting; NOT_REACHED(); } @@ -347,8 +347,8 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte param_setID, byte layo case 0x7C: return (this->industry->psa != nullptr) ? this->industry->psa->GetValue(parameter) : 0; /* Industry structure access*/ - case 0x80: return static_cast(this->industry->location.tile); - case 0x81: return GB(static_cast(this->industry->location.tile), 8, 8); + case 0x80: return this->industry->location.tile.base(); + case 0x81: return GB(this->industry->location.tile.base(), 8, 8); /* Pointer to the town the industry is associated with */ case 0x82: return this->industry->town->index; case 0x83: diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index c6098d54c7..740f82ec97 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -277,7 +277,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte local_id, uint32_t grf break; /* Construction date */ - case 0x42: return static_cast(TimerGameCalendar::date); + case 0x42: return TimerGameCalendar::date.base(); /* Object founder information */ case 0x44: return _current_company; @@ -315,7 +315,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(byte local_id, uint32_t grf case 0x41: return GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile); /* Construction date */ - case 0x42: return static_cast(this->obj->build_date); + case 0x42: return this->obj->build_date.base(); /* Animation counter */ case 0x43: return GetAnimationFrame(this->tile); diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 694025ef07..608e63546f 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -19,7 +19,7 @@ /* virtual */ uint32_t RailTypeScopeResolver::GetRandomBits() const { - uint tmp = CountBits(static_cast(this->tile + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE)); + uint tmp = CountBits(this->tile.base() + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE); return GB(tmp, 0, 2); } @@ -30,7 +30,7 @@ case 0x40: return 0; case 0x41: return 0; case 0x42: return 0; - case 0x43: return static_cast(TimerGameCalendar::date); + case 0x43: return TimerGameCalendar::date.base(); case 0x44: return HZB_TOWN_EDGE; } } @@ -40,8 +40,8 @@ case 0x41: return 0; case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile); case 0x43: - if (IsRailDepotTile(this->tile)) return static_cast(Depot::GetByTile(this->tile)->build_date); - return static_cast(TimerGameCalendar::date); + if (IsRailDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date.base(); + return TimerGameCalendar::date.base(); case 0x44: { const Town *t = nullptr; if (IsRailDepotTile(this->tile)) { diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp index c49850d687..4a877c8bf3 100644 --- a/src/newgrf_roadtype.cpp +++ b/src/newgrf_roadtype.cpp @@ -19,7 +19,7 @@ /* virtual */ uint32_t RoadTypeScopeResolver::GetRandomBits() const { - uint tmp = CountBits(static_cast(this->tile + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE)); + uint tmp = CountBits(this->tile.base() + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE); return GB(tmp, 0, 2); } @@ -30,7 +30,7 @@ case 0x40: return 0; case 0x41: return 0; case 0x42: return 0; - case 0x43: return static_cast(TimerGameCalendar::date); + case 0x43: return TimerGameCalendar::date.base(); case 0x44: return HZB_TOWN_EDGE; } } @@ -40,8 +40,8 @@ case 0x41: return 0; case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile); case 0x43: - if (IsRoadDepotTile(this->tile)) return static_cast(Depot::GetByTile(this->tile)->build_date); - return static_cast(TimerGameCalendar::date); + if (IsRoadDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date.base(); + return TimerGameCalendar::date.base(); case 0x44: { const Town *t = nullptr; if (IsRoadDepotTile(this->tile)) { diff --git a/src/newgrf_town.cpp b/src/newgrf_town.cpp index 5f8f5972c8..83eda4204c 100644 --- a/src/newgrf_town.cpp +++ b/src/newgrf_town.cpp @@ -44,8 +44,8 @@ } /* Town properties */ - case 0x80: return static_cast(this->t->xy); - case 0x81: return GB(static_cast(this->t->xy), 8, 8); + case 0x80: return this->t->xy.base(); + case 0x81: return GB(this->t->xy.base(), 8, 8); case 0x82: return ClampTo(this->t->cache.population); case 0x83: return GB(ClampTo(this->t->cache.population), 8, 8); case 0x8A: return this->t->grow_counter / Ticks::TOWN_GROWTH_TICKS; diff --git a/src/news_func.h b/src/news_func.h index 941e6b54c9..01f22ebc8a 100644 --- a/src/news_func.h +++ b/src/news_func.h @@ -44,7 +44,7 @@ static inline void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle) static inline void AddTileNewsItem(StringID string, NewsType type, TileIndex tile, const NewsAllocatedData *data = nullptr, StationID station = INVALID_STATION) { - AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_TILE, static_cast(tile), station == INVALID_STATION ? NR_NONE : NR_STATION, station, data); + AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_TILE, tile.base(), station == INVALID_STATION ? NR_NONE : NR_STATION, station, data); } static inline void AddIndustryNewsItem(StringID string, NewsType type, IndustryID industry, const NewsAllocatedData *data = nullptr) diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index fb39133dc7..f8c503499b 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -511,7 +511,7 @@ static void ReallyClearObjectTile(Object *o) { Object::DecTypeCount(o->type); for (TileIndex tile_cur : o->location) { - DeleteNewGRFInspectWindow(GSF_OBJECTS, static_cast(tile_cur)); + DeleteNewGRFInspectWindow(GSF_OBJECTS, tile_cur.base()); MakeWaterKeepingClass(tile_cur, GetTileOwner(tile_cur)); } diff --git a/src/openttd.cpp b/src/openttd.cpp index 611d21f1e3..19eb01432f 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -429,7 +429,7 @@ struct AfterNewGRFScan : NewGRFScanCallback { MusicDriver::GetInstance()->SetVolume(_settings_client.music.music_vol); SetEffectVolume(_settings_client.music.effect_vol); - if (startyear != CalendarTime::INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", static_cast(startyear)); + if (startyear != CalendarTime::INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", startyear.base()); if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed; if (!dedicated_host.empty()) { @@ -1409,7 +1409,7 @@ void StateGameLoop() CallWindowGameTickEvent(); NewsLoop(); } else { - if (_debug_desync_level > 2 && TimerGameCalendar::date_fract == 0 && (static_cast(TimerGameCalendar::date) & 0x1F) == 0) { + if (_debug_desync_level > 2 && TimerGameCalendar::date_fract == 0 && (TimerGameCalendar::date.base() & 0x1F) == 0) { /* Save the desync savegame if needed. */ std::string name = fmt::format("dmp_cmds_{:08x}_{:08x}.sav", _settings_game.game_creation.generation_seed, TimerGameCalendar::date); SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false); diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index fc32913bdc..2650843c1f 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1900,7 +1900,7 @@ static bool OrderConditionCompare(OrderConditionComparator occ, int variable, in template ::value, int> = 0> static bool OrderConditionCompare(OrderConditionComparator occ, T variable, int value) { - return OrderConditionCompare(occ, static_cast(variable), value); + return OrderConditionCompare(occ, variable.base(), value); } /** diff --git a/src/pathfinder/yapf/yapf_node.hpp b/src/pathfinder/yapf/yapf_node.hpp index 9d079ae918..760ed330bb 100644 --- a/src/pathfinder/yapf/yapf_node.hpp +++ b/src/pathfinder/yapf/yapf_node.hpp @@ -25,7 +25,7 @@ struct CYapfNodeKeyExitDir { inline int CalcHash() const { - return m_exitdir | (static_cast(m_tile) << 2); + return m_exitdir | (m_tile.base() << 2); } inline bool operator==(const CYapfNodeKeyExitDir &other) const @@ -45,7 +45,7 @@ struct CYapfNodeKeyTrackDir : public CYapfNodeKeyExitDir { inline int CalcHash() const { - return m_td | (static_cast(m_tile) << 4); + return m_td | (m_tile.base() << 4); } inline bool operator==(const CYapfNodeKeyTrackDir &other) const diff --git a/src/pathfinder/yapf/yapf_node_rail.hpp b/src/pathfinder/yapf/yapf_node_rail.hpp index cecaaa95c4..a7a0795150 100644 --- a/src/pathfinder/yapf/yapf_node_rail.hpp +++ b/src/pathfinder/yapf/yapf_node_rail.hpp @@ -27,7 +27,7 @@ struct CYapfRailSegmentKey inline void Set(const CYapfNodeKeyTrackDir &node_key) { - m_value = (static_cast(node_key.m_tile) << 4) | node_key.m_td; + m_value = (node_key.m_tile.base() << 4) | node_key.m_td; } inline int32_t CalcHash() const diff --git a/src/rail.cpp b/src/rail.cpp index 9bd11e391c..01b6421535 100644 --- a/src/rail.cpp +++ b/src/rail.cpp @@ -225,7 +225,7 @@ RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date if (rti->label == 0) continue; /* Not date introduced. */ - if (!IsInsideMM(rti->introduction_date, 0, static_cast(CalendarTime::MAX_DATE))) continue; + if (!IsInsideMM(rti->introduction_date, 0, CalendarTime::MAX_DATE.base())) continue; /* Not yet introduced at this date. */ if (rti->introduction_date > date) continue; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 1d312ffd49..d4dd2fe65d 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -656,7 +656,7 @@ CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(owner); MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypeRoad(tile), GetRoadTypeTram(tile), GetTownIndex(tile), GetRoadOwner(tile, RTT_ROAD), GetRoadOwner(tile, RTT_TRAM)); - DeleteNewGRFInspectWindow(GSF_RAILTYPES, static_cast(tile)); + DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile.base()); } break; } @@ -714,7 +714,7 @@ CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track } else { DoClearSquare(tile); } - DeleteNewGRFInspectWindow(GSF_RAILTYPES, static_cast(tile)); + DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile.base()); } else { SetTrackBits(tile, present); SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present); diff --git a/src/road.cpp b/src/road.cpp index bf607fdb36..d3de25d44f 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -115,7 +115,7 @@ bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype) if (rti->label == 0) return false; /* Not yet introduced at this date. */ - if (IsInsideMM(rti->introduction_date, 0, static_cast(CalendarTime::MAX_DATE)) && rti->introduction_date > TimerGameCalendar::date) return false; + if (IsInsideMM(rti->introduction_date, 0, CalendarTime::MAX_DATE.base()) && rti->introduction_date > TimerGameCalendar::date) return false; /* * Do not allow building hidden road types, except when a town may build it. @@ -173,7 +173,7 @@ RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date if (rti->label == 0) continue; /* Not date introduced. */ - if (!IsInsideMM(rti->introduction_date, 0, static_cast(CalendarTime::MAX_DATE))) continue; + if (!IsInsideMM(rti->introduction_date, 0, CalendarTime::MAX_DATE.base())) continue; /* Not yet introduced at this date. */ if (rti->introduction_date > date) continue; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index d94b17306d..1a13b011c9 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2144,7 +2144,7 @@ bool AfterLoadGame() /* Delete small ufos heading for non-existing vehicles */ for (DisasterVehicle *v : DisasterVehicle::Iterate()) { if (v->subtype == 2 /* ST_SMALL_UFO */ && v->state != 0) { - const Vehicle *u = Vehicle::GetIfValid(static_cast(v->dest_tile)); + const Vehicle *u = Vehicle::GetIfValid(v->dest_tile.base()); if (u == nullptr || u->type != VEH_ROAD || !RoadVehicle::From(u)->IsFrontEngine()) { delete v; } diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 54c4f51090..7589e87708 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -57,8 +57,8 @@ static void FixTTDMapArray() /* _old_map3 is moved to _m::m3 and _m::m4 */ for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) { Tile tile(t); - tile.m3() = _old_map3[static_cast(t) * 2]; - tile.m4() = _old_map3[static_cast(t) * 2 + 1]; + tile.m3() = _old_map3[t.base() * 2]; + tile.m4() = _old_map3[t.base() * 2 + 1]; } for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) { @@ -416,7 +416,7 @@ static bool FixTTOEngines() if (TimerGameCalendar::date >= e->intro_date && HasBit(e->info.climates, 0)) { e->flags |= ENGINE_AVAILABLE; e->company_avail = MAX_UVALUE(CompanyMask); - e->age = TimerGameCalendar::date > e->intro_date ? static_cast(TimerGameCalendar::date - e->intro_date) / 30 : 0; + e->age = TimerGameCalendar::date > e->intro_date ? (TimerGameCalendar::date - e->intro_date).base() / 30 : 0; } } else { /* Using data from TTO savegame */ diff --git a/src/script/api/script_basestation.cpp b/src/script/api/script_basestation.cpp index caa5cf8034..2dc0ce6c81 100644 --- a/src/script/api/script_basestation.cpp +++ b/src/script/api/script_basestation.cpp @@ -63,5 +63,5 @@ { if (!IsValidBaseStation(station_id)) return ScriptDate::DATE_INVALID; - return (ScriptDate::Date)(int32_t)::BaseStation::Get(station_id)->build_date; + return (ScriptDate::Date)::BaseStation::Get(station_id)->build_date.base(); } diff --git a/src/script/api/script_bridge.cpp b/src/script/api/script_bridge.cpp index b128c87d2b..165fc60a2f 100644 --- a/src/script/api/script_bridge.cpp +++ b/src/script/api/script_bridge.cpp @@ -83,8 +83,8 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) switch (vehicle_type) { case ScriptVehicle::VT_ROAD: - ScriptObject::SetCallbackVariable(0, static_cast(start)); - ScriptObject::SetCallbackVariable(1, static_cast(end)); + ScriptObject::SetCallbackVariable(0, start.base()); + ScriptObject::SetCallbackVariable(1, end.base()); return ScriptObject::Command::Do(&::_DoCommandReturnBuildBridge1, end, start, TRANSPORT_ROAD, bridge_id, ScriptRoad::GetCurrentRoadType()); case ScriptVehicle::VT_RAIL: return ScriptObject::Command::Do(end, start, TRANSPORT_RAIL, bridge_id, ScriptRail::GetCurrentRailType()); diff --git a/src/script/api/script_client.cpp b/src/script/api/script_client.cpp index 5445698913..9b65f638db 100644 --- a/src/script/api/script_client.cpp +++ b/src/script/api/script_client.cpp @@ -50,5 +50,5 @@ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client) { NetworkClientInfo *ci = FindClientInfo(client); if (ci == nullptr) return ScriptDate::DATE_INVALID; - return (ScriptDate::Date)(int32_t)ci->join_date; + return (ScriptDate::Date)ci->join_date.base(); } diff --git a/src/script/api/script_date.cpp b/src/script/api/script_date.cpp index 886bef830f..d82c2815f4 100644 --- a/src/script/api/script_date.cpp +++ b/src/script/api/script_date.cpp @@ -22,7 +22,7 @@ /* static */ ScriptDate::Date ScriptDate::GetCurrentDate() { - return (ScriptDate::Date)(int32_t)TimerGameCalendar::date; + return (ScriptDate::Date)TimerGameCalendar::date.base(); } /* static */ SQInteger ScriptDate::GetYear(ScriptDate::Date date) @@ -31,7 +31,7 @@ ::TimerGameCalendar::YearMonthDay ymd; ::TimerGameCalendar::ConvertDateToYMD(date, &ymd); - return (int32_t)ymd.year; + return ymd.year.base(); } /* static */ SQInteger ScriptDate::GetMonth(ScriptDate::Date date) @@ -58,7 +58,7 @@ if (day_of_month < 1 || day_of_month > 31) return DATE_INVALID; if (year < 0 || year > CalendarTime::MAX_YEAR) return DATE_INVALID; - return (ScriptDate::Date)(int32_t)::TimerGameCalendar::ConvertYMDToDate(year, month - 1, day_of_month); + return (ScriptDate::Date)::TimerGameCalendar::ConvertYMDToDate(year, month - 1, day_of_month).base(); } /* static */ SQInteger ScriptDate::GetSystemTime() diff --git a/src/script/api/script_date.hpp b/src/script/api/script_date.hpp index 2e108a74c8..b224c6e62b 100644 --- a/src/script/api/script_date.hpp +++ b/src/script/api/script_date.hpp @@ -31,7 +31,7 @@ public: * compose valid date values for a known year, month and day. */ enum Date { - DATE_INVALID = (int32_t)::CalendarTime::INVALID_DATE, ///< A value representing an invalid date. + DATE_INVALID = ::CalendarTime::INVALID_DATE.base(), ///< A value representing an invalid date. }; /** diff --git a/src/script/api/script_depotlist.cpp b/src/script/api/script_depotlist.cpp index 9f2dc96ee4..6f3caa2900 100644 --- a/src/script/api/script_depotlist.cpp +++ b/src/script/api/script_depotlist.cpp @@ -30,7 +30,7 @@ ScriptDepotList::ScriptDepotList(ScriptTile::TransportType transport_type) for (const Station *st : Station::Iterate()) { if (st->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity()) { for (uint i = 0; i < st->airport.GetNumHangars(); i++) { - this->AddItem(static_cast(st->airport.GetHangarTile(i))); + this->AddItem(st->airport.GetHangarTile(i).base()); } } } @@ -40,6 +40,6 @@ ScriptDepotList::ScriptDepotList(ScriptTile::TransportType transport_type) /* Handle 'standard' depots. */ for (const Depot *depot : Depot::Iterate()) { - if ((::GetTileOwner(depot->xy) == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity()) && ::IsTileType(depot->xy, tile_type)) this->AddItem(static_cast(depot->xy)); + if ((::GetTileOwner(depot->xy) == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity()) && ::IsTileType(depot->xy, tile_type)) this->AddItem(depot->xy.base()); } } diff --git a/src/script/api/script_engine.cpp b/src/script/api/script_engine.cpp index 9797b863c4..22caa1fad9 100644 --- a/src/script/api/script_engine.cpp +++ b/src/script/api/script_engine.cpp @@ -139,7 +139,7 @@ if (!IsValidEngine(engine_id)) return -1; if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1; - return (int32_t)::Engine::Get(engine_id)->GetLifeLengthInDays(); + return ::Engine::Get(engine_id)->GetLifeLengthInDays().base(); } /* static */ Money ScriptEngine::GetRunningCost(EngineID engine_id) @@ -179,7 +179,7 @@ { if (!IsValidEngine(engine_id)) return ScriptDate::DATE_INVALID; - return (ScriptDate::Date)(int32_t)::Engine::Get(engine_id)->intro_date; + return (ScriptDate::Date)::Engine::Get(engine_id)->intro_date.base(); } /* static */ ScriptVehicle::VehicleType ScriptEngine::GetVehicleType(EngineID engine_id) diff --git a/src/script/api/script_industry.cpp b/src/script/api/script_industry.cpp index 3196e9c698..86f5a85e40 100644 --- a/src/script/api/script_industry.cpp +++ b/src/script/api/script_industry.cpp @@ -53,7 +53,7 @@ { Industry *i = Industry::GetIfValid(industry_id); if (i == nullptr) return ScriptDate::DATE_INVALID; - return (ScriptDate::Date)(int32_t)i->construction_date; + return (ScriptDate::Date)i->construction_date.base(); } /* static */ bool ScriptIndustry::SetText(IndustryID industry_id, Text *text) @@ -222,7 +222,7 @@ { Industry *i = Industry::GetIfValid(industry_id); if (i == nullptr) return 0; - return (int32_t)i->last_prod_year; + return i->last_prod_year.base(); } /* static */ ScriptDate::Date ScriptIndustry::GetCargoLastAcceptedDate(IndustryID industry_id, CargoID cargo_type) @@ -232,11 +232,11 @@ if (!::IsValidCargoID(cargo_type)) { auto it = std::max_element(std::begin(i->accepted), std::end(i->accepted), [](const auto &a, const auto &b) { return a.last_accepted < b.last_accepted; }); - return (ScriptDate::Date)(int32_t)it->last_accepted; + return (ScriptDate::Date)it->last_accepted.base(); } else { auto it = i->GetCargoAccepted(cargo_type); if (it == std::end(i->accepted)) return ScriptDate::DATE_INVALID; - return (ScriptDate::Date)(int32_t)it->last_accepted; + return (ScriptDate::Date)it->last_accepted.base(); } } diff --git a/src/script/api/script_map.hpp b/src/script/api/script_map.hpp index 45b4a4b191..323ba31c28 100644 --- a/src/script/api/script_map.hpp +++ b/src/script/api/script_map.hpp @@ -19,7 +19,7 @@ */ class ScriptMap : public ScriptObject { public: - static const int TILE_INVALID = static_cast(INVALID_TILE); ///< Invalid TileIndex. + static const int TILE_INVALID = INVALID_TILE.base(); ///< Invalid TileIndex. /** * Checks whether the given tile is valid. diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp index 8c702f1b41..2be3dac282 100644 --- a/src/script/api/script_road.cpp +++ b/src/script/api/script_road.cpp @@ -382,8 +382,8 @@ static bool NormaliseTileOffset(int32_t *tile) /* static */ SQInteger ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> &&existing, TileIndex start_, TileIndex end_) { ::Slope slope = (::Slope)slope_; - int32_t start = static_cast(start_); - int32_t end = static_cast(end_); + int32_t start = start_.base(); + int32_t end = end_.base(); /* The start tile and end tile cannot be the same tile either. */ if (start == end) return -1; diff --git a/src/script/api/script_story_page.cpp b/src/script/api/script_story_page.cpp index 4a049f540c..87a46427eb 100644 --- a/src/script/api/script_story_page.cpp +++ b/src/script/api/script_story_page.cpp @@ -182,7 +182,7 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type) EnforcePrecondition(ScriptDate::DATE_INVALID, IsValidStoryPage(story_page_id)); EnforceDeityMode(ScriptDate::DATE_INVALID); - return (ScriptDate::Date)(int32_t)StoryPage::Get(story_page_id)->date; + return (ScriptDate::Date)StoryPage::Get(story_page_id)->date.base(); } /* static */ bool ScriptStoryPage::SetDate(StoryPageID story_page_id, ScriptDate::Date date) diff --git a/src/script/api/script_tilelist.cpp b/src/script/api/script_tilelist.cpp index e23b4eaa33..6262db3acc 100644 --- a/src/script/api/script_tilelist.cpp +++ b/src/script/api/script_tilelist.cpp @@ -21,14 +21,14 @@ void ScriptTileList::AddRectangle(TileIndex t1, TileIndex t2) if (!::IsValidTile(t2)) return; TileArea ta(t1, t2); - for (TileIndex t : ta) this->AddItem(static_cast(t)); + for (TileIndex t : ta) this->AddItem(t.base()); } void ScriptTileList::AddTile(TileIndex tile) { if (!::IsValidTile(tile)) return; - this->AddItem(static_cast(tile)); + this->AddItem(tile.base()); } void ScriptTileList::RemoveRectangle(TileIndex t1, TileIndex t2) @@ -37,14 +37,14 @@ void ScriptTileList::RemoveRectangle(TileIndex t1, TileIndex t2) if (!::IsValidTile(t2)) return; TileArea ta(t1, t2); - for (TileIndex t : ta) this->RemoveItem(static_cast(t)); + for (TileIndex t : ta) this->RemoveItem(t.base()); } void ScriptTileList::RemoveTile(TileIndex tile) { if (!::IsValidTile(tile)) return; - this->RemoveItem(static_cast(tile)); + this->RemoveItem(tile.base()); } /** diff --git a/src/script/api/script_tunnel.cpp b/src/script/api/script_tunnel.cpp index a1ff3e03e2..1ae9f2d78f 100644 --- a/src/script/api/script_tunnel.cpp +++ b/src/script/api/script_tunnel.cpp @@ -93,7 +93,7 @@ static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance) /* For rail we do nothing special */ return ScriptObject::Command::Do(start, TRANSPORT_RAIL, ScriptRail::GetCurrentRailType()); } else { - ScriptObject::SetCallbackVariable(0, static_cast(start)); + ScriptObject::SetCallbackVariable(0, start.base()); return ScriptObject::Command::Do(&::_DoCommandReturnBuildTunnel1, start, TRANSPORT_ROAD, ScriptRoad::GetCurrentRoadType()); } } diff --git a/src/script/api/script_vehicle.cpp b/src/script/api/script_vehicle.cpp index 76f4f282b0..4b1c3c2baf 100644 --- a/src/script/api/script_vehicle.cpp +++ b/src/script/api/script_vehicle.cpp @@ -311,7 +311,7 @@ { if (!IsValidVehicle(vehicle_id)) return -1; - return (int32_t)::Vehicle::Get(vehicle_id)->age; + return ::Vehicle::Get(vehicle_id)->age.base(); } /* static */ SQInteger ScriptVehicle::GetWagonAge(VehicleID vehicle_id, SQInteger wagon) @@ -323,21 +323,21 @@ if (v->type == VEH_TRAIN) { while (wagon-- > 0) v = ::Train::From(v)->GetNextUnit(); } - return (int32_t)v->age; + return v->age.base(); } /* static */ SQInteger ScriptVehicle::GetMaxAge(VehicleID vehicle_id) { if (!IsPrimaryVehicle(vehicle_id)) return -1; - return (int32_t)::Vehicle::Get(vehicle_id)->max_age; + return ::Vehicle::Get(vehicle_id)->max_age.base(); } /* static */ SQInteger ScriptVehicle::GetAgeLeft(VehicleID vehicle_id) { if (!IsPrimaryVehicle(vehicle_id)) return -1; - return (int32_t)(::Vehicle::Get(vehicle_id)->max_age - ::Vehicle::Get(vehicle_id)->age); + return (::Vehicle::Get(vehicle_id)->max_age - ::Vehicle::Get(vehicle_id)->age).base(); } /* static */ SQInteger ScriptVehicle::GetCurrentSpeed(VehicleID vehicle_id) diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index ba22fc881a..cff129c6d2 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -37,7 +37,7 @@ namespace SQConvert { template <> struct Return { static inline int Set(HSQUIRRELVM vm, int32_t res) { sq_pushinteger(vm, res); return 1; } }; template <> struct Return { static inline int Set(HSQUIRRELVM vm, int64_t res) { sq_pushinteger(vm, res); return 1; } }; template <> struct Return { static inline int Set(HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } }; - template <> struct Return { static inline int Set(HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32_t)static_cast(res)); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32_t)res.base()); return 1; } }; template <> struct Return { static inline int Set(HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } }; template <> struct Return { /* Do not use char *, use std::optional instead. */ }; template <> struct Return { /* Do not use const char *, use std::optional instead. */ }; diff --git a/src/settings_internal.h b/src/settings_internal.h index 7980ebae03..914071909b 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -174,25 +174,25 @@ struct IntSettingDesc : SettingDesc { str(str), str_help(str_help), str_val(str_val), cat(cat), pre_check(pre_check), post_callback(post_callback) { if constexpr (std::is_base_of_v) { - this->def = static_cast(def); + this->def = def.base(); } else { this->def = def; } if constexpr (std::is_base_of_v) { - this->min = static_cast(min); + this->min = min.base(); } else { this->min = min; } if constexpr (std::is_base_of_v) { - this->max = static_cast(max); + this->max = max.base(); } else { this->max = max; } if constexpr (std::is_base_of_v) { - this->interval = static_cast(interval); + this->interval = interval.base(); } else { this->interval = interval; } diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 2f03490441..4a561ad060 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1664,7 +1664,7 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector &affected_st if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[rt]--; DoClearSquare(tile); - DeleteNewGRFInspectWindow(GSF_STATIONS, static_cast(tile)); + DeleteNewGRFInspectWindow(GSF_STATIONS, tile.base()); if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt); Company::Get(owner)->infrastructure.station--; DirtyCompanyInfrastructureWindows(owner); @@ -2162,7 +2162,7 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags, int repla uint specindex = GetCustomRoadStopSpecIndex(tile); - DeleteNewGRFInspectWindow(GSF_ROADSTOPS, static_cast(tile)); + DeleteNewGRFInspectWindow(GSF_ROADSTOPS, tile.base()); if (IsDriveThroughStopTile(tile)) { /* Clears the tile for us */ @@ -2546,7 +2546,7 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) if (flags & DC_EXEC) { DeleteAnimatedTile(tile_cur); DoClearSquare(tile_cur); - DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, static_cast(tile_cur)); + DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur.base()); } } diff --git a/src/story.cpp b/src/story.cpp index 86e09a0705..a03c2a12f7 100644 --- a/src/story.cpp +++ b/src/story.cpp @@ -99,7 +99,7 @@ static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32_t referen break; case SPET_LOCATION: pe.text = text; - pe.referenced_id = static_cast(tile); + pe.referenced_id = tile.base(); break; case SPET_GOAL: pe.referenced_id = (GoalID)reference; diff --git a/src/strings_func.h b/src/strings_func.h index 38417a85b7..bb2e5476d5 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -86,13 +86,13 @@ void SetDParamMaxDigits(size_t n, uint count, FontSize size = FS_NORMAL); template ::value, int> = 0> void SetDParam(size_t n, T v) { - SetDParam(n, static_cast(v)); + SetDParam(n, v.base()); } template ::value, int> = 0> void SetDParamMaxValue(size_t n, T max_value, uint min_count = 0, FontSize size = FS_NORMAL) { - SetDParamMaxValue(n, static_cast(max_value), min_count, size); + SetDParamMaxValue(n, max_value.base(), min_count, size); } void SetDParamStr(size_t n, const char *str); diff --git a/src/strings_internal.h b/src/strings_internal.h index ef5499059a..f5648d3d39 100644 --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -156,7 +156,7 @@ public: template ::value, int> = 0> void SetParam(size_t n, T v) { - SetParam(n, static_cast(v)); + SetParam(n, v.base()); } void SetParam(size_t n, const char *str) diff --git a/src/timer/timer_game_calendar.cpp b/src/timer/timer_game_calendar.cpp index dcdabfb021..4b62da7f6a 100644 --- a/src/timer/timer_game_calendar.cpp +++ b/src/timer/timer_game_calendar.cpp @@ -75,8 +75,8 @@ static const uint16_t _accum_days_for_month[] = { */ /* There are 97 leap years in 400 years */ - TimerGameCalendar::Year yr = 400 * (static_cast(date) / (CalendarTime::DAYS_IN_YEAR * 400 + 97)); - int rem = static_cast(date) % (CalendarTime::DAYS_IN_YEAR * 400 + 97); + TimerGameCalendar::Year yr = 400 * (date.base() / (CalendarTime::DAYS_IN_YEAR * 400 + 97)); + int rem = date.base() % (CalendarTime::DAYS_IN_YEAR * 400 + 97); uint16_t x; if (rem >= CalendarTime::DAYS_IN_YEAR * 100 + 25) { @@ -141,7 +141,7 @@ static const uint16_t _accum_days_for_month[] = { */ /* static */ bool TimerGameCalendar::IsLeapYear(TimerGameCalendar::Year yr) { - return static_cast(yr) % 4 == 0 && (static_cast(yr) % 100 != 0 || static_cast(yr) % 400 == 0); + return yr.base() % 4 == 0 && (yr.base() % 100 != 0 || yr.base() % 400 == 0); } /** @@ -215,7 +215,7 @@ void TimerManager::Elapsed([[maybe_unused]] TimerGameCalendar timer->Elapsed(TimerGameCalendar::DAY); } - if ((static_cast(TimerGameCalendar::date) % 7) == 3) { + if ((TimerGameCalendar::date.base() % 7) == 3) { for (auto timer : timers) { timer->Elapsed(TimerGameCalendar::WEEK); } diff --git a/src/timer/timer_game_calendar.h b/src/timer/timer_game_calendar.h index e62f745615..0b82db80c6 100644 --- a/src/timer/timer_game_calendar.h +++ b/src/timer/timer_game_calendar.h @@ -113,7 +113,7 @@ public: static constexpr Year DateToYear(Date date) { /* Hardcode the number of days in a year because we can't access CalendarTime from here. */ - return static_cast(date) / 366; + return date.base() / 366; } /** @@ -123,7 +123,7 @@ public: */ static constexpr Date DateAtStartOfYear(Year year) { - int32_t year_as_int = static_cast(year); + int32_t year_as_int = year.base(); uint number_of_leap_years = (year == 0) ? 0 : ((year_as_int - 1) / 4 - (year_as_int - 1) / 100 + (year_as_int - 1) / 400 + 1); /* Hardcode the number of days in a year because we can't access CalendarTime from here. */ diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 6b77355c59..a18ed54426 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -437,7 +437,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED); if (v->timetable_start != 0) { - v->lateness_counter = static_cast(TimerGameCalendar::date - v->timetable_start) * Ticks::DAY_TICKS + TimerGameCalendar::date_fract; + v->lateness_counter = (TimerGameCalendar::date - v->timetable_start).base() * Ticks::DAY_TICKS + TimerGameCalendar::date_fract; v->timetable_start = 0; } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 7df6a2c833..8919c99dac 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2499,7 +2499,7 @@ struct ScenarioEditorToolbarWindow : Window { value = atoi(str); } else { /* An empty string means revert to the default */ - value = static_cast(CalendarTime::DEF_START_YEAR); + value = CalendarTime::DEF_START_YEAR.base(); } SetStartingYear(value); diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 49a4ab1acf..30463dd25d 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -594,7 +594,7 @@ static void TileLoop_Town(TileIndex tile) /* Binomial distribution per tick, by a series of coin flips */ /* Reduce generation rate to a 1/4, using tile bits to spread out distribution. * As tick counter is incremented by 256 between each call, we ignore the lower 8 bits. */ - if (GB(TimerGameTick::counter, 8, 2) == GB(static_cast(tile), 0, 2)) { + if (GB(TimerGameTick::counter, 8, 2) == GB(tile.base(), 0, 2)) { /* Make a bitmask with up to 32 bits set, one for each potential pax */ int genmax = (hs->population + 7) / 8; uint32_t genmask = (genmax >= 32) ? 0xFFFFFFFF : ((1 << genmax) - 1); @@ -870,7 +870,7 @@ RoadType GetTownRoadType() if (!HasBit(rti->flags, ROTF_TOWN_BUILD)) continue; /* Not yet introduced at this date. */ - if (IsInsideMM(rti->introduction_date, 0, static_cast(CalendarTime::MAX_DATE)) && rti->introduction_date > TimerGameCalendar::date) continue; + if (IsInsideMM(rti->introduction_date, 0, CalendarTime::MAX_DATE.base()) && rti->introduction_date > TimerGameCalendar::date) continue; if (best != nullptr) { if ((rti->max_speed == 0 ? assume_max_speed : rti->max_speed) < (best->max_speed == 0 ? assume_max_speed : best->max_speed)) continue; @@ -2720,7 +2720,7 @@ static void DoClearTownHouseHelper(TileIndex tile, Town *t, HouseID house) DoClearSquare(tile); DeleteAnimatedTile(tile); - DeleteNewGRFInspectWindow(GSF_HOUSES, static_cast(tile)); + DeleteNewGRFInspectWindow(GSF_HOUSES, tile.base()); } /** diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index e0dc5279bc..99406f81fb 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -527,7 +527,7 @@ static void DrawTile_Trees(TileInfo *ti) /* Do not draw trees when the invisible trees setting is set */ if (IsInvisibilitySet(TO_TREES)) return; - uint tmp = CountBits(static_cast(ti->tile + ti->x + ti->y)); + uint tmp = CountBits(ti->tile.base() + ti->x + ti->y); uint index = GB(tmp, 0, 2) + (GetTreeType(ti->tile) << 2); /* different tree styles above one of the grounds */ diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 2fc8ee6cc1..e2cf5ba841 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1400,7 +1400,7 @@ void AgeVehicle(Vehicle *v) str = STR_NEWS_VEHICLE_IS_GETTING_OLD; } else if (age == TimerGameCalendar::DateAtStartOfYear(0)) { str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD; - } else if (age > TimerGameCalendar::DateAtStartOfYear(0) && (static_cast(age) % CalendarTime::DAYS_IN_LEAP_YEAR) == 0) { + } else if (age > TimerGameCalendar::DateAtStartOfYear(0) && (age.base() % CalendarTime::DAYS_IN_LEAP_YEAR) == 0) { str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND; } else { return; diff --git a/src/window_func.h b/src/window_func.h index c99ef98616..8cc02153ee 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -23,7 +23,7 @@ void ChangeWindowOwner(Owner old_owner, Owner new_owner); template::value, int> = 0> Window *FindWindowById(WindowClass cls, T number) { - return FindWindowById(cls, static_cast(number)); + return FindWindowById(cls, number.base()); } void ResizeWindow(Window *w, int x, int y, bool clamp_to_screen = true); @@ -47,7 +47,7 @@ void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = template::value, int> = 0> void InvalidateWindowData(WindowClass cls, T number, int data = 0, bool gui_scope = false) { - InvalidateWindowData(cls, static_cast(number), data, gui_scope); + InvalidateWindowData(cls, number.base(), data, gui_scope); } void CloseNonVitalWindows(); @@ -70,7 +70,7 @@ void SetWindowClassesDirty(WindowClass cls); template::value, int> = 0> void SetWindowDirty(WindowClass cls, T number) { - SetWindowDirty(cls, static_cast(number)); + SetWindowDirty(cls, number.base()); } void CloseWindowById(WindowClass cls, WindowNumber number, bool force = true, int data = 0); @@ -79,7 +79,7 @@ void CloseWindowByClass(WindowClass cls, int data = 0); template::value, int> = 0> void CloseWindowById(WindowClass cls, T number, bool force = true, int data = 0) { - CloseWindowById(cls, static_cast(number), force, data); + CloseWindowById(cls, number.base(), force, data); } bool EditBoxInGlobalFocus(); diff --git a/src/window_gui.h b/src/window_gui.h index e444c6ea89..46dcdd6acb 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -289,7 +289,7 @@ public: template::value, int> = 0> void FinishInitNested(T number) { - this->FinishInitNested(static_cast(number)); + this->FinishInitNested(number.base()); } /** @@ -935,7 +935,7 @@ Window *FindWindowFromPt(int x, int y); template::value, int> = 0> Window *BringWindowToFrontById(WindowClass cls, T number) { - return BringWindowToFrontById(cls, static_cast(number)); + return BringWindowToFrontById(cls, number.base()); } /**