mirror of https://github.com/OpenTTD/OpenTTD
Add: Filter purchase lists by badge text. (#13588)
parent
5e43aaff35
commit
7a23bfa747
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue