mirror of https://github.com/OpenTTD/OpenTTD.git
Feature: Add cargo filter support to vehicle list. (#8308)
This commit is contained in:
parent
a8a7f95665
commit
0d303d6c3f
|
@ -81,6 +81,7 @@ static const NWidgetPart _nested_group_widgets[] = {
|
|||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_FILTER_BY_CARGO), SetMinimalSize(167, 12), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
|
@ -118,7 +119,6 @@ private:
|
|||
VGC_END
|
||||
};
|
||||
|
||||
VehicleID vehicle_sel; ///< Selected vehicle
|
||||
GroupID group_sel; ///< Selected group (for drag/drop)
|
||||
GroupID group_rename; ///< Group being renamed, INVALID_GROUP if none
|
||||
GroupID group_over; ///< Group over which a vehicle is dragged, INVALID_GROUP if none
|
||||
|
@ -349,7 +349,6 @@ public:
|
|||
this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR);
|
||||
|
||||
this->vli.index = ALL_GROUP;
|
||||
this->vehicle_sel = INVALID_VEHICLE;
|
||||
this->group_sel = INVALID_GROUP;
|
||||
this->group_rename = INVALID_GROUP;
|
||||
this->group_over = INVALID_GROUP;
|
||||
|
@ -451,6 +450,10 @@ public:
|
|||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_GL_FILTER_BY_CARGO:
|
||||
SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]);
|
||||
break;
|
||||
|
||||
case WID_GL_AVAILABLE_VEHICLES:
|
||||
SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype);
|
||||
break;
|
||||
|
@ -530,6 +533,9 @@ public:
|
|||
/* Set text of "sort by" dropdown widget. */
|
||||
this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->GetVehicleSorterNames()[this->vehgroups.SortType()];
|
||||
|
||||
/* Set text of filter by cargo dropdown */
|
||||
this->GetWidget<NWidgetCore>(WID_GL_FILTER_BY_CARGO)->widget_data = this->cargo_filter_texts[this->cargo_filter_criteria];
|
||||
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
|
@ -647,6 +653,10 @@ public:
|
|||
ShowDropDownMenu(this, this->GetVehicleSorterNames(), this->vehgroups.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10));
|
||||
return;
|
||||
|
||||
case WID_GL_FILTER_BY_CARGO: // Select filtering criteria dropdown menu
|
||||
ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_GL_FILTER_BY_CARGO, 0, 0);
|
||||
break;
|
||||
|
||||
case WID_GL_ALL_VEHICLES: // All vehicles button
|
||||
if (!IsAllGroupID(this->vli.index)) {
|
||||
this->vli.index = ALL_GROUP;
|
||||
|
@ -930,6 +940,10 @@ public:
|
|||
this->vehgroups.SetSortType(index);
|
||||
break;
|
||||
|
||||
case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria
|
||||
this->SetCargoFilterIndex(index);
|
||||
break;
|
||||
|
||||
case WID_GL_MANAGE_VEHICLES_DROPDOWN:
|
||||
assert(this->vehicles.size() != 0);
|
||||
|
||||
|
|
|
@ -3884,6 +3884,11 @@ STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. Tra
|
|||
STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Range: {GOLD}{COMMA} tiles
|
||||
STR_PURCHASE_INFO_AIRCRAFT_TYPE :{BLACK}Aircraft type: {GOLD}{STRING}
|
||||
|
||||
###length 3
|
||||
STR_CARGO_TYPE_FILTER_ALL :All cargo types
|
||||
STR_CARGO_TYPE_FILTER_FREIGHT :Freight
|
||||
STR_CARGO_TYPE_FILTER_NONE :None
|
||||
|
||||
###length VEHICLE_TYPES
|
||||
STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Train vehicle selection list. Click on vehicle for information. Ctrl+Click for toggling hiding of the vehicle type
|
||||
STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Road vehicle selection list. Click on vehicle for information. Ctrl+Click for toggling hiding of the vehicle type
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define VEHICLE_GUI_BASE_H
|
||||
|
||||
#include "core/smallvec_type.hpp"
|
||||
#include "cargo_type.h"
|
||||
#include "date_type.h"
|
||||
#include "economy_type.h"
|
||||
#include "sortlist_type.h"
|
||||
|
@ -22,7 +23,7 @@
|
|||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
||||
typedef GUIList<const Vehicle*> GUIVehicleList;
|
||||
typedef GUIList<const Vehicle*, CargoID> GUIVehicleList;
|
||||
|
||||
struct GUIVehicleGroup {
|
||||
VehicleList::const_iterator vehicles_begin; ///< Pointer to beginning element of this vehicle group.
|
||||
|
@ -65,7 +66,7 @@ struct GUIVehicleGroup {
|
|||
}
|
||||
};
|
||||
|
||||
typedef GUIList<GUIVehicleGroup> GUIVehicleGroupList;
|
||||
typedef GUIList<GUIVehicleGroup, CargoID> GUIVehicleGroupList;
|
||||
|
||||
struct BaseVehicleListWindow : public Window {
|
||||
|
||||
|
@ -76,14 +77,25 @@ struct BaseVehicleListWindow : public Window {
|
|||
GB_END,
|
||||
};
|
||||
|
||||
GroupBy grouping; ///< How we want to group the list.
|
||||
VehicleList vehicles; ///< List of vehicles. This is the buffer for `vehgroups` to point into; if this is structurally modified, `vehgroups` must be rebuilt.
|
||||
GUIVehicleGroupList vehgroups; ///< List of (groups of) vehicles. This stores iterators of `vehicles`, and should be rebuilt if `vehicles` is structurally changed.
|
||||
Listing *sorting; ///< Pointer to the vehicle type related sorting.
|
||||
byte unitnumber_digits; ///< The number of digits of the highest unit number.
|
||||
/** Special cargo filter criteria */
|
||||
enum CargoFilterSpecialType {
|
||||
CF_NONE = CT_INVALID, ///< Show only vehicles which do not carry cargo (e.g. train engines)
|
||||
CF_ANY = CT_NO_REFIT, ///< Show all vehicles independent of carried cargo (i.e. no filtering)
|
||||
CF_FREIGHT = CT_AUTO_REFIT, ///< Show only vehicles which carry any freight (non-passenger) cargo
|
||||
};
|
||||
|
||||
GroupBy grouping; ///< How we want to group the list.
|
||||
VehicleList vehicles; ///< List of vehicles. This is the buffer for `vehgroups` to point into; if this is structurally modified, `vehgroups` must be rebuilt.
|
||||
GUIVehicleGroupList vehgroups; ///< List of (groups of) vehicles. This stores iterators of `vehicles`, and should be rebuilt if `vehicles` is structurally changed.
|
||||
Listing *sorting; ///< Pointer to the vehicle type related sorting.
|
||||
byte unitnumber_digits; ///< The number of digits of the highest unit number.
|
||||
Scrollbar *vscroll;
|
||||
VehicleListIdentifier vli; ///< Identifier of the vehicle list we want to currently show.
|
||||
uint order_arrow_width; ///< Width of the arrow in the small order list.
|
||||
VehicleListIdentifier vli; ///< Identifier of the vehicle list we want to currently show.
|
||||
VehicleID vehicle_sel; ///< Selected vehicle
|
||||
CargoID cargo_filter[NUM_CARGO + 3]; ///< Available cargo filters; CargoID or CF_ANY or CF_FREIGHT or CF_NONE
|
||||
StringID cargo_filter_texts[NUM_CARGO + 4]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID
|
||||
byte cargo_filter_criteria; ///< Selected cargo filter index
|
||||
uint order_arrow_width; ///< Width of the arrow in the small order list.
|
||||
|
||||
typedef GUIVehicleGroupList::SortFunction VehicleGroupSortFunction;
|
||||
typedef GUIVehicleList::SortFunction VehicleIndividualSortFunction;
|
||||
|
@ -113,6 +125,9 @@ struct BaseVehicleListWindow : public Window {
|
|||
void UpdateVehicleGroupBy(GroupBy group_by);
|
||||
void SortVehicleList();
|
||||
void BuildVehicleList();
|
||||
void SetCargoFilterIndex(byte index);
|
||||
void SetCargoFilterArray();
|
||||
void FilterVehicleList();
|
||||
Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group);
|
||||
DropDownList BuildActionDropdownList(bool show_autoreplace, bool show_group);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ enum GroupListWidgets {
|
|||
WID_GL_GROUP_BY_DROPDOWN, ///< Group by dropdown list.
|
||||
WID_GL_SORT_BY_ORDER, ///< Sort order.
|
||||
WID_GL_SORT_BY_DROPDOWN, ///< Sort by dropdown list.
|
||||
WID_GL_FILTER_BY_CARGO, ///< Filter vehicles by cargo type.
|
||||
WID_GL_LIST_VEHICLE, ///< List of the vehicles.
|
||||
WID_GL_LIST_VEHICLE_SCROLLBAR, ///< Scrollbar for the list.
|
||||
WID_GL_AVAILABLE_VEHICLES, ///< Available vehicles.
|
||||
|
|
|
@ -69,6 +69,8 @@ enum VehicleListWidgets {
|
|||
WID_VL_GROUP_BY_PULLDOWN, ///< Group by dropdown list.
|
||||
WID_VL_SORT_ORDER, ///< Sort order.
|
||||
WID_VL_SORT_BY_PULLDOWN, ///< Sort by dropdown list.
|
||||
WID_VL_FILTER_BY_CARGO, ///< Cargo filter dropdown list.
|
||||
WID_VL_FILTER_BY_CARGO_SEL, ///< Cargo filter dropdown list panel selector.
|
||||
WID_VL_LIST, ///< List of the vehicles.
|
||||
WID_VL_SCROLLBAR, ///< Scrollbar for the list.
|
||||
WID_VL_HIDE_BUTTONS, ///< Selection to hide the buttons.
|
||||
|
|
Loading…
Reference in New Issue