1
0
Fork 0

Add: Filter purchase lists by badge text. (#13588)

pull/13594/head
Peter Nelson 2025-02-17 17:28:26 +00:00 committed by GitHub
parent 5e43aaff35
commit 7a23bfa747
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 66 additions and 4 deletions

View File

@ -1436,6 +1436,8 @@ struct BuildVehicleWindow : Window {
list.clear();
BadgeTextFilter btf(this->string_filter, GSF_TRAINS);
/* Make list of all available train engines and wagons.
* Also check to see if the previously selected engine is still available,
* and if not, reset selection to EngineID::Invalid(). This could be the case
@ -1452,7 +1454,7 @@ struct BuildVehicleWindow : Window {
if (!FilterSingleEngine(eid)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e)) continue;
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
@ -1501,6 +1503,8 @@ struct BuildVehicleWindow : Window {
this->eng_list.clear();
BadgeTextFilter btf(this->string_filter, GSF_ROADVEHICLES);
for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
EngineID eid = e->index;
@ -1508,7 +1512,7 @@ struct BuildVehicleWindow : Window {
if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e)) continue;
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
@ -1523,13 +1527,15 @@ struct BuildVehicleWindow : Window {
EngineID sel_id = EngineID::Invalid();
this->eng_list.clear();
BadgeTextFilter btf(this->string_filter, GSF_SHIPS);
for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e)) continue;
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
@ -1547,6 +1553,8 @@ struct BuildVehicleWindow : Window {
const Station *st = this->listview_mode ? nullptr : Station::GetByTile(TileIndex(this->window_number));
BadgeTextFilter btf(this->string_filter, GSF_AIRCRAFT);
/* Make list of all available planes.
* Also check to see if the previously selected plane is still available,
* and if not, reset selection to EngineID::Invalid(). This could be the case
@ -1559,7 +1567,7 @@ struct BuildVehicleWindow : Window {
if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e)) continue;
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);

View File

@ -14,6 +14,7 @@
#include "newgrf_badge.h"
#include "newgrf_badge_type.h"
#include "newgrf_spritegroup.h"
#include "stringfilter_type.h"
#include "strings_func.h"
#include "timer/timer_game_calendar.h"
#include "window_gui.h"
@ -389,6 +390,42 @@ uint GUIBadgeClasses::GetTotalColumnsWidth() const
return std::accumulate(std::begin(this->column_widths), std::end(this->column_widths), 0U);
}
/**
* Construct a badge text filter.
* @param filter string filter.
* @param feature feature being used.
*/
BadgeTextFilter::BadgeTextFilter(StringFilter &filter, GrfSpecFeature feature)
{
/* Do not filter if the filter text box is empty */
if (filter.IsEmpty()) return;
/* Pre-build list of badges that match by string. */
for (const auto &badge : _badges.specs) {
if (badge.name == STR_NULL) continue;
if (!badge.features.Test(feature)) continue;
filter.ResetState();
filter.AddLine(GetString(badge.name));
if (!filter.GetState()) continue;
auto it = std::ranges::lower_bound(this->badges, badge.index);
if (it != std::end(this->badges) && *it == badge.index) continue;
this->badges.insert(it, badge.index);
}
}
/**
* Test if any of the given badges matches the filtered badge list.
* @param badges List of badges.
* @returns true iff at least one badge in badges is present.
*/
bool BadgeTextFilter::Filter(std::span<const BadgeID> badges) const
{
return std::ranges::any_of(badges, [this](const BadgeID &badge) { return std::ranges::binary_search(this->badges, badge); });
}
/**
* Draw names for a list of badge labels.
* @param r Rect to draw in.

View File

@ -74,6 +74,15 @@ void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &badge_clas
uint32_t GetBadgeVariableResult(const struct GRFFile &grffile, std::span<const BadgeID> badges, uint32_t parameter);
class BadgeTextFilter {
public:
BadgeTextFilter(struct StringFilter &filter, GrfSpecFeature feature);
bool Filter(std::span<const BadgeID> badges) const;
private:
std::vector<BadgeID> badges{};
};
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, StringID 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, StringID str, int value, bool masked = false, bool shaded = false);

View File

@ -147,6 +147,8 @@ static bool TypeIDSorter(PickerItem const &a, PickerItem const &b)
/** Filter types by class name. */
static bool TypeTagNameFilter(PickerItem const *item, PickerFilterData &filter)
{
if (filter.btf.has_value() && filter.btf->Filter(filter.callbacks->GetTypeBadges(item->class_index, item->index))) return true;
filter.ResetState();
filter.AddLine(GetString(filter.callbacks->GetTypeName(item->class_index, item->index)));
return filter.GetState();
@ -449,6 +451,11 @@ void PickerWindow::OnEditboxChanged(WidgetID wid)
case WID_PW_TYPE_FILTER:
this->type_string_filter.SetFilterTerm(this->type_editbox.text.GetText());
if (!type_string_filter.IsEmpty()) {
this->type_string_filter.btf.emplace(this->type_string_filter, this->callbacks.GetFeature());
} else {
this->type_string_filter.btf.reset();
}
this->types.SetFilterState(!type_string_filter.IsEmpty());
this->InvalidateData(PickerInvalidation::Type);
break;

View File

@ -144,6 +144,7 @@ public:
struct PickerFilterData : StringFilter {
const PickerCallbacks *callbacks; ///< Callbacks for filter functions to access to callbacks.
std::optional<BadgeTextFilter> btf;
};
using PickerClassList = GUIList<int, std::nullptr_t, PickerFilterData &>; ///< GUIList holding classes to display.