Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Option to group vehicle list by shared orders #7028

Merged
merged 6 commits into from Dec 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
151 changes: 99 additions & 52 deletions src/group_gui.cpp
Expand Up @@ -71,6 +71,11 @@ static const NWidgetPart _nested_group_widgets[] = {
EndContainer(),
/* right part */
NWidget(NWID_VERTICAL),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GL_GROUP_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_STATION_VIEW_GROUP, STR_TOOLTIP_GROUP_ORDER),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(),
EndContainer(),
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),
Expand Down Expand Up @@ -341,24 +346,12 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR);
this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR);

switch (this->vli.vtype) {
default: NOT_REACHED();
case VEH_TRAIN: this->sorting = &_sorting.train; break;
case VEH_ROAD: this->sorting = &_sorting.roadveh; break;
case VEH_SHIP: this->sorting = &_sorting.ship; break;
case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break;
}

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;

this->vehicles.SetListing(*this->sorting);
this->vehicles.ForceRebuild();
this->vehicles.NeedResort();

this->BuildVehicleList();
this->SortVehicleList();

Expand All @@ -382,7 +375,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow {

~VehicleGroupWindow()
{
*this->sorting = this->vehicles.GetListing();
*this->sorting = this->vehgroups.GetListing();
}

void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Expand Down Expand Up @@ -453,10 +446,10 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
{
if (data == 0) {
/* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
this->vehicles.ForceRebuild();
this->vehgroups.ForceRebuild();
this->groups.ForceRebuild();
} else {
this->vehicles.ForceResort();
this->vehgroups.ForceResort();
this->groups.ForceResort();
}

Expand Down Expand Up @@ -509,8 +502,8 @@ class VehicleGroupWindow : public BaseVehicleListWindow {

this->BuildGroupList(this->owner);

this->group_sb->SetCount((uint)this->groups.size());
this->vscroll->SetCount((uint)this->vehicles.size());
this->group_sb->SetCount(static_cast<int>(this->groups.size()));
this->vscroll->SetCount(static_cast<int>(this->vehgroups.size()));

/* The drop down menu is out, *but* it may not be used, retract it. */
if (this->vehicles.size() == 0 && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) {
Expand Down Expand Up @@ -549,8 +542,11 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && Group::Get(this->vli.index)->replace_protection) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN;
this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype;

/* Set text of sort by dropdown */
this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()];
/* Set text of "group by" dropdown widget. */
this->GetWidget<NWidgetCore>(WID_GL_GROUP_BY_DROPDOWN)->widget_data = this->vehicle_group_by_names[this->grouping];

/* Set text of "sort by" dropdown widget. */
this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->GetVehicleSorterNames()[this->vehgroups.SortType()];

this->DrawWidgets();
}
Expand All @@ -569,11 +565,9 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
case WID_GL_INFO: {
Money this_year = 0;
Money last_year = 0;
uint32 occupancy = 0;
size_t vehicle_count = this->vehicles.size();
uint64 occupancy = 0;

for (uint i = 0; i < vehicle_count; i++) {
const Vehicle *v = this->vehicles[i];
for (const Vehicle * const v : this->vehicles) {
assert(v->owner == this->owner);

this_year += v->GetDisplayProfitThisYear();
Expand All @@ -596,6 +590,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow {

y += FONT_HEIGHT_NORMAL;
DrawString(left, right, y, STR_GROUP_OCCUPANCY, TC_BLACK);
const size_t vehicle_count = this->vehicles.size();
if (vehicle_count > 0) {
SetDParam(0, occupancy / vehicle_count);
DrawString(left, right, y, STR_GROUP_OCCUPANCY_VALUE, TC_BLACK, SA_RIGHT);
Expand Down Expand Up @@ -623,16 +618,16 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
}

case WID_GL_SORT_BY_ORDER:
this->DrawSortButtonState(WID_GL_SORT_BY_ORDER, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
this->DrawSortButtonState(WID_GL_SORT_BY_ORDER, this->vehgroups.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
break;

case WID_GL_LIST_VEHICLE:
if (this->vli.index != ALL_GROUP) {
/* Mark vehicles which are in sub-groups */
if (this->vli.index != ALL_GROUP && this->grouping == GB_NONE) {
/* Mark vehicles which are in sub-groups (only if we are not using shared order coalescing) */
int y = r.top;
uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->vehicles.size());
uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), static_cast<uint>(this->vehgroups.size()));
for (uint i = this->vscroll->GetPosition(); i < max; ++i) {
const Vehicle *v = this->vehicles[i];
const Vehicle *v = this->vehgroups[i].GetSingleVehicle();
if (v->group_id != this->vli.index) {
GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 2, _colour_gradient[COLOUR_GREY][3], FILLRECT_CHECKER);
}
Expand All @@ -658,26 +653,30 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
{
switch (widget) {
case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending
this->vehicles.ToggleSortOrder();
this->vehgroups.ToggleSortOrder();
this->SetDirty();
break;

case WID_GL_GROUP_BY_DROPDOWN: // Select grouping option dropdown menu
ShowDropDownMenu(this, this->vehicle_group_by_names, this->grouping, WID_GL_GROUP_BY_DROPDOWN, 0, 0);
return;

case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu
ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10));
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_ALL_VEHICLES: // All vehicles button
if (!IsAllGroupID(this->vli.index)) {
this->vli.index = ALL_GROUP;
this->vehicles.ForceRebuild();
this->vehgroups.ForceRebuild();
this->SetDirty();
}
break;

case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button
if (!IsDefaultGroupID(this->vli.index)) {
this->vli.index = DEFAULT_GROUP;
this->vehicles.ForceRebuild();
this->vehgroups.ForceRebuild();
this->SetDirty();
}
break;
Expand Down Expand Up @@ -717,29 +716,54 @@ class VehicleGroupWindow : public BaseVehicleListWindow {

SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);

this->vehicles.ForceRebuild();
this->vehgroups.ForceRebuild();
this->SetDirty();
break;
}

case WID_GL_LIST_VEHICLE: { // Matrix Vehicle
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE);
if (id_v >= this->vehicles.size()) return; // click out of list bound
if (id_v >= this->vehgroups.size()) return; // click out of list bound

const GUIVehicleGroup &vehgroup = this->vehgroups[id_v];

const Vehicle *v = nullptr;

const Vehicle *v = this->vehicles[id_v];
if (VehicleClicked(v)) break;
switch (this->grouping) {
case GB_NONE: {
const Vehicle *v2 = vehgroup.GetSingleVehicle();
if (VehicleClicked(v2)) break;
v = v2;
break;
}

this->vehicle_sel = v->index;
case GB_SHARED_ORDERS: {
assert(vehgroup.NumVehicles() > 0);
v = vehgroup.vehicles_begin[0];
/*
No VehicleClicked(v) support for now, because don't want
to enable any contextual actions except perhaps clicking/ctrl-clicking to clone orders.
*/
break;
}

if (_ctrl_pressed) {
this->SelectGroup(v->group_id);
default:
NOT_REACHED();
}
if (v) {
this->vehicle_sel = v->index;

SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
SetMouseCursorVehicle(v, EIT_IN_LIST);
_cursor.vehchain = true;
if (_ctrl_pressed) {
this->SelectGroup(v->group_id);
}

SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
SetMouseCursorVehicle(v, EIT_IN_LIST);
_cursor.vehchain = true;

this->SetDirty();
}

this->SetDirty();
break;
}

Expand Down Expand Up @@ -823,7 +847,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
{
switch (widget) {
case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE));
DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE));

this->vehicle_sel = INVALID_VEHICLE;
this->group_over = INVALID_GROUP;
Expand All @@ -840,7 +864,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height);
GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;

DoCommandP(0, new_g, vindex | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr);
DoCommandP(0, new_g, vindex | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr);
break;
}

Expand All @@ -851,11 +875,30 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
this->SetDirty();

uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE);
if (id_v >= this->vehicles.size()) return; // click out of list bound
if (id_v >= this->vehgroups.size()) return; // click out of list bound

const GUIVehicleGroup &vehgroup = this->vehgroups[id_v];
switch (this->grouping) {
case GB_NONE: {
const Vehicle *v = vehgroup.GetSingleVehicle();
if (!VehicleClicked(v) && vindex == v->index) {
ShowVehicleViewWindow(v);
}
break;
}

case GB_SHARED_ORDERS: {
const Vehicle *v = vehgroup.vehicles_begin[0];
/* We do not support VehicleClicked() here since the contextual action may only make sense for individual vehicles */

if (vindex == v->index) {
ShowVehicleListWindow(v);
}
break;
}

const Vehicle *v = this->vehicles[id_v];
if (!VehicleClicked(v) && vindex == v->index) {
ShowVehicleViewWindow(v);
default:
NOT_REACHED();
}
break;
}
Expand Down Expand Up @@ -885,8 +928,12 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
void OnDropdownSelect(int widget, int index) override
{
switch (widget) {
case WID_GL_GROUP_BY_DROPDOWN:
this->UpdateVehicleGroupBy(static_cast<GroupBy>(index));
break;

case WID_GL_SORT_BY_DROPDOWN:
this->vehicles.SetSortType(index);
this->vehgroups.SetSortType(index);
break;

case WID_GL_MANAGE_VEHICLES_DROPDOWN:
Expand Down Expand Up @@ -924,7 +971,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow {

void OnGameTick() override
{
if (this->groups.NeedResort() || this->vehicles.NeedResort()) {
if (this->groups.NeedResort() || this->vehgroups.NeedResort()) {
this->SetDirty();
}
}
Expand Down Expand Up @@ -1019,7 +1066,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
}
this->group_sb->ScrollTowards(id_g);
}
this->vehicles.ForceRebuild();
this->vehgroups.ForceRebuild();
this->SetDirty();
}

Expand Down
9 changes: 9 additions & 0 deletions src/lang/english.txt
Expand Up @@ -315,6 +315,15 @@ STR_SORT_BY_CARGO_CAPACITY :Cargo capacity
STR_SORT_BY_RANGE :Range
STR_SORT_BY_POPULATION :Population
STR_SORT_BY_RATING :Rating
STR_SORT_BY_NUM_VEHICLES :Number of vehicles
STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Total profit last year
STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Total profit this year
STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Average profit last year
STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Average profit this year

# Group by options for vehicle list
STR_GROUP_BY_NONE :None
STR_GROUP_BY_SHARED_ORDERS :Shared orders

# Tooltips for the main toolbar
STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pause game
Expand Down
8 changes: 4 additions & 4 deletions src/station_gui.cpp
Expand Up @@ -792,14 +792,14 @@ static const NWidgetPart _nested_station_view_widgets[] = {
NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
NWidget(WWT_STICKYBOX, COLOUR_GREY),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_WAITING), SetMinimalSize(237, 44), SetResize(1, 10), SetScrollbar(WID_SV_SCROLLBAR), EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SV_SCROLLBAR),
Expand Down