From c2d4098afa7be59cefc0b1e01c6f7b83e4a63c65 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 23 May 2025 17:44:19 +0100 Subject: [PATCH] Add: Configuration of NewGRF badges. --- src/CMakeLists.txt | 2 + src/dropdown.cpp | 7 +- src/dropdown_type.h | 2 +- src/lang/english.txt | 1 + src/newgrf.cpp | 2 + src/newgrf_badge.cpp | 10 ++ src/newgrf_badge.h | 1 + src/newgrf_badge_config.cpp | 199 ++++++++++++++++++++++++++++++++ src/newgrf_badge_config.h | 31 +++++ src/newgrf_badge_gui.cpp | 218 +++++++++++++++++++++++++++++++++++- src/newgrf_badge_gui.h | 3 + src/settings.cpp | 3 + 12 files changed, 470 insertions(+), 9 deletions(-) create mode 100644 src/newgrf_badge_config.cpp create mode 100644 src/newgrf_badge_config.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 591bc6f4ba..266e4e577c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -279,6 +279,8 @@ add_files( newgrf_animation_type.h newgrf_badge.cpp newgrf_badge.h + newgrf_badge_config.cpp + newgrf_badge_config.h newgrf_badge_gui.cpp newgrf_badge_gui.h newgrf_badge_type.h diff --git a/src/dropdown.cpp b/src/dropdown.cpp index b55b9ad65d..efeb428b4a 100644 --- a/src/dropdown.cpp +++ b/src/dropdown.cpp @@ -347,9 +347,10 @@ struct DropdownWindow : Window { } } - void ReplaceList(DropDownList &&list) + void ReplaceList(DropDownList &&list, std::optional selected_result) { this->list = std::move(list); + if (selected_result.has_value()) this->selected_result = *selected_result; this->UpdateSizeAndPosition(); this->ReInit(0, 0); this->InitializePositionSize(this->position.x, this->position.y, this->nested_root->smallest_x, this->nested_root->smallest_y); @@ -358,10 +359,10 @@ struct DropdownWindow : Window { } }; -void ReplaceDropDownList(Window *parent, DropDownList &&list) +void ReplaceDropDownList(Window *parent, DropDownList &&list, std::optional selected_result) { DropdownWindow *ddw = dynamic_cast(parent->FindChildWindow(WC_DROPDOWN_MENU)); - if (ddw != nullptr) ddw->ReplaceList(std::move(list)); + if (ddw != nullptr) ddw->ReplaceList(std::move(list), selected_result); } /** diff --git a/src/dropdown_type.h b/src/dropdown_type.h index ad77986459..5e6057d1ee 100644 --- a/src/dropdown_type.h +++ b/src/dropdown_type.h @@ -60,6 +60,6 @@ void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID but Dimension GetDropDownListDimension(const DropDownList &list); -void ReplaceDropDownList(Window *parent, DropDownList &&list); +void ReplaceDropDownList(Window *parent, DropDownList &&list, std::optional selected_result = std::nullopt); #endif /* DROPDOWN_TYPE_H */ diff --git a/src/lang/english.txt b/src/lang/english.txt index 5ec8953530..1fe8b436e3 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -5917,3 +5917,4 @@ STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) STR_BADGE_NAME_LIST :{STRING}: {GOLD}{RAW_STRING} +STR_BADGE_CONFIG_RESET :Reset diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 4ec0b83160..f1bb512784 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -22,6 +22,7 @@ #include "currency.h" #include "landscape.h" #include "newgrf_badge.h" +#include "newgrf_badge_config.h" #include "newgrf_cargo.h" #include "newgrf_sound.h" #include "newgrf_station.h" @@ -1604,6 +1605,7 @@ static void FinaliseBadges() } ApplyBadgeFeaturesToClassBadges(); + AddBadgeClassesToConfiguration(); } extern void InitGRFTownGeneratorNames(); diff --git a/src/newgrf_badge.cpp b/src/newgrf_badge.cpp index ee0b39742c..da9a8604ce 100644 --- a/src/newgrf_badge.cpp +++ b/src/newgrf_badge.cpp @@ -10,6 +10,7 @@ #include "stdafx.h" #include "newgrf.h" #include "newgrf_badge.h" +#include "newgrf_badge_config.h" #include "newgrf_badge_type.h" #include "newgrf_spritegroup.h" #include "stringfilter_type.h" @@ -42,6 +43,15 @@ std::span GetBadges() return _badges.specs; } +/** + * Get a read-only view of class badge index. + * @return Span of badges. + */ +std::span GetClassBadges() +{ + return _badges.classes; +} + /** * Assign a BadgeClassID to the given badge. * @param index Badge ID of badge that should be assigned. diff --git a/src/newgrf_badge.h b/src/newgrf_badge.h index 684bf08a5b..2c7c0855ca 100644 --- a/src/newgrf_badge.h +++ b/src/newgrf_badge.h @@ -55,6 +55,7 @@ std::span GetBadges(); Badge *GetBadge(BadgeID index); Badge *GetBadgeByLabel(std::string_view label); Badge *GetClassBadge(BadgeClassID class_index); +std::span GetClassBadges(); uint32_t GetBadgeVariableResult(const struct GRFFile &grffile, std::span badges, uint32_t parameter); diff --git a/src/newgrf_badge_config.cpp b/src/newgrf_badge_config.cpp new file mode 100644 index 0000000000..8dcbbf353c --- /dev/null +++ b/src/newgrf_badge_config.cpp @@ -0,0 +1,199 @@ +/* + * 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 newgrf_badge_config.cpp Functionality for NewGRF badge configuration. */ + +#include "stdafx.h" +#include "core/string_consumer.hpp" +#include "ini_type.h" +#include "newgrf.h" +#include "newgrf_badge.h" +#include "newgrf_badge_config.h" +#include "newgrf_badge_type.h" + +#include "table/strings.h" + +#include "safeguards.h" + +/** Global state for badge class configuration. */ +class BadgeClassConfig { +public: + static inline const BadgeClassConfigItem EMPTY_CONFIG_ITEM{}; + + std::array, GrfSpecFeature::GSF_END> features = {}; + + static constexpr GrfSpecFeatures CONFIGURABLE_FEATURES = { + GSF_TRAINS, GSF_ROADVEHICLES, GSF_SHIPS, GSF_AIRCRAFT, GSF_STATIONS, GSF_HOUSES, GSF_OBJECTS, GSF_ROADSTOPS, + }; + + static inline const std::array sections = { + "badges_trains", // GSF_TRAINS + "badges_roadvehicles", // GSF_ROADVEHICLES + "badges_ships", // GSF_SHIPS + "badges_aircraft", // GSF_AIRCRAFT + "badges_stations", // GSF_STATIONS + {}, // GSF_CANALS + {}, // GSF_BRIDGES + "badges_houses", // GSF_HOUSES + {}, // GSF_GLOBALVAR + {}, // GSF_INDUSTRYTILES + {}, // GSF_INDUSTRIES + {}, // GSF_CARGOES + {}, // GSF_SOUNDFX + {}, // GSF_AIRPORTS + {}, // GSF_SIGNALS + "badges_objects", // GSF_OBJECTS + {}, // GSF_RAILTYPES + {}, // GSF_AIRPORTTILES + {}, // GSF_ROADTYPES + {}, // GSF_TRAMTYPES + "badges_roadstops", // GSF_ROADSTOPS + {}, // GSF_BADGES + }; +}; + +/** Static instance of badge class configuration state. */ +static BadgeClassConfig _badge_config; + +/** + * Get the badge user configuration for a feature. + * @returns badge configuration for the given feature. + */ +std::span GetBadgeClassConfiguration(GrfSpecFeature feature) +{ + assert(BadgeClassConfig::CONFIGURABLE_FEATURES.Test(feature)); + assert(feature < std::size(_badge_config.features)); + return _badge_config.features[to_underlying(feature)]; +} + +/** + * Add current badge classes to user configuration. + */ +void AddBadgeClassesToConfiguration() +{ + for (const GrfSpecFeature &feature : BadgeClassConfig::CONFIGURABLE_FEATURES) { + auto &config = _badge_config.features[feature]; + + for (const BadgeID &index : GetClassBadges()) { + const Badge &badge = *GetBadge(index); + if (badge.name == STR_NULL) continue; + if (!badge.features.Test(feature)) continue; + + auto found = std::ranges::find(config, badge.label, &BadgeClassConfigItem::label); + if (found != std::end(config)) continue; + + /* Not found, insert it. */ + config.emplace_back(badge.label, 0, true); + } + } +} + +/** + * Reset badge class configuration for a feature. + * @param feature Feature to reset. + */ +void ResetBadgeClassConfiguration(GrfSpecFeature feature) +{ + assert(feature < GrfSpecFeature::GSF_END); + + auto &config = _badge_config.features[feature]; + config.clear(); + + for (const BadgeID &index : GetClassBadges()) { + const Badge &badge = *GetBadge(index); + if (badge.name == STR_NULL) continue; + config.emplace_back(badge.label, 0, true); + } +} + +/** + * Get configuration for a badge class. + * @param feature Feature being used. + * @param label Badge class label. + * @return badge class configuration item. + */ +std::pair GetBadgeClassConfigItem(GrfSpecFeature feature, std::string_view label) +{ + auto config = GetBadgeClassConfiguration(feature); + auto found = std::ranges::find(config, label, &BadgeClassConfigItem::label); + if (found == std::end(config)) { + return {BadgeClassConfig::EMPTY_CONFIG_ITEM, 0}; + } + + /* Sort order is simply the position in the configuration list. */ + return {*found, static_cast(std::distance(std::begin(config), found))}; +} + +/** + * Load badge column preferences. + * @param ini IniFile to load to. + * @param feature Feature to load. + */ +static void BadgeClassLoadConfigFeature(const IniFile &ini, GrfSpecFeature feature) +{ + assert(BadgeClassConfig::CONFIGURABLE_FEATURES.Test(feature)); + assert(!BadgeClassConfig::sections[feature].empty()); + + auto &config = _badge_config.features[feature]; + config.clear(); + + const IniGroup *group = ini.GetGroup(BadgeClassConfig::sections[feature]); + if (group == nullptr) return; + + for (const IniItem &item : group->items) { + int column = 0; + bool show_icon = true; + + if (item.value.has_value() && !item.value.value().empty()) { + StringConsumer consumer(item.value.value()); + if (consumer.ReadCharIf('!')) show_icon = false; + if (auto value = consumer.TryReadIntegerBase(10); value.has_value()) column = *value; + } + + config.emplace_back(item.name, column, show_icon); + } +} + +/** + * Load badge column preferences. + * @param ini IniFile to load to. + */ +void BadgeClassLoadConfig(const IniFile &ini) +{ + for (const GrfSpecFeature &feature : BadgeClassConfig::CONFIGURABLE_FEATURES) { + BadgeClassLoadConfigFeature(ini, feature); + } +} + +/** + * Save badge column preferences. + * @param ini IniFile to save to. + * @param feature Feature to save. + */ +static void BadgeClassSaveConfigFeature(IniFile &ini, GrfSpecFeature feature) +{ + assert(BadgeClassConfig::CONFIGURABLE_FEATURES.Test(feature)); + assert(!BadgeClassConfig::sections[feature].empty()); + + IniGroup &group = ini.GetOrCreateGroup(BadgeClassConfig::sections[feature]); + group.Clear(); + + for (const auto &item : _badge_config.features[to_underlying(feature)]) { + group.CreateItem(item.label).SetValue(fmt::format("{}{}", item.show_icon ? "" : "!", item.column)); + } +} + +/** + * Save badge column preferences. + * @param ini IniFile to save to. + */ +void BadgeClassSaveConfig(IniFile &ini) +{ + for (const GrfSpecFeature &feature : BadgeClassConfig::CONFIGURABLE_FEATURES) { + BadgeClassSaveConfigFeature(ini, feature); + } +} diff --git a/src/newgrf_badge_config.h b/src/newgrf_badge_config.h new file mode 100644 index 0000000000..4b7f7845a3 --- /dev/null +++ b/src/newgrf_badge_config.h @@ -0,0 +1,31 @@ +/* + * 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 newgrf_badge_config.h Functions related to NewGRF badge configuration. */ + +#ifndef NEWGRF_BADGE_CONFIG_H +#define NEWGRF_BADGE_CONFIG_H + +#include "newgrf.h" +#include "newgrf_badge_type.h" + +class BadgeClassConfigItem { +public: + std::string label; ///< Class label. + int column = -1; ///< UI column, feature-dependent. + bool show_icon = false; ///< Set if the badge icons should be displayed for this class. +}; + +void BadgeClassLoadConfig(const struct IniFile &ini); +void BadgeClassSaveConfig(struct IniFile &ini); + +std::span GetBadgeClassConfiguration(GrfSpecFeature feature); +void AddBadgeClassesToConfiguration(); +void ResetBadgeClassConfiguration(GrfSpecFeature feature); +std::pair GetBadgeClassConfigItem(GrfSpecFeature feature, std::string_view label); + +#endif /* NEWGRF_BADGE_CONFIG_H */ diff --git a/src/newgrf_badge_gui.cpp b/src/newgrf_badge_gui.cpp index 6a9fba6459..6716ee152b 100644 --- a/src/newgrf_badge_gui.cpp +++ b/src/newgrf_badge_gui.cpp @@ -11,10 +11,13 @@ #include "core/flatset_type.hpp" #include "dropdown_type.h" +#include "dropdown_func.h" #include "newgrf.h" #include "newgrf_badge.h" +#include "newgrf_badge_config.h" #include "newgrf_badge_gui.h" #include "newgrf_badge_type.h" +#include "settings_gui.h" #include "strings_func.h" #include "timer/timer_game_calendar.h" #include "window_gui.h" @@ -77,12 +80,10 @@ GUIBadgeClasses::GUIBadgeClasses(GrfSpecFeature feature) Dimension size = GetBadgeMaximalDimension(class_index, feature); if (size.width == 0) continue; - uint8_t column = 0; - bool visible = true; - uint sort_order = UINT_MAX; + auto [config, sort_order] = GetBadgeClassConfigItem(feature, class_badge->label); - this->gui_classes.emplace_back(class_index, column, visible, sort_order, size, class_badge->label); - if (visible) max_column = std::max(max_column, column); + this->gui_classes.emplace_back(class_index, config.column, config.show_icon, sort_order, size, class_badge->label); + if (config.show_icon) max_column = std::max(max_column, config.column); } std::sort(std::begin(this->gui_classes), std::end(this->gui_classes)); @@ -246,3 +247,210 @@ std::unique_ptr MakeDropDownListBadgeIconItem(const std::share { return std::make_unique(gui_classes, badges, feature, introduction_date, dim, sprite, palette, std::move(str), value, masked, shaded); } + +/** + * Drop down component that shows extra buttons to indicate that the item can be moved up or down. + */ +template +class DropDownMover : public TBase { +public: + template + explicit DropDownMover(int click_up, int click_down, Colours button_colour, Args &&...args) + : TBase(std::forward(args)...), click_up(click_up), click_down(click_down), button_colour(button_colour) + { + } + + uint Height() const override + { + return std::max(SETTING_BUTTON_HEIGHT, this->TBase::Height()); + } + + uint Width() const override + { + return SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide + this->TBase::Width(); + } + + int OnClick(const Rect &r, const Point &pt) const override + { + bool rtl = (_current_text_dir == TD_RTL); + int w = SETTING_BUTTON_WIDTH; + + Rect br = r.WithWidth(w, TEnd ^ rtl).CentreTo(w, SETTING_BUTTON_HEIGHT); + if (br.WithWidth(w / 2, rtl).Contains(pt)) return this->click_up; + if (br.WithWidth(w / 2, !rtl).Contains(pt)) return this->click_down; + + return this->TBase::OnClick(r.Indent(w + WidgetDimensions::scaled.hsep_wide, TEnd ^ rtl), pt); + } + + void Draw(const Rect &full, const Rect &r, bool sel, int click_result, Colours bg_colour) const override + { + bool rtl = (_current_text_dir == TD_RTL); + int w = SETTING_BUTTON_WIDTH; + + int state = 0; + if (sel && click_result != 0) { + if (click_result == this->click_up) state = 1; + if (click_result == this->click_down) state = 2; + } + + Rect br = r.WithWidth(w, TEnd ^ rtl).CentreTo(w, SETTING_BUTTON_HEIGHT); + DrawUpDownButtons(br.left, br.top, this->button_colour, state, this->click_up != 0, this->click_down != 0); + + this->TBase::Draw(full, r.Indent(w + WidgetDimensions::scaled.hsep_wide, TEnd ^ rtl), sel, click_result, bg_colour); + } + +private: + int click_up; ///< Click result for up button. Button is inactive if 0. + int click_down; ///< Click result for down button. Button is inactive if 0. + Colours button_colour; ///< Colour of buttons. +}; + +using DropDownListToggleMoverItem = DropDownMover>>; + +enum BadgeClick : int { + BADGE_CLICK_NONE, + BADGE_CLICK_MOVE_UP, + BADGE_CLICK_MOVE_DOWN, + BADGE_CLICK_TOGGLE_ICON, +}; + +DropDownList BuildBadgeClassConfigurationList(const GUIBadgeClasses &gui_classes, uint columns, std::span column_separators) +{ + DropDownList list; + + list.push_back(MakeDropDownListStringItem(STR_BADGE_CONFIG_RESET, INT_MAX)); + if (gui_classes.GetClasses().empty()) return list; + list.push_back(MakeDropDownListDividerItem()); + + const BadgeClassID front = gui_classes.GetClasses().front().class_index; + const BadgeClassID back = gui_classes.GetClasses().back().class_index; + + for (uint i = 0; i < columns; ++i) { + for (const auto &gc : gui_classes.GetClasses()) { + if (gc.column_group != i) continue; + + bool first = (i == 0 && gc.class_index == front); + bool last = (i == columns - 1 && gc.class_index == back); + list.push_back(std::make_unique(first ? 0 : BADGE_CLICK_MOVE_UP, last ? 0 : BADGE_CLICK_MOVE_DOWN, COLOUR_YELLOW, gc.visible, BADGE_CLICK_TOGGLE_ICON, COLOUR_YELLOW, COLOUR_GREY, GetString(GetClassBadge(gc.class_index)->name), gc.class_index.base())); + } + + if (i >= column_separators.size()) continue; + + if (column_separators[i] == STR_NULL) { + list.push_back(MakeDropDownListDividerItem()); + } else { + list.push_back(MakeDropDownListStringItem(column_separators[i], INT_MIN + i, false, true)); + } + } + + return list; +} + +/** + * Toggle badge class visibility. + * @param feature Feature being used. + * @param class_badge Class badge. + * @param click Dropdown click reuslt. + */ +static void BadgeClassToggleVisibility(GrfSpecFeature feature, Badge &class_badge, int click_result) +{ + auto config = GetBadgeClassConfiguration(feature); + auto it = std::ranges::find(config, class_badge.label, &BadgeClassConfigItem::label); + if (it == std::end(config)) return; + + if (click_result == BADGE_CLICK_TOGGLE_ICON) it->show_icon = !it->show_icon; +} + +/** + * Move the badge class to the previous position. + * @param feature Feature being used. + * @param class_badge Class badge. + */ +static void BadgeClassMovePrevious(GrfSpecFeature feature, Badge &class_badge) +{ + GUIBadgeClasses gui_classes(feature); + if (gui_classes.GetClasses().empty()) return; + + auto config = GetBadgeClassConfiguration(feature); + auto it = std::ranges::find(config, class_badge.label, &BadgeClassConfigItem::label); + if (it == std::end(config)) return; + + auto pos_cur = std::ranges::find(gui_classes.GetClasses(), class_badge.class_index, &GUIBadgeClasses::Element::class_index); + if (pos_cur == std::begin(gui_classes.GetClasses())) { + if (it->column > 0) --it->column; + return; + } + + auto pos_prev = std::ranges::find(config, std::prev(pos_cur)->label, &BadgeClassConfigItem::label); + if (it->column > pos_prev->column) { + --it->column; + } else { + /* Rotate elements right so that it is placed before pos_prev, maintaining order of non-visible elements. */ + std::rotate(pos_prev, it, std::next(it)); + } +} + +/** + * Move the badge class to the next position. + * @param feature Feature being used. + * @param class_badge Class badge. + * @param columns Maximum column number permitted. + */ +static void BadgeClassMoveNext(GrfSpecFeature feature, Badge &class_badge, uint columns) +{ + GUIBadgeClasses gui_classes(feature); + if (gui_classes.GetClasses().empty()) return; + + auto config = GetBadgeClassConfiguration(feature); + auto it = std::ranges::find(config, class_badge.label, &BadgeClassConfigItem::label); + if (it == std::end(config)) return; + + auto pos_cur = std::ranges::find(gui_classes.GetClasses(), class_badge.class_index, &GUIBadgeClasses::Element::class_index); + if (std::next(pos_cur) == std::end(gui_classes.GetClasses())) { + if (it->column < static_cast(columns - 1)) ++it->column; + return; + } + + auto pos_next = std::ranges::find(config, std::next(pos_cur)->label, &BadgeClassConfigItem::label); + if (it->column < pos_next->column) { + ++it->column; + } else { + /* Rotate elements left so that it is placed after pos_next, maintaining order of non-visible elements. */ + std::rotate(it, std::next(it), std::next(pos_next)); + } +} + +/** + * Handle the badge configuration drop down selection. + * @param feature Feature being used. + * @param columns Maximum column number permitted. + * @param result Selected dropdown item value. + * @param click_result Dropdown click result. + * @return true iff the caller should reinitialise their widgets. + */ +bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result) +{ + if (result == INT_MAX) { + ResetBadgeClassConfiguration(feature); + return true; + } + + Badge *class_badge = GetClassBadge(static_cast(result)); + if (class_badge == nullptr) return false; + + switch (click_result) { + case BADGE_CLICK_MOVE_DOWN: // Move down button. + BadgeClassMoveNext(feature, *class_badge, columns); + break; + case BADGE_CLICK_MOVE_UP: // Move up button. + BadgeClassMovePrevious(feature, *class_badge); + break; + case BADGE_CLICK_TOGGLE_ICON: + BadgeClassToggleVisibility(feature, *class_badge, click_result); + break; + default: + break; + } + + return true; +} diff --git a/src/newgrf_badge_gui.h b/src/newgrf_badge_gui.h index 765fef751d..89b72656d6 100644 --- a/src/newgrf_badge_gui.h +++ b/src/newgrf_badge_gui.h @@ -52,4 +52,7 @@ void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classe std::unique_ptr MakeDropDownListBadgeItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, std::string &&str, int value, bool masked = false, bool shaded = false); std::unique_ptr MakeDropDownListBadgeIconItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked = false, bool shaded = false); +DropDownList BuildBadgeClassConfigurationList(const class GUIBadgeClasses &badge_class, uint columns, std::span column_separators); +bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result); + #endif /* NEWGRF_BADGE_GUI_H */ diff --git a/src/settings.cpp b/src/settings.cpp index 1522cac8eb..1be8716ef9 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -46,6 +46,7 @@ #include "game/game_config.hpp" #include "newgrf_config.h" #include "picker_func.h" +#include "newgrf_badge_config.h" #include "base_media_base.h" #include "base_media_graphics.h" #include "fios.h" @@ -1449,6 +1450,7 @@ void LoadFromConfig(bool startup) AILoadConfig(generic_ini, "ai_players"); GameLoadConfig(generic_ini, "game_scripts"); PickerLoadConfig(favs_ini); + BadgeClassLoadConfig(favs_ini); PrepareOldDiffCustom(); IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false); @@ -1522,6 +1524,7 @@ void SaveToConfig() AISaveConfig(generic_ini, "ai_players"); GameSaveConfig(generic_ini, "game_scripts"); PickerSaveConfig(favs_ini); + BadgeClassSaveConfig(favs_ini); SaveVersionInConfig(generic_ini); SaveVersionInConfig(private_ini);