Feature: Add cargo filter support to vehicle list. (#8308)

This commit is contained in:
stormcone
2022-11-08 21:11:16 +01:00
committed by GitHub
parent a8a7f95665
commit 0d303d6c3f
6 changed files with 183 additions and 11 deletions

View File

@@ -139,6 +139,7 @@ const StringID BaseVehicleListWindow::vehicle_depot_name[] = {
BaseVehicleListWindow::BaseVehicleListWindow(WindowDesc *desc, WindowNumber wno) : Window(desc), vli(VehicleListIdentifier::UnPack(wno))
{
this->vehicle_sel = INVALID_VEHICLE;
this->grouping = _grouping[vli.type][vli.vtype];
this->UpdateSortingFromGrouping();
}
@@ -195,6 +196,8 @@ void BaseVehicleListWindow::BuildVehicleList()
max_unitnumber = std::max<uint>(max_unitnumber, (*it)->unitnumber);
}
this->unitnumber_digits = CountDigitsForAllocatingSpace(max_unitnumber);
this->FilterVehicleList();
} else {
/* Sort by the primary vehicle; we just want all vehicles that share the same orders to form a contiguous range. */
std::stable_sort(this->vehicles.begin(), this->vehicles.end(), [](const Vehicle * const &u, const Vehicle * const &v) {
@@ -223,6 +226,118 @@ void BaseVehicleListWindow::BuildVehicleList()
this->vscroll->SetCount(static_cast<int>(this->vehgroups.size()));
}
/** Cargo filter functions */
/**
* Check whether a vehicle can carry a specific cargo.
* @param vehgroup The vehicle group which contains the vehicle to be checked
* @param cid The cargo what we are looking for
* @return Whether the vehicle can carry the specified cargo or not
*/
static bool CDECL CargoFilter(const GUIVehicleGroup *vehgroup, const CargoID cid)
{
const Vehicle *v = (*vehgroup).GetSingleVehicle();
if (cid == BaseVehicleListWindow::CF_ANY) {
return true;
} else if (cid == BaseVehicleListWindow::CF_NONE) {
for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
if (w->cargo_cap > 0) {
return false;
}
}
return true;
} else if (cid == BaseVehicleListWindow::CF_FREIGHT) {
bool have_capacity = false;
for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
if (w->cargo_cap > 0) {
if (IsCargoInClass(w->cargo_type, CC_PASSENGERS)) {
return false;
} else {
have_capacity = true;
}
}
}
return have_capacity;
} else {
for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
if (w->cargo_cap > 0 && w->cargo_type == cid) {
return true;
}
}
return false;
}
}
static GUIVehicleGroupList::FilterFunction * const _filter_funcs[] = {
&CargoFilter,
};
/**
* Set cargo filter list item index.
* @param index The index to be set
*/
void BaseVehicleListWindow::SetCargoFilterIndex(byte index)
{
if (this->cargo_filter_criteria != index) {
this->cargo_filter_criteria = index;
/* Deactivate filter if criteria is 'Show All', activate it otherwise. */
this->vehgroups.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
this->vehgroups.SetFilterType(0);
this->vehgroups.ForceRebuild();
}
}
/**
*Populate the filter list and set the cargo filter criteria.
*/
void BaseVehicleListWindow::SetCargoFilterArray()
{
byte filter_items = 0;
/* Add item for disabling filtering. */
this->cargo_filter[filter_items] = CF_ANY;
this->cargo_filter_texts[filter_items] = STR_CARGO_TYPE_FILTER_ALL;
this->cargo_filter_criteria = filter_items;
filter_items++;
/* Add item for freight (i.e. vehicles with cargo capacity and with no passenger capacity). */
this->cargo_filter[filter_items] = CF_FREIGHT;
this->cargo_filter_texts[filter_items] = STR_CARGO_TYPE_FILTER_FREIGHT;
filter_items++;
/* Add item for vehicles not carrying anything, e.g. train engines. */
this->cargo_filter[filter_items] = CF_NONE;
this->cargo_filter_texts[filter_items] = STR_CARGO_TYPE_FILTER_NONE;
filter_items++;
/* Collect available cargo types for filtering. */
for (const auto &cs : _sorted_cargo_specs) {
this->cargo_filter[filter_items] = cs->Index();
this->cargo_filter_texts[filter_items] = cs->name;
filter_items++;
}
/* Terminate the filter list. */
this->cargo_filter_texts[filter_items] = INVALID_STRING_ID;
this->vehgroups.SetFilterFuncs(_filter_funcs);
this->vehgroups.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
}
/**
*Filter the engine list against the currently selected cargo filter.
*/
void BaseVehicleListWindow::FilterVehicleList()
{
this->vehgroups.Filter(this->cargo_filter[this->cargo_filter_criteria]);
if (this->vehicles.size() == 0) {
/* No vehicle passed through the filter, invalidate the previously selected vehicle */
this->vehicle_sel = INVALID_VEHICLE;
} else if (this->vehicle_sel != INVALID_VEHICLE && std::find(this->vehicles.begin(), this->vehicles.end(), Vehicle::Get(this->vehicle_sel)) == this->vehicles.end()) { // previously selected engine didn't pass the filter, remove selection
this->vehicle_sel = INVALID_VEHICLE;
}
}
/**
* Compute the size for the Action dropdown.
* @param show_autoreplace If true include the autoreplace item.
@@ -248,6 +363,7 @@ Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bo
void BaseVehicleListWindow::OnInit()
{
this->order_arrow_width = GetStringBoundingBox(STR_TINY_RIGHT_ARROW).width;
this->SetCargoFilterArray();
}
/**
@@ -1391,6 +1507,9 @@ static const NWidgetPart _nested_vehicle_list[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_SORT_BY_PULLDOWN), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VL_FILTER_BY_CARGO_SEL),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_FILTER_BY_CARGO), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(),
EndContainer(),
@@ -1662,6 +1781,8 @@ public:
{
this->CreateNestedTree();
this->GetWidget<NWidgetStacked>(WID_VL_FILTER_BY_CARGO_SEL)->SetDisplayedPlane((this->vli.type == VL_SHARED_ORDERS) ? SZSP_NONE : 0);
this->vscroll = this->GetScrollbar(WID_VL_SCROLLBAR);
this->BuildVehicleList();
@@ -1736,6 +1857,10 @@ public:
SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype);
break;
case WID_VL_FILTER_BY_CARGO:
SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]);
break;
case WID_VL_CAPTION:
case WID_VL_CAPTION_SHARED_ORDERS: {
switch (this->vli.type) {
@@ -1819,6 +1944,8 @@ public:
/* Set text of sort by dropdown widget. */
this->GetWidget<NWidgetCore>(WID_VL_SORT_BY_PULLDOWN)->widget_data = this->GetVehicleSorterNames()[this->vehgroups.SortType()];
this->GetWidget<NWidgetCore>(WID_VL_FILTER_BY_CARGO)->widget_data = this->cargo_filter_texts[this->cargo_filter_criteria];
this->DrawWidgets();
}
@@ -1845,6 +1972,10 @@ public:
(this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10));
return;
case WID_VL_FILTER_BY_CARGO: // Cargo filter dropdown
ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_VL_FILTER_BY_CARGO, 0, 0);
break;
case WID_VL_LIST: { // Matrix to show vehicles
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VL_LIST);
if (id_v >= this->vehgroups.size()) return; // click out of list bound
@@ -1913,6 +2044,10 @@ public:
this->vehgroups.SetSortType(index);
break;
case WID_VL_FILTER_BY_CARGO:
this->SetCargoFilterIndex(index);
break;
case WID_VL_MANAGE_VEHICLES_DROPDOWN:
assert(this->vehicles.size() != 0);