mirror of
https://github.com/OpenTTD/OpenTTD
synced 2026-01-26 21:54:22 +01:00
Feature: User-defined collections of saved items in the picker window (#14813)
This commit is contained in:
@@ -2858,18 +2858,38 @@ STR_PICKER_PREVIEW_SHRINK_TOOLTIP :Reduce the heig
|
||||
STR_PICKER_PREVIEW_EXPAND :+
|
||||
STR_PICKER_PREVIEW_EXPAND_TOOLTIP :Increase the height of preview images. Ctrl+Click to increase to maximum
|
||||
|
||||
STR_PICKER_DEFAULT_COLLECTION :Default collection
|
||||
STR_PICKER_SELECT_COLLECTION_TOOLTIP :Select a collection
|
||||
STR_PICKER_COLLECTION_ADD :Add
|
||||
STR_PICKER_COLLECTION_ADD_TOOLTIP :Create a new collection
|
||||
STR_PICKER_COLLECTION_RENAME :Rename
|
||||
STR_PICKER_COLLECTION_RENAME_TOOLTIP :Rename a collection
|
||||
STR_PICKER_COLLECTION_DELETE :Delete
|
||||
STR_PICKER_COLLECTION_DELETE_TOOLTIP :Delete a collection
|
||||
|
||||
STR_PICKER_COLLECTION_RENAME_QUERY :Rename this collection
|
||||
STR_PICKER_COLLECTION_DELETE_QUERY :Delete collection
|
||||
STR_PICKER_COLLECTION_DELETE_QUERY_TEXT :{YELLOW}Are you sure you want to delete this collection?
|
||||
STR_PICKER_COLLECTION_DELETE_QUERY_DISABLED_TEXT :{YELLOW}Are you sure you want to delete this collection? There are items from disabled NewGRFs in it!
|
||||
|
||||
STR_PICKER_STATION_CLASS_TOOLTIP :Select a station class to display
|
||||
STR_PICKER_STATION_TYPE_TOOLTIP :Select a station type to build. Ctrl+Click to add or remove in saved items
|
||||
STR_PICKER_STATION_COLLECTION_TOOLTIP :Select a collection of stations to display
|
||||
STR_PICKER_WAYPOINT_CLASS_TOOLTIP :Select a waypoint class to display
|
||||
STR_PICKER_WAYPOINT_TYPE_TOOLTIP :Select a waypoint to build. Ctrl+Click to add or remove in saved items
|
||||
STR_PICKER_WAYPOINT_COLLECTION_TOOLTIP :Select a collection of waypoints to display
|
||||
STR_PICKER_ROADSTOP_BUS_CLASS_TOOLTIP :Select a bus station class to display
|
||||
STR_PICKER_ROADSTOP_BUS_TYPE_TOOLTIP :Select a bus station type to build. Ctrl+Click to add or remove in saved items
|
||||
STR_PICKER_ROADSTOP_BUS_COLLECTION_TOOLTIP :Select a collection of bus stations to display
|
||||
STR_PICKER_ROADSTOP_TRUCK_CLASS_TOOLTIP :Select a lorry station class to display
|
||||
STR_PICKER_ROADSTOP_TRUCK_TYPE_TOOLTIP :Select a lorry station type to build. Ctrl+Click to add or remove in saved items
|
||||
STR_PICKER_ROADSTOP_TRUCK_COLLECTION_TOOLTIP :Select a collection of lorry stations to display
|
||||
STR_PICKER_OBJECT_CLASS_TOOLTIP :Select an object class to display
|
||||
STR_PICKER_OBJECT_TYPE_TOOLTIP :Select an object type to build. Ctrl+Click to add or remove in saved items. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
||||
STR_PICKER_OBJECT_COLLECTION_TOOLTIP :Select a collection of objects to display
|
||||
STR_PICKER_HOUSE_CLASS_TOOLTIP :Select a town zone to display
|
||||
STR_PICKER_HOUSE_TYPE_TOOLTIP :Select a house type to build. Ctrl+Click to add or remove in saved items
|
||||
STR_PICKER_HOUSE_COLLECTION_TOOLTIP :Select a collection of houses to display
|
||||
|
||||
STR_HOUSE_PICKER_CAPTION :House Selection
|
||||
STR_HOUSE_PICKER_NAME :{BLACK}Name: {GOLD}{STRING}
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
|
||||
StringID GetClassTooltip() const override { return STR_PICKER_OBJECT_CLASS_TOOLTIP; }
|
||||
StringID GetTypeTooltip() const override { return STR_PICKER_OBJECT_TYPE_TOOLTIP; }
|
||||
StringID GetCollectionTooltip() const override { return STR_PICKER_OBJECT_COLLECTION_TOOLTIP; }
|
||||
|
||||
bool IsActive() const override
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "core/backup_type.hpp"
|
||||
#include "company_func.h"
|
||||
#include "dropdown_func.h"
|
||||
#include "gui.h"
|
||||
#include "hotkeys.h"
|
||||
#include "ini_type.h"
|
||||
@@ -64,29 +65,39 @@ PickerCallbacks::~PickerCallbacks()
|
||||
*/
|
||||
static void PickerLoadConfig(const IniFile &ini, PickerCallbacks &callbacks)
|
||||
{
|
||||
const IniGroup *group = ini.GetGroup(callbacks.ini_group);
|
||||
if (group == nullptr) return;
|
||||
|
||||
callbacks.saved.clear();
|
||||
for (const IniItem &item : group->items) {
|
||||
std::array<uint8_t, 4> grfid_buf;
|
||||
for (const IniGroup &group : ini.groups) {
|
||||
/* Read the collection name */
|
||||
if (!group.name.starts_with(callbacks.ini_group)) continue;
|
||||
auto pos = group.name.find('-');
|
||||
if (pos == std::string_view::npos && group.name != callbacks.ini_group) continue;
|
||||
std::string collection = (pos == std::string_view::npos) ? "" : group.name.substr(pos + 1);
|
||||
|
||||
std::string_view str = item.name;
|
||||
if (group.items.empty() && pos != std::string_view::npos) {
|
||||
callbacks.saved[collection];
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try reading "<grfid>|<localid>" */
|
||||
auto grfid_pos = str.find('|');
|
||||
if (grfid_pos == std::string_view::npos) continue;
|
||||
for (const IniItem &item : group.items) {
|
||||
std::array<uint8_t, 4> grfid_buf;
|
||||
|
||||
std::string_view grfid_str = str.substr(0, grfid_pos);
|
||||
if (!ConvertHexToBytes(grfid_str, grfid_buf)) continue;
|
||||
std::string_view str = item.name;
|
||||
|
||||
str = str.substr(grfid_pos + 1);
|
||||
uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
|
||||
uint16_t localid;
|
||||
auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), localid);
|
||||
/* Try reading "<grfid>|<localid>" */
|
||||
auto grfid_pos = str.find('|');
|
||||
if (grfid_pos == std::string_view::npos) continue;
|
||||
|
||||
if (err == std::errc{} && ptr == str.data() + str.size()) {
|
||||
callbacks.saved.insert({grfid, localid, 0, 0});
|
||||
std::string_view grfid_str = str.substr(0, grfid_pos);
|
||||
if (!ConvertHexToBytes(grfid_str, grfid_buf)) continue;
|
||||
|
||||
str = str.substr(grfid_pos + 1);
|
||||
uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
|
||||
uint16_t localid;
|
||||
auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), localid);
|
||||
|
||||
if (err == std::errc{} && ptr == str.data() + str.size()) {
|
||||
callbacks.saved[collection].emplace(grfid, localid, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,12 +109,18 @@ static void PickerLoadConfig(const IniFile &ini, PickerCallbacks &callbacks)
|
||||
*/
|
||||
static void PickerSaveConfig(IniFile &ini, const PickerCallbacks &callbacks)
|
||||
{
|
||||
IniGroup &group = ini.GetOrCreateGroup(callbacks.ini_group);
|
||||
group.Clear();
|
||||
/* Clean the ini file of any obsolete collections to prevent them coming back after a restart */
|
||||
for (const std::string &rm_collection : callbacks.rm_collections) {
|
||||
ini.RemoveGroup(callbacks.ini_group + "-" + rm_collection);
|
||||
}
|
||||
|
||||
for (const PickerItem &item : callbacks.saved) {
|
||||
std::string key = fmt::format("{:08X}|{}", std::byteswap(item.grfid), item.local_id);
|
||||
group.CreateItem(key);
|
||||
for (const auto &collection : callbacks.saved) {
|
||||
IniGroup &group = ini.GetOrCreateGroup(collection.first == "" ? callbacks.ini_group : callbacks.ini_group + "-" + collection.first);
|
||||
group.Clear();
|
||||
for (const PickerItem &item : collection.second) {
|
||||
std::string key = fmt::format("{:08X}|{}", std::byteswap(item.grfid), item.local_id);
|
||||
group.CreateItem(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,10 +176,28 @@ static bool TypeTagNameFilter(PickerItem const *item, PickerFilterData &filter)
|
||||
return filter.GetState();
|
||||
}
|
||||
|
||||
/** Allow the collection sorter to test if the collection has inactive items */
|
||||
PickerWindow *picker_window;
|
||||
|
||||
/**
|
||||
* Sort collections by id.
|
||||
* @param a First string for sorting.
|
||||
* @param b Second string for sorting.
|
||||
* @return Sort order.
|
||||
*/
|
||||
static bool CollectionIDSorter(std::string const &a, std::string const &b)
|
||||
{
|
||||
if (a == GetString(STR_PICKER_DEFAULT_COLLECTION) || b == GetString(STR_PICKER_DEFAULT_COLLECTION)) return a == GetString(STR_PICKER_DEFAULT_COLLECTION);
|
||||
if (picker_window->inactive.contains(a) == picker_window->inactive.contains(b)) return StrNaturalCompare(a, b) < 0;
|
||||
return picker_window->inactive.contains(a) < picker_window->inactive.contains(b);
|
||||
}
|
||||
|
||||
static const std::initializer_list<PickerClassList::SortFunction * const> _class_sorter_funcs = { &ClassIDSorter }; ///< Sort functions of the #PickerClassList
|
||||
static const std::initializer_list<PickerClassList::FilterFunction * const> _class_filter_funcs = { &ClassTagNameFilter }; ///< Filter functions of the #PickerClassList.
|
||||
static const std::initializer_list<PickerTypeList::SortFunction * const> _type_sorter_funcs = { TypeIDSorter }; ///< Sort functions of the #PickerTypeList.
|
||||
static const std::initializer_list<PickerTypeList::FilterFunction * const> _type_filter_funcs = { TypeTagNameFilter }; ///< Filter functions of the #PickerTypeList.
|
||||
static const std::initializer_list<PickerCollectionList::SortFunction * const> _collection_sorter_funcs = { &CollectionIDSorter }; ///< Sort functions of the #PickerCollectionList.
|
||||
|
||||
|
||||
PickerWindow::PickerWindow(WindowDesc &desc, Window *parent, int window_number, PickerCallbacks &callbacks) : PickerWindowBase(desc, parent), callbacks(callbacks),
|
||||
class_editbox(EDITBOX_MAX_SIZE * MAX_CHAR_LENGTH, EDITBOX_MAX_SIZE),
|
||||
@@ -182,10 +217,12 @@ void PickerWindow::ConstructWindow()
|
||||
bool is_active = this->callbacks.IsActive();
|
||||
|
||||
this->preview_height = std::max(this->callbacks.preview_height, PREVIEW_HEIGHT);
|
||||
picker_window = this;
|
||||
|
||||
/* Functionality depends on widgets being present, not window class. */
|
||||
this->has_class_picker = is_active && this->GetWidget<NWidgetBase>(WID_PW_CLASS_LIST) != nullptr && this->callbacks.HasClassChoice();
|
||||
this->has_type_picker = is_active && this->GetWidget<NWidgetBase>(WID_PW_TYPE_MATRIX) != nullptr;
|
||||
this->has_collection_picker = is_active && this->GetWidget<NWidgetBase>(WID_PW_COLEC_LIST) != nullptr;
|
||||
|
||||
if (this->has_class_picker) {
|
||||
this->GetWidget<NWidgetCore>(WID_PW_CLASS_LIST)->SetToolTip(this->callbacks.GetClassTooltip());
|
||||
@@ -209,7 +246,10 @@ void PickerWindow::ConstructWindow()
|
||||
this->classes.SetFilterFuncs(_class_filter_funcs);
|
||||
|
||||
/* Update saved type information. */
|
||||
if (this->callbacks.sel_collection == "") SetWidgetsDisabledState(true, WID_PW_COLEC_RENAME, WID_PW_COLEC_DELETE);
|
||||
this->callbacks.saved = this->callbacks.UpdateSavedItems(this->callbacks.saved);
|
||||
this->inactive = this->callbacks.InitializeInactiveCollections(this->callbacks.saved);
|
||||
this->collections.ForceRebuild();
|
||||
|
||||
/* Clear used type information. */
|
||||
this->callbacks.used.clear();
|
||||
@@ -243,6 +283,13 @@ void PickerWindow::ConstructWindow()
|
||||
this->types.SetSortFuncs(_type_sorter_funcs);
|
||||
this->types.SetFilterFuncs(_type_filter_funcs);
|
||||
|
||||
if (this->has_collection_picker) {
|
||||
this->GetWidget<NWidgetCore>(WID_PW_COLEC_LIST)->SetToolTip(this->callbacks.GetCollectionTooltip());
|
||||
}
|
||||
|
||||
this->collections.SetListing(this->callbacks.collection_last_sorting);
|
||||
this->collections.SetSortFuncs(_collection_sorter_funcs);
|
||||
|
||||
this->FinishInitNested(this->window_number);
|
||||
|
||||
this->InvalidateData(PICKER_INVALIDATION_ALL);
|
||||
@@ -298,13 +345,30 @@ void PickerWindow::UpdateWidgetSize(WidgetID widget, Dimension &size, const Dime
|
||||
|
||||
std::string PickerWindow::GetWidgetString(WidgetID widget, StringID stringid) const
|
||||
{
|
||||
if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
|
||||
return this->GetWidget<NWidgetBadgeFilter>(widget)->GetStringParameter(this->badge_filter_choices);
|
||||
}
|
||||
switch (widget) {
|
||||
case WID_PW_COLEC_LIST:
|
||||
return this->callbacks.sel_collection == "" ? GetString(STR_PICKER_DEFAULT_COLLECTION) : this->callbacks.sel_collection;
|
||||
|
||||
default:
|
||||
if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
|
||||
return this->GetWidget<NWidgetBadgeFilter>(widget)->GetStringParameter(this->badge_filter_choices);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return this->Window::GetWidgetString(widget, stringid);
|
||||
}
|
||||
|
||||
DropDownList PickerWindow::BuildCollectionDropDownList()
|
||||
{
|
||||
DropDownList list;
|
||||
int i = 0;
|
||||
for (const auto &collection : collections) {
|
||||
list.push_back(MakeDropDownListStringItem(GetString(collection == "" ? STR_PICKER_DEFAULT_COLLECTION : STR_JUST_RAW_STRING, collection), i, false, this->inactive.contains(collection)));
|
||||
i++;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void PickerWindow::DrawWidget(const Rect &r, WidgetID widget) const
|
||||
{
|
||||
switch (widget) {
|
||||
@@ -343,8 +407,10 @@ void PickerWindow::DrawWidget(const Rect &r, WidgetID widget) const
|
||||
PaletteID palette = _game_mode != GM_NORMAL || feature == GSF_HOUSES ? PAL_NONE : GetCompanyPalette(_local_company);
|
||||
DrawBadgeColumn({0, by, ir.Width() - 1, ir.Height() - 1}, 0, this->badge_classes, this->callbacks.GetTypeBadges(item.class_index, item.index), feature, std::nullopt, palette);
|
||||
|
||||
if (this->callbacks.saved.contains(item)) {
|
||||
DrawSprite(SPR_BLOT, PALETTE_TO_YELLOW, 0, 0);
|
||||
if (this->callbacks.saved.contains(this->callbacks.sel_collection)) {
|
||||
if (this->callbacks.saved.at(this->callbacks.sel_collection).contains(item)) {
|
||||
DrawSprite(SPR_BLOT, PALETTE_TO_YELLOW, 0, 0);
|
||||
}
|
||||
}
|
||||
if (this->callbacks.used.contains(item)) {
|
||||
DrawSprite(SPR_BLOT, PALETTE_TO_GREEN, ir.Width() - GetSpriteSize(SPR_BLOT).width, 0);
|
||||
@@ -372,6 +438,21 @@ void PickerWindow::OnResize()
|
||||
}
|
||||
}
|
||||
|
||||
void PickerWindow::DeletePickerCollectionCallback(Window *win, bool confirmed)
|
||||
{
|
||||
if (confirmed) {
|
||||
PickerWindow *w = (PickerWindow*)win;
|
||||
w->callbacks.saved.erase(w->callbacks.saved.find(w->callbacks.edit_collection));
|
||||
w->inactive.erase(w->callbacks.edit_collection);
|
||||
w->callbacks.rm_collections.emplace(w->callbacks.edit_collection);
|
||||
w->callbacks.sel_collection = "";
|
||||
w->callbacks.edit_collection.clear();
|
||||
picker_window = w;
|
||||
w->SetWidgetsDisabledState(true, WID_PW_COLEC_RENAME, WID_PW_COLEC_DELETE);
|
||||
w->InvalidateData({PickerInvalidation::Collection, PickerInvalidation::Position});
|
||||
}
|
||||
}
|
||||
|
||||
void PickerWindow::OnClick(Point pt, WidgetID widget, int)
|
||||
{
|
||||
switch (widget) {
|
||||
@@ -422,13 +503,20 @@ void PickerWindow::OnClick(Point pt, WidgetID widget, int)
|
||||
const auto &item = this->types[sel];
|
||||
|
||||
if (_ctrl_pressed) {
|
||||
auto it = this->callbacks.saved.find(item);
|
||||
if (it == std::end(this->callbacks.saved)) {
|
||||
this->callbacks.saved.insert(item);
|
||||
} else {
|
||||
this->callbacks.saved.erase(it);
|
||||
if (this->callbacks.saved.find(this->callbacks.sel_collection) == this->callbacks.saved.end()) {
|
||||
this->callbacks.saved[""].emplace(item);
|
||||
this->InvalidateData({PickerInvalidation::Collection, PickerInvalidation::Class});
|
||||
this->SetDirty();
|
||||
break;
|
||||
}
|
||||
this->InvalidateData(PickerInvalidation::Type);
|
||||
|
||||
auto it = this->callbacks.saved.at(this->callbacks.sel_collection).find(item);
|
||||
if (it == std::end(this->callbacks.saved.at(this->callbacks.sel_collection))) {
|
||||
this->callbacks.saved.at(this->callbacks.sel_collection).emplace(item);
|
||||
} else {
|
||||
this->callbacks.saved.at(this->callbacks.sel_collection).erase(it);
|
||||
}
|
||||
this->InvalidateData({PickerInvalidation::Type, PickerInvalidation::Class});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -442,6 +530,37 @@ void PickerWindow::OnClick(Point pt, WidgetID widget, int)
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_PW_COLEC_LIST: {
|
||||
ShowDropDownList(this, this->BuildCollectionDropDownList(), -1, widget, 0);
|
||||
CloseWindowById(WC_SELECT_STATION, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_PW_COLEC_ADD:
|
||||
this->callbacks.rename_collection = false;
|
||||
ShowQueryString({}, STR_PICKER_COLLECTION_ADD_TOOLTIP, MAX_LENGTH_GROUP_NAME_CHARS, this, CS_ALPHANUMERAL, QueryStringFlag::LengthIsInChars);
|
||||
break;
|
||||
|
||||
case WID_PW_COLEC_RENAME:
|
||||
if (this->callbacks.saved.contains(this->callbacks.sel_collection)) {
|
||||
CloseChildWindows(WC_CONFIRM_POPUP_QUERY);
|
||||
this->callbacks.edit_collection = this->callbacks.sel_collection;
|
||||
this->callbacks.rename_collection = true;
|
||||
ShowQueryString(this->callbacks.sel_collection, STR_PICKER_COLLECTION_RENAME_QUERY, MAX_LENGTH_GROUP_NAME_CHARS, this, CS_ALPHANUMERAL, QueryStringFlag::LengthIsInChars);
|
||||
}
|
||||
break;
|
||||
|
||||
case WID_PW_COLEC_DELETE:
|
||||
if (this->callbacks.saved.contains(this->callbacks.sel_collection)) {
|
||||
CloseChildWindows(WC_QUERY_STRING);
|
||||
this->callbacks.edit_collection = this->callbacks.sel_collection;
|
||||
|
||||
this->inactive.contains(this->callbacks.sel_collection) ?
|
||||
ShowQuery(GetEncodedString(STR_PICKER_COLLECTION_DELETE_QUERY), GetEncodedString(STR_PICKER_COLLECTION_DELETE_QUERY_DISABLED_TEXT), this, DeletePickerCollectionCallback) :
|
||||
ShowQuery(GetEncodedString(STR_PICKER_COLLECTION_DELETE_QUERY), GetEncodedString(STR_PICKER_COLLECTION_DELETE_QUERY_TEXT), this, DeletePickerCollectionCallback);
|
||||
}
|
||||
break;
|
||||
|
||||
case WID_PW_CONFIGURE_BADGES:
|
||||
if (this->badge_classes.GetClasses().empty()) break;
|
||||
ShowDropDownList(this, BuildBadgeClassConfigurationList(this->badge_classes, 1, {}, COLOUR_DARK_GREEN), -1, widget, 0, DropDownOption::Persist);
|
||||
@@ -457,9 +576,54 @@ void PickerWindow::OnClick(Point pt, WidgetID widget, int)
|
||||
}
|
||||
}
|
||||
|
||||
void PickerWindow::OnQueryTextFinished(std::optional<std::string> str)
|
||||
{
|
||||
if (!str.has_value()) return;
|
||||
|
||||
if (!this->callbacks.saved.contains(*str)) {
|
||||
if (this->callbacks.saved.contains(this->callbacks.edit_collection) && this->callbacks.rename_collection) {
|
||||
auto rename_collection = this->callbacks.saved.extract(this->callbacks.edit_collection);
|
||||
rename_collection.key() = *str;
|
||||
this->callbacks.saved.insert(std::move(rename_collection));
|
||||
|
||||
if (this->inactive.contains(this->callbacks.edit_collection)) {
|
||||
this->inactive.erase(this->callbacks.edit_collection);
|
||||
this->inactive.emplace(*str);
|
||||
}
|
||||
|
||||
this->callbacks.rm_collections.emplace(this->callbacks.edit_collection);
|
||||
this->callbacks.edit_collection.clear();
|
||||
|
||||
} else {
|
||||
this->callbacks.saved.insert({*str, {}});
|
||||
}
|
||||
}
|
||||
|
||||
this->callbacks.sel_collection = *str;
|
||||
picker_window = this;
|
||||
SetWidgetsDisabledState(this->callbacks.sel_collection == "" ? true : false, WID_PW_COLEC_RENAME, WID_PW_COLEC_DELETE);
|
||||
if (!IsWidgetLowered(WID_PW_MODE_SAVED)) {
|
||||
this->InvalidateData({PickerInvalidation::Type, PickerInvalidation::Class});
|
||||
}
|
||||
this->InvalidateData({PickerInvalidation::Collection, PickerInvalidation::Position});
|
||||
}
|
||||
|
||||
void PickerWindow::OnDropdownSelect(WidgetID widget, int index, int click_result)
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_PW_COLEC_LIST: {
|
||||
auto it = this->collections.begin() + index;
|
||||
if (this->callbacks.sel_collection != *it) {
|
||||
this->callbacks.sel_collection = *it;
|
||||
if (this->IsWidgetLowered(WID_PW_MODE_SAVED)) this->InvalidateData({PickerInvalidation::Class, PickerInvalidation::Type, PickerInvalidation::Validate});
|
||||
this->InvalidateData(PickerInvalidation::Position);
|
||||
}
|
||||
SetWidgetsDisabledState(this->callbacks.sel_collection == "" ? true : false, WID_PW_COLEC_RENAME, WID_PW_COLEC_DELETE);
|
||||
|
||||
SndClickBeep();
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_PW_CONFIGURE_BADGES: {
|
||||
bool reopen = HandleBadgeConfigurationDropDownClick(this->callbacks.GetFeature(), 1, index, click_result, this->badge_filter_choices);
|
||||
|
||||
@@ -506,6 +670,7 @@ void PickerWindow::OnInvalidateData(int data, bool gui_scope)
|
||||
|
||||
if (pi.Test(PickerInvalidation::Class)) this->classes.ForceRebuild();
|
||||
if (pi.Test(PickerInvalidation::Type)) this->types.ForceRebuild();
|
||||
if (pi.Test(PickerInvalidation::Collection)) this->collections.ForceRebuild();
|
||||
|
||||
this->BuildPickerClassList();
|
||||
if (pi.Test(PickerInvalidation::Validate)) this->EnsureSelectedClassIsValid();
|
||||
@@ -515,6 +680,8 @@ void PickerWindow::OnInvalidateData(int data, bool gui_scope)
|
||||
if (pi.Test(PickerInvalidation::Validate)) this->EnsureSelectedTypeIsValid();
|
||||
if (pi.Test(PickerInvalidation::Position)) this->EnsureSelectedTypeIsVisible();
|
||||
|
||||
this->BuildPickerCollectionList();
|
||||
|
||||
if (this->has_type_picker) {
|
||||
SetWidgetLoweredState(WID_PW_MODE_ALL, HasBit(this->callbacks.mode, PFM_ALL));
|
||||
SetWidgetLoweredState(WID_PW_MODE_USED, HasBit(this->callbacks.mode, PFM_USED));
|
||||
@@ -582,7 +749,8 @@ void PickerWindow::BuildPickerClassList()
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (this->callbacks.GetClassName(i) == INVALID_STRING_ID) continue;
|
||||
if (filter_used && std::none_of(std::begin(this->callbacks.used), std::end(this->callbacks.used), [i](const PickerItem &item) { return item.class_index == i; })) continue;
|
||||
if (filter_saved && std::none_of(std::begin(this->callbacks.saved), std::end(this->callbacks.saved), [i](const PickerItem &item) { return item.class_index == i; })) continue;
|
||||
if (filter_saved && this->callbacks.saved.find(this->callbacks.sel_collection) == this->callbacks.saved.end()) continue;
|
||||
if (filter_saved && std::none_of(std::begin(this->callbacks.saved.at(this->callbacks.sel_collection)), std::end(this->callbacks.saved.at(this->callbacks.sel_collection)), [i](const PickerItem &item) { return item.class_index == i; })) continue;
|
||||
this->classes.emplace_back(i);
|
||||
}
|
||||
|
||||
@@ -656,10 +824,10 @@ void PickerWindow::BuildPickerTypeList()
|
||||
if (this->callbacks.GetTypeName(item.class_index, item.index) == INVALID_STRING_ID) continue;
|
||||
this->types.emplace_back(item);
|
||||
}
|
||||
} else if (filter_saved) {
|
||||
} else if (filter_saved && this->callbacks.saved.contains(this->callbacks.sel_collection)) {
|
||||
/* Showing only saved items. */
|
||||
this->types.reserve(this->callbacks.saved.size());
|
||||
for (const PickerItem &item : this->callbacks.saved) {
|
||||
this->types.reserve(std::size(this->callbacks.saved.at(this->callbacks.sel_collection)));
|
||||
for (const PickerItem &item : this->callbacks.saved.at(this->callbacks.sel_collection)) {
|
||||
/* The used list may contain items that aren't currently loaded, skip these. */
|
||||
if (item.class_index == -1) continue;
|
||||
if (!show_all && item.class_index != cls_id) continue;
|
||||
@@ -741,6 +909,30 @@ void PickerWindow::EnsureSelectedTypeIsVisible()
|
||||
this->GetWidget<NWidgetMatrix>(WID_PW_TYPE_MATRIX)->SetClicked(pos);
|
||||
}
|
||||
|
||||
/** Builds the filter list of collections. */
|
||||
void PickerWindow::BuildPickerCollectionList()
|
||||
{
|
||||
if (!this->collections.NeedRebuild()) return;
|
||||
|
||||
int count = std::max(static_cast<int>(this->callbacks.saved.size()), 1);
|
||||
|
||||
this->collections.clear();
|
||||
this->collections.reserve(count);
|
||||
|
||||
if (this->callbacks.saved.find("") == this->callbacks.saved.end()) {
|
||||
this->collections.emplace_back("");
|
||||
}
|
||||
|
||||
for (auto it = this->callbacks.saved.begin(); it != this->callbacks.saved.end(); it++) {
|
||||
this->collections.emplace_back(it->first);
|
||||
}
|
||||
|
||||
this->collections.RebuildDone();
|
||||
this->collections.Sort();
|
||||
|
||||
if (!this->has_class_picker) return;
|
||||
}
|
||||
|
||||
/** Create nested widgets for the class picker widgets. */
|
||||
std::unique_ptr<NWidgetBase> MakePickerClassWidgets()
|
||||
{
|
||||
@@ -750,12 +942,24 @@ std::unique_ptr<NWidgetBase> MakePickerClassWidgets()
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_EDITBOX, COLOUR_DARK_GREEN, WID_PW_CLASS_FILTER), SetMinimalSize(144, 0), SetPadding(2), SetFill(1, 0), SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_PW_CLASS_LIST), SetFill(1, 1), SetResize(1, 1), SetPadding(WidgetDimensions::unscaled.picker),
|
||||
SetMatrixDataTip(1, 0), SetScrollbar(WID_PW_CLASS_SCROLL),
|
||||
/* Collection view */
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_GREEN, WID_PW_COLEC_ADD), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_PICKER_COLLECTION_ADD, STR_PICKER_COLLECTION_ADD_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_GREEN, WID_PW_COLEC_RENAME), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_PICKER_COLLECTION_RENAME, STR_PICKER_COLLECTION_RENAME_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_GREEN, WID_PW_COLEC_DELETE), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_PICKER_COLLECTION_DELETE, STR_PICKER_COLLECTION_DELETE_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_DARK_GREEN, WID_PW_COLEC_LIST), SetMinimalSize(144, 12), SetFill(0, 1), SetResize(1, 0), SetToolTip(STR_PICKER_SELECT_COLLECTION_TOOLTIP),
|
||||
EndContainer(),
|
||||
/* Class view */
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_PW_CLASS_LIST), SetFill(1, 1), SetResize(1, 1), SetPadding(WidgetDimensions::unscaled.picker),
|
||||
SetMatrixDataTip(1, 0), SetScrollbar(WID_PW_CLASS_SCROLL),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_PW_CLASS_SCROLL),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_PW_CLASS_SCROLL),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
|
||||
@@ -66,7 +66,6 @@ public:
|
||||
virtual StringID GetTypeTooltip() const = 0;
|
||||
/** Get the number of types in a class. @note Used only to estimate space requirements. */
|
||||
virtual int GetTypeCount(int cls_id) const = 0;
|
||||
|
||||
/** Get the selected type. */
|
||||
virtual int GetSelectedType() const = 0;
|
||||
/** Set the selected type. */
|
||||
@@ -82,10 +81,38 @@ public:
|
||||
/** Draw preview image of an item. */
|
||||
virtual void DrawType(int x, int y, int cls_id, int id) const = 0;
|
||||
|
||||
/* Collection Callbacks */
|
||||
/** Get the tooltip string for the collection list. */
|
||||
virtual StringID GetCollectionTooltip() const = 0;
|
||||
|
||||
/** Fill a set with all items that are used by the current player. */
|
||||
virtual void FillUsedItems(std::set<PickerItem> &items) = 0;
|
||||
/** Update link between grfid/localidx and class_index/index in saved items. */
|
||||
virtual std::set<PickerItem> UpdateSavedItems(const std::set<PickerItem> &src) = 0;
|
||||
virtual std::map<std::string, std::set<PickerItem>> UpdateSavedItems(const std::map<std::string, std::set<PickerItem>> &src) = 0;
|
||||
/**
|
||||
* Initialize the list of active collections for sorting purposes.
|
||||
* @param collections The map of collections to check.
|
||||
* @return The set of collections with inactive items.
|
||||
*/
|
||||
inline std::set<std::string> InitializeInactiveCollections(const std::map<std::string, std::set<PickerItem>> collections)
|
||||
{
|
||||
std::set<std::string> inactive;
|
||||
|
||||
for (const auto &collection : collections) {
|
||||
if ((collection.second.size() == 1 && collection.second.contains({})) || collection.first == "") continue;
|
||||
for (const PickerItem &item : collection.second) {
|
||||
if (item.class_index == -1 || item.index == -1) {
|
||||
inactive.emplace(collection.first);
|
||||
break;
|
||||
}
|
||||
if (GetTypeName(item.class_index, item.index) == INVALID_STRING_ID) {
|
||||
inactive.emplace(collection.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return inactive;
|
||||
}
|
||||
|
||||
Listing class_last_sorting = { false, 0 }; ///< Default sorting of #PickerClassList.
|
||||
Filtering class_last_filtering = { false, 0 }; ///< Default filtering of #PickerClassList.
|
||||
@@ -93,13 +120,19 @@ public:
|
||||
Listing type_last_sorting = { false, 0 }; ///< Default sorting of #PickerTypeList.
|
||||
Filtering type_last_filtering = { false, 0 }; ///< Default filtering of #PickerTypeList.
|
||||
|
||||
Listing collection_last_sorting = { false, 0 }; ///< Default sorting of #PickerCollectionList.
|
||||
|
||||
const std::string ini_group; ///< Ini Group for saving favourites.
|
||||
uint8_t mode = 0; ///< Bitmask of \c PickerFilterModes.
|
||||
bool rename_collection = false; ///< Are we renaming a collection?
|
||||
std::string sel_collection; ///< Currently selected collection of saved items.
|
||||
std::string edit_collection; ///< Collection to rename or delete.
|
||||
std::set<std::string> rm_collections; ///< Set of removed or renamed collections for updating ini file.
|
||||
|
||||
int preview_height = 0; ///< Previously adjusted height.
|
||||
|
||||
std::set<PickerItem> used; ///< Set of items used in the current game by the current company.
|
||||
std::set<PickerItem> saved; ///< Set of saved favourite items.
|
||||
std::map<std::string, std::set<PickerItem>> saved; ///< Set of saved collections of items.
|
||||
};
|
||||
|
||||
/** Helper for PickerCallbacks when the class system is based on NewGRFClass. */
|
||||
@@ -128,17 +161,24 @@ public:
|
||||
return GetPickerItem(GetClass(cls_id)->GetSpec(id), cls_id, id);
|
||||
}
|
||||
|
||||
std::set<PickerItem> UpdateSavedItems(const std::set<PickerItem> &src) override
|
||||
std::map<std::string, std::set<PickerItem>> UpdateSavedItems(const std::map<std::string, std::set<PickerItem>> &src) override
|
||||
{
|
||||
if (src.empty()) return {};
|
||||
|
||||
std::set<PickerItem> dst;
|
||||
for (const auto &item : src) {
|
||||
const auto *spec = T::GetByGrf(item.grfid, item.local_id);
|
||||
if (spec == nullptr) {
|
||||
dst.emplace(item.grfid, item.local_id, -1, -1);
|
||||
} else {
|
||||
dst.emplace(GetPickerItem(spec));
|
||||
std::map<std::string, std::set<PickerItem>> dst;
|
||||
for (auto it = src.begin(); it != src.end(); it++) {
|
||||
if (it->second.empty() || (it->second.size() == 1 && it->second.contains({}))) {
|
||||
dst[it->first];
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &item : it->second) {
|
||||
const auto *spec = T::GetByGrf(item.grfid, item.local_id);
|
||||
if (spec == nullptr) {
|
||||
dst[it->first].emplace(item.grfid, item.local_id, -1, -1);
|
||||
} else {
|
||||
dst[it->first].emplace(GetPickerItem(spec));
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
@@ -153,6 +193,7 @@ struct PickerFilterData : StringFilter {
|
||||
|
||||
using PickerClassList = GUIList<int, std::nullptr_t, PickerFilterData &>; ///< GUIList holding classes to display.
|
||||
using PickerTypeList = GUIList<PickerItem, std::nullptr_t, PickerFilterData &>; ///< GUIList holding classes/types to display.
|
||||
using PickerCollectionList = GUIList<std::string, std::nullptr_t, PickerFilterData &>; ///< GUIList holding collections to display.
|
||||
|
||||
class PickerWindow : public PickerWindowBase {
|
||||
public:
|
||||
@@ -166,6 +207,7 @@ public:
|
||||
enum class PickerInvalidation : uint8_t {
|
||||
Class, ///< Refresh the class list.
|
||||
Type, ///< Refresh the type list.
|
||||
Collection, ///< Refresh the collection list.
|
||||
Position, ///< Update scroll positions.
|
||||
Validate, ///< Validate selected item.
|
||||
Filter, ///< Update filter state.
|
||||
@@ -186,17 +228,22 @@ public:
|
||||
|
||||
bool has_class_picker = false; ///< Set if this window has a class picker 'component'.
|
||||
bool has_type_picker = false; ///< Set if this window has a type picker 'component'.
|
||||
bool has_collection_picker = false; ///< Set if this window has a collection picker 'component'.
|
||||
int preview_height = 0; ///< Height of preview images.
|
||||
std::set<std::string> inactive; ///< Set of collections with inactive items.
|
||||
|
||||
PickerWindow(WindowDesc &desc, Window *parent, int window_number, PickerCallbacks &callbacks);
|
||||
void OnInit() override;
|
||||
void Close(int data = 0) override;
|
||||
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override;
|
||||
std::string GetWidgetString(WidgetID widget, StringID stringid) const override;
|
||||
DropDownList BuildCollectionDropDownList();
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override;
|
||||
void OnDropdownSelect(WidgetID widget, int index, int click_result) override;
|
||||
void OnResize() override;
|
||||
void static DeletePickerCollectionCallback(Window *win, bool confirmed);
|
||||
void OnClick(Point pt, WidgetID widget, int click_count) override;
|
||||
void OnQueryTextFinished(std::optional<std::string> str) override;
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override;
|
||||
EventState OnHotkey(int hotkey) override;
|
||||
void OnEditboxChanged(WidgetID wid) override;
|
||||
@@ -231,6 +278,10 @@ private:
|
||||
void EnsureSelectedTypeIsValid();
|
||||
void EnsureSelectedTypeIsVisible();
|
||||
|
||||
PickerCollectionList collections; ///< List of collections.
|
||||
|
||||
void BuildPickerCollectionList();
|
||||
|
||||
GUIBadgeClasses badge_classes;
|
||||
std::pair<WidgetID, WidgetID> badge_filters{};
|
||||
BadgeFilterChoices badge_filter_choices{};
|
||||
|
||||
@@ -978,6 +978,7 @@ public:
|
||||
|
||||
StringID GetClassTooltip() const override { return STR_PICKER_STATION_CLASS_TOOLTIP; }
|
||||
StringID GetTypeTooltip() const override { return STR_PICKER_STATION_TYPE_TOOLTIP; }
|
||||
StringID GetCollectionTooltip() const override { return STR_PICKER_STATION_COLLECTION_TOOLTIP; }
|
||||
|
||||
bool IsActive() const override
|
||||
{
|
||||
@@ -1796,6 +1797,7 @@ public:
|
||||
|
||||
StringID GetClassTooltip() const override { return STR_PICKER_WAYPOINT_CLASS_TOOLTIP; }
|
||||
StringID GetTypeTooltip() const override { return STR_PICKER_WAYPOINT_TYPE_TOOLTIP; }
|
||||
StringID GetCollectionTooltip() const override { return STR_PICKER_WAYPOINT_COLLECTION_TOOLTIP; }
|
||||
|
||||
bool IsActive() const override
|
||||
{
|
||||
|
||||
@@ -1200,6 +1200,7 @@ public:
|
||||
|
||||
StringID GetClassTooltip() const override;
|
||||
StringID GetTypeTooltip() const override;
|
||||
StringID GetCollectionTooltip() const override;
|
||||
|
||||
bool IsActive() const override
|
||||
{
|
||||
@@ -1290,9 +1291,11 @@ public:
|
||||
|
||||
template <> StringID RoadStopPickerCallbacks<RoadStopType::Bus>::GetClassTooltip() const { return STR_PICKER_ROADSTOP_BUS_CLASS_TOOLTIP; }
|
||||
template <> StringID RoadStopPickerCallbacks<RoadStopType::Bus>::GetTypeTooltip() const { return STR_PICKER_ROADSTOP_BUS_TYPE_TOOLTIP; }
|
||||
template <> StringID RoadStopPickerCallbacks<RoadStopType::Bus>::GetCollectionTooltip() const { return STR_PICKER_ROADSTOP_BUS_COLLECTION_TOOLTIP; }
|
||||
|
||||
template <> StringID RoadStopPickerCallbacks<RoadStopType::Truck>::GetClassTooltip() const { return STR_PICKER_ROADSTOP_TRUCK_CLASS_TOOLTIP; }
|
||||
template <> StringID RoadStopPickerCallbacks<RoadStopType::Truck>::GetTypeTooltip() const { return STR_PICKER_ROADSTOP_TRUCK_TYPE_TOOLTIP; }
|
||||
template <> StringID RoadStopPickerCallbacks<RoadStopType::Truck>::GetCollectionTooltip() const { return STR_PICKER_ROADSTOP_TRUCK_COLLECTION_TOOLTIP; }
|
||||
|
||||
static RoadStopPickerCallbacks<RoadStopType::Bus> _bus_callback_instance("fav_passenger_roadstops");
|
||||
static RoadStopPickerCallbacks<RoadStopType::Truck> _truck_callback_instance("fav_freight_roadstops");
|
||||
@@ -1632,6 +1635,7 @@ public:
|
||||
|
||||
StringID GetClassTooltip() const override { return STR_PICKER_WAYPOINT_CLASS_TOOLTIP; }
|
||||
StringID GetTypeTooltip() const override { return STR_PICKER_WAYPOINT_TYPE_TOOLTIP; }
|
||||
StringID GetCollectionTooltip() const override { return STR_PICKER_WAYPOINT_COLLECTION_TOOLTIP; }
|
||||
|
||||
bool IsActive() const override
|
||||
{
|
||||
|
||||
@@ -1491,6 +1491,7 @@ public:
|
||||
|
||||
StringID GetClassTooltip() const override { return STR_PICKER_HOUSE_CLASS_TOOLTIP; }
|
||||
StringID GetTypeTooltip() const override { return STR_PICKER_HOUSE_TYPE_TOOLTIP; }
|
||||
StringID GetCollectionTooltip() const override { return STR_PICKER_HOUSE_COLLECTION_TOOLTIP; }
|
||||
bool IsActive() const override { return true; }
|
||||
|
||||
bool HasClassChoice() const override { return true; }
|
||||
@@ -1580,27 +1581,34 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::set<PickerItem> UpdateSavedItems(const std::set<PickerItem> &src) override
|
||||
std::map<std::string, std::set<PickerItem>> UpdateSavedItems(const std::map<std::string, std::set<PickerItem>> &src) override
|
||||
{
|
||||
if (src.empty()) return src;
|
||||
|
||||
const auto &specs = HouseSpec::Specs();
|
||||
std::set<PickerItem> dst;
|
||||
for (const auto &item : src) {
|
||||
if (item.grfid == 0) {
|
||||
const HouseSpec *hs = HouseSpec::Get(item.local_id);
|
||||
if (hs == nullptr) continue;
|
||||
int class_index = GetClassIdFromHouseZone(hs->building_availability);
|
||||
dst.emplace(item.grfid, item.local_id, class_index, item.local_id);
|
||||
} else {
|
||||
/* Search for spec by grfid and local index. */
|
||||
auto it = std::ranges::find_if(specs, [&item](const HouseSpec &spec) { return spec.grf_prop.grfid == item.grfid && spec.grf_prop.local_id == item.local_id; });
|
||||
if (it == specs.end()) {
|
||||
/* Not preset, hide from UI. */
|
||||
dst.emplace(item.grfid, item.local_id, -1, -1);
|
||||
std::map<std::string, std::set<PickerItem>> dst;
|
||||
for (auto group_it = src.begin(); group_it != src.end(); group_it++) {
|
||||
if (group_it->second.empty() || (group_it->second.size() == 1 && group_it->second.contains({}))) {
|
||||
dst[group_it->first];
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &item : group_it->second) {
|
||||
if (item.grfid == 0) {
|
||||
const HouseSpec *hs = HouseSpec::Get(item.local_id);
|
||||
if (hs == nullptr) continue;
|
||||
int class_index = GetClassIdFromHouseZone(hs->building_availability);
|
||||
dst[group_it->first].emplace(item.grfid, item.local_id, class_index, item.local_id);
|
||||
} else {
|
||||
int class_index = GetClassIdFromHouseZone(it->building_availability);
|
||||
dst.emplace(item.grfid, item.local_id, class_index, it->Index());
|
||||
/* Search for spec by grfid and local index. */
|
||||
auto it = std::ranges::find_if(specs, [&item](const HouseSpec &spec) { return spec.grf_prop.grfid == item.grfid && spec.grf_prop.local_id == item.local_id; });
|
||||
if (it == specs.end()) {
|
||||
/* Not preset, hide from UI. */
|
||||
dst[group_it->first].emplace(item.grfid, item.local_id, -1, -1);
|
||||
} else {
|
||||
int class_index = GetClassIdFromHouseZone(it->building_availability);
|
||||
dst[group_it->first].emplace(item.grfid, item.local_id, class_index, it->Index());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ enum PickerClassWindowWidgets : WidgetID {
|
||||
WID_PW_CLASS_LIST, ///< List of classes.
|
||||
WID_PW_CLASS_SCROLL, ///< Scrollbar for list of classes.
|
||||
|
||||
WID_PW_COLEC_LIST, ///< List of collections.
|
||||
WID_PW_COLEC_ADD, ///< Button to create a new collections.
|
||||
WID_PW_COLEC_RENAME, ///< Button to rename a collections.
|
||||
WID_PW_COLEC_DELETE, ///< Button to delete a collection.
|
||||
|
||||
WID_PW_TYPE_SEL, ///< Stack to hide the type picker.
|
||||
WID_PW_TYPE_FILTER, ///< Text filter.
|
||||
WID_PW_MODE_ALL, ///< Toggle "Show all" filter mode.
|
||||
@@ -32,7 +37,7 @@ enum PickerClassWindowWidgets : WidgetID {
|
||||
WID_PW_TYPE_NAME, ///< Name of selected item.
|
||||
WID_PW_TYPE_RESIZE, ///< Type resize handle.
|
||||
WID_PW_CONFIGURE_BADGES, ///< Button to configure badges.
|
||||
WID_PW_BADGE_FILTER, ///< Container for dropdown badge filters.
|
||||
WID_PW_BADGE_FILTER, ///< Container for dropdown badge filters. Must be last in this list.
|
||||
};
|
||||
|
||||
#endif /* WIDGETS_PICKER_WIDGET_H */
|
||||
|
||||
Reference in New Issue
Block a user