mirror of https://github.com/OpenTTD/OpenTTD
Add: Configuration of NewGRF badges.
parent
daef052329
commit
c2d4098afa
|
@ -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
|
||||
|
|
|
@ -347,9 +347,10 @@ struct DropdownWindow : Window {
|
|||
}
|
||||
}
|
||||
|
||||
void ReplaceList(DropDownList &&list)
|
||||
void ReplaceList(DropDownList &&list, std::optional<int> 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<int> selected_result)
|
||||
{
|
||||
DropdownWindow *ddw = dynamic_cast<DropdownWindow *>(parent->FindChildWindow(WC_DROPDOWN_MENU));
|
||||
if (ddw != nullptr) ddw->ReplaceList(std::move(list));
|
||||
if (ddw != nullptr) ddw->ReplaceList(std::move(list), selected_result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<int> selected_result = std::nullopt);
|
||||
|
||||
#endif /* DROPDOWN_TYPE_H */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<const Badge> GetBadges()
|
|||
return _badges.specs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a read-only view of class badge index.
|
||||
* @return Span of badges.
|
||||
*/
|
||||
std::span<const BadgeID> GetClassBadges()
|
||||
{
|
||||
return _badges.classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a BadgeClassID to the given badge.
|
||||
* @param index Badge ID of badge that should be assigned.
|
||||
|
|
|
@ -55,6 +55,7 @@ std::span<const Badge> GetBadges();
|
|||
Badge *GetBadge(BadgeID index);
|
||||
Badge *GetBadgeByLabel(std::string_view label);
|
||||
Badge *GetClassBadge(BadgeClassID class_index);
|
||||
std::span<const BadgeID> GetClassBadges();
|
||||
|
||||
uint32_t GetBadgeVariableResult(const struct GRFFile &grffile, std::span<const BadgeID> badges, uint32_t parameter);
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<std::vector<BadgeClassConfigItem>, 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<std::string_view, GrfSpecFeature::GSF_END> 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<BadgeClassConfigItem> 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<const BadgeClassConfigItem &, int> 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<int>(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<int>(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);
|
||||
}
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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<BadgeClassConfigItem> GetBadgeClassConfiguration(GrfSpecFeature feature);
|
||||
void AddBadgeClassesToConfiguration();
|
||||
void ResetBadgeClassConfiguration(GrfSpecFeature feature);
|
||||
std::pair<const BadgeClassConfigItem &, int> GetBadgeClassConfigItem(GrfSpecFeature feature, std::string_view label);
|
||||
|
||||
#endif /* NEWGRF_BADGE_CONFIG_H */
|
|
@ -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<uint>(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<uint>(max_column, config.column);
|
||||
}
|
||||
|
||||
std::sort(std::begin(this->gui_classes), std::end(this->gui_classes));
|
||||
|
@ -246,3 +247,210 @@ std::unique_ptr<DropDownListItem> MakeDropDownListBadgeIconItem(const std::share
|
|||
{
|
||||
return std::make_unique<DropDownListBadgeIconItem>(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 TBase, bool TEnd = true, FontSize TFs = FS_NORMAL>
|
||||
class DropDownMover : public TBase {
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit DropDownMover(int click_up, int click_down, Colours button_colour, Args &&...args)
|
||||
: TBase(std::forward<Args>(args)...), click_up(click_up), click_down(click_down), button_colour(button_colour)
|
||||
{
|
||||
}
|
||||
|
||||
uint Height() const override
|
||||
{
|
||||
return std::max<uint>(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<DropDownToggle<DropDownString<DropDownListItem>>>;
|
||||
|
||||
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<const StringID> 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<DropDownListToggleMoverItem>(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<int>(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<BadgeClassID>(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;
|
||||
}
|
||||
|
|
|
@ -52,4 +52,7 @@ void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classe
|
|||
std::unique_ptr<DropDownListItem> MakeDropDownListBadgeItem(const std::shared_ptr<GUIBadgeClasses> &gui_classes, std::span<const BadgeID> badges, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, std::string &&str, int value, bool masked = false, bool shaded = false);
|
||||
std::unique_ptr<DropDownListItem> MakeDropDownListBadgeIconItem(const std::shared_ptr<GUIBadgeClasses> &gui_classes, std::span<const BadgeID> badges, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> 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<const StringID> column_separators);
|
||||
bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result);
|
||||
|
||||
#endif /* NEWGRF_BADGE_GUI_H */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue