diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 332c827fbb..42c1d17674 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -22,6 +22,7 @@ #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" +#include "vehicle_gui.h" #include "sound_func.h" #include "cheat_type.h" #include "company_base.h" @@ -471,7 +472,7 @@ void Aircraft::OnNewDay() SubtractMoneyFromCompanyFract(this->owner, cost); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); - SetWindowClassesDirty(WC_AIRCRAFT_LIST); + DirtyVehicleListWindowForVehicle(this); } static void HelicopterTickHandler(Aircraft *v) @@ -1514,7 +1515,7 @@ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir) VehicleServiceInDepot(v); SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); - SetWindowClassesDirty(WC_AIRCRAFT_LIST); + DirtyVehicleListWindowForVehicle(v); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/economy.cpp b/src/economy.cpp index ecaa224704..06b44f515a 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -2158,7 +2158,7 @@ static void LoadUnloadVehicle(Vehicle *front) } if (dirty_vehicle) { - SetWindowDirty(GetWindowClassForVehicleType(front->type), front->owner); + DirtyVehicleListWindowForVehicle(front); SetWindowDirty(WC_VEHICLE_DETAILS, front->index); front->MarkDirty(); } diff --git a/src/group_gui.cpp b/src/group_gui.cpp index d4b653f837..b2477cdb06 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -157,6 +157,10 @@ private: Dimension column_size[VGC_END]; ///< Size of the columns in the group list. + Money money_this_year; + Money money_last_year; + uint32 occupancy_ratio; + /** return true if group has children */ void AddChildren(GUIGroupList *source, GroupID parent, int indent) { @@ -377,6 +381,31 @@ private: this->SetDirty(); } + bool RecalculateInfoTotals() + { + Money this_year = 0; + Money last_year = 0; + uint32 occupancy = 0; + size_t vehicle_count = this->vehicles.size(); + + for (uint i = 0; i < vehicle_count; i++) { + const Vehicle *v = this->vehicles[i]; + assert(v->owner == this->owner); + + this_year += v->GetDisplayProfitThisYear(); + last_year += v->GetDisplayProfitLastYear(); + occupancy += v->trip_occupancy; + } + + uint32 occupancy_ratio = occupancy / vehicle_count; + + bool ret = (this->money_this_year != this_year) || (this->money_last_year != last_year) || (occupancy_ratio != this->occupancy_ratio); + this->money_this_year = this_year; + this->money_last_year = last_year; + this->occupancy_ratio = occupancy_ratio; + return ret; + } + public: VehicleGroupWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) { @@ -412,6 +441,8 @@ public: this->BuildGroupList(vli.company); this->group_sb->SetCount((uint)this->groups.size()); + this->RecalculateInfoTotals(); + this->GetWidget(WID_GL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype; this->GetWidget(WID_GL_LIST_VEHICLE)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype; @@ -556,6 +587,7 @@ public: { /* If we select the all vehicles, this->list will contain all vehicles of the owner * else this->list will contain all vehicles which belong to the selected group */ + if (this->vehicles.NeedRebuild()) this->RecalculateInfoTotals(); this->BuildVehicleList(); this->SortVehicleList(); @@ -621,37 +653,23 @@ public: break; case WID_GL_INFO: { - Money this_year = 0; - Money last_year = 0; - uint32 occupancy = 0; - size_t vehicle_count = this->vehicles.size(); - - for (uint i = 0; i < vehicle_count; i++) { - const Vehicle *v = this->vehicles[i]; - assert(v->owner == this->owner); - - this_year += v->GetDisplayProfitThisYear(); - last_year += v->GetDisplayProfitLastYear(); - occupancy += v->trip_occupancy; - } - const int left = r.left + WD_FRAMERECT_LEFT + 8; const int right = r.right - WD_FRAMERECT_RIGHT - 8; int y = r.top + WD_FRAMERECT_TOP; DrawString(left, right, y, STR_GROUP_PROFIT_THIS_YEAR, TC_BLACK); - SetDParam(0, this_year); + SetDParam(0, this->money_this_year); DrawString(left, right, y, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT); y += FONT_HEIGHT_NORMAL; DrawString(left, right, y, STR_GROUP_PROFIT_LAST_YEAR, TC_BLACK); - SetDParam(0, last_year); + SetDParam(0, this->money_last_year); DrawString(left, right, y, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT); y += FONT_HEIGHT_NORMAL; DrawString(left, right, y, STR_GROUP_OCCUPANCY, TC_BLACK); - if (vehicle_count > 0) { - SetDParam(0, occupancy / vehicle_count); + if (this->vehicles.size() > 0) { + SetDParam(0, this->occupancy_ratio); DrawString(left, right, y, STR_GROUP_OCCUPANCY_VALUE, TC_BLACK, SA_RIGHT); } @@ -1024,7 +1042,10 @@ public: void OnGameTick() override { if (this->groups.NeedResort() || this->vehicles.NeedResort()) { - this->SetDirty(); + this->SetWidgetDirty(WID_GL_LIST_VEHICLE); + } + if (this->RecalculateInfoTotals()) { + this->SetWidgetDirty(WID_GL_INFO); } } diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 656b9284e8..0bcaf9b0e0 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1464,8 +1464,7 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 } /* We have an aircraft/ship, they have a mini-schedule, so update them all */ - if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST); - if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST); + if (v->type == VEH_AIRCRAFT || v->type == VEH_SHIP) DirtyVehicleListWindowForVehicle(v); return CommandCost(); } @@ -2958,7 +2957,7 @@ bool ProcessOrders(Vehicle *v) case VEH_AIRCRAFT: case VEH_SHIP: - SetWindowClassesDirty(GetWindowClassForVehicleType(v->type)); + DirtyVehicleListWindowForVehicle(v); break; } diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 9c62e9550a..87e2ea3360 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -1833,7 +1833,7 @@ void RoadVehicle::OnNewDay() SubtractMoneyFromCompanyFract(this->owner, cost); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); - SetWindowClassesDirty(WC_ROADVEH_LIST); + DirtyVehicleListWindowForVehicle(this); } Trackdir RoadVehicle::GetVehicleTrackdir() const diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index a702f044eb..3e0fe08793 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -24,6 +24,7 @@ #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" +#include "vehicle_gui.h" #include "sound_func.h" #include "ai/ai.hpp" #include "game/game.hpp" @@ -254,7 +255,7 @@ void Ship::OnNewDay() SetWindowDirty(WC_VEHICLE_DETAILS, this->index); /* we need this for the profit */ - SetWindowClassesDirty(WC_SHIPS_LIST); + DirtyVehicleListWindowForVehicle(this); } Trackdir Ship::GetVehicleTrackdir() const @@ -414,7 +415,7 @@ static bool CheckShipLeaveDepot(Ship *v) PlayShipSound(v); VehicleServiceInDepot(v); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); - SetWindowClassesDirty(WC_SHIPS_LIST); + DirtyVehicleListWindowForVehicle(v); return false; } diff --git a/src/tbtr_template_gui_create.cpp b/src/tbtr_template_gui_create.cpp index 57c2113c1d..a2c6593cec 100644 --- a/src/tbtr_template_gui_create.cpp +++ b/src/tbtr_template_gui_create.cpp @@ -169,8 +169,6 @@ public: virtual_train = nullptr; } - SetWindowClassesDirty(WC_TRAINS_LIST); - /* more cleanup */ *create_window_open = false; DeleteWindowById(WC_BUILD_VIRTUAL_TRAIN, this->window_number); diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 389a7680e3..c61892dead 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -2972,6 +2972,7 @@ void ShowTraceRestrictProgramWindow(TileIndex tile, Track track) /** Slot GUI widget IDs */ enum TraceRestrictSlotWindowWidgets { + WID_TRSL_LIST_VEHICLE, // this must be first, see: DirtyVehicleListWindowForVehicle WID_TRSL_CAPTION, WID_TRSL_ALL_VEHICLES, WID_TRSL_LIST_SLOTS, @@ -2984,7 +2985,6 @@ enum TraceRestrictSlotWindowWidgets { WID_TRSL_SORT_BY_DROPDOWN, WID_TRSL_FILTER_BY_CARGO, WID_TRSL_FILTER_BY_CARGO_SEL, - WID_TRSL_LIST_VEHICLE, WID_TRSL_LIST_VEHICLE_SCROLLBAR, }; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 7202a5b0d9..f13f2e4939 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2378,8 +2378,7 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); SetWindowDirty(WC_VEHICLE_DETAILS, front->index); SetWindowDirty(WC_VEHICLE_VIEW, front->index); - SetWindowClassesDirty(WC_TRAINS_LIST); - SetWindowClassesDirty(WC_TRACE_RESTRICT_SLOTS); + DirtyVehicleListWindowForVehicle(front); } } else { /* turn the whole train around */ @@ -2609,8 +2608,6 @@ static bool CheckTrainStayInDepot(Train *v) if (v->force_proceed == TFP_NONE) { /* force proceed was not pressed */ if (++v->wait_counter < 37) { - SetWindowClassesDirty(WC_TRAINS_LIST); - SetWindowClassesDirty(WC_TRACE_RESTRICT_SLOTS); return true; } @@ -2619,8 +2616,6 @@ static bool CheckTrainStayInDepot(Train *v) seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner); if (seg_state == SIGSEG_FULL || HasDepotReservation(v->tile)) { /* Full and no PBS signal in block or depot reserved, can't exit. */ - SetWindowClassesDirty(WC_TRAINS_LIST); - SetWindowClassesDirty(WC_TRACE_RESTRICT_SLOTS); return true; } } else { @@ -2684,8 +2679,6 @@ static bool CheckTrainStayInDepot(Train *v) /* Only leave when we can reserve a path to our destination. */ if (seg_state == SIGSEG_PBS && !TryPathReserve(v) && v->force_proceed == TFP_NONE) { /* No path and no force proceed. */ - SetWindowClassesDirty(WC_TRAINS_LIST); - SetWindowClassesDirty(WC_TRACE_RESTRICT_SLOTS); MarkTrainAsStuck(v); return true; } @@ -2694,8 +2687,7 @@ static bool CheckTrainStayInDepot(Train *v) if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile, VMDF_NOT_MAP_MODE); VehicleServiceInDepot(v); - SetWindowClassesDirty(WC_TRAINS_LIST); - SetWindowClassesDirty(WC_TRACE_RESTRICT_SLOTS); + DirtyVehicleListWindowForVehicle(v); v->PlayLeaveStationSound(); v->track = TRACK_BIT_X; @@ -5244,8 +5236,7 @@ void Train::OnNewDay() SubtractMoneyFromCompanyFract(this->owner, cost); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); - SetWindowClassesDirty(WC_TRAINS_LIST); - SetWindowClassesDirty(WC_TRACE_RESTRICT_SLOTS); + DirtyVehicleListWindowForVehicle(this); } } if (IsEngine() || IsMultiheaded()) { diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 19f2362ce2..32c4a3a3d1 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2172,8 +2172,6 @@ void VehicleEnterDepot(Vehicle *v) switch (v->type) { case VEH_TRAIN: { Train *t = Train::From(v); - SetWindowClassesDirty(WC_TRAINS_LIST); - SetWindowClassesDirty(WC_TRACE_RESTRICT_SLOTS); /* Clear path reservation */ SetDepotReservation(t->tile, false); if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile, VMDF_NOT_MAP_MODE); @@ -2188,11 +2186,9 @@ void VehicleEnterDepot(Vehicle *v) } case VEH_ROAD: - SetWindowClassesDirty(WC_ROADVEH_LIST); break; case VEH_SHIP: { - SetWindowClassesDirty(WC_SHIPS_LIST); Ship *ship = Ship::From(v); ship->state = TRACK_BIT_DEPOT; ship->UpdateCache(); @@ -2202,12 +2198,12 @@ void VehicleEnterDepot(Vehicle *v) } case VEH_AIRCRAFT: - SetWindowClassesDirty(WC_AIRCRAFT_LIST); HandleAircraftEnterHangar(Aircraft::From(v)); break; default: NOT_REACHED(); } SetWindowDirty(WC_VEHICLE_VIEW, v->index); + DirtyVehicleListWindowForVehicle(v); if (v->type != VEH_TRAIN) { /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters. @@ -2935,7 +2931,7 @@ void Vehicle::BeginLoading() PrepareUnload(this); } - SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner); + DirtyVehicleListWindowForVehicle(this); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); SetWindowDirty(WC_STATION_VIEW, this->last_station_visited); diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 23fe050cdc..2c64897f94 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -659,7 +659,7 @@ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, v->MarkDirty(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); - SetWindowClassesDirty(GetWindowClassForVehicleType(v->type)); + DirtyVehicleListWindowForVehicle(v); InvalidateWindowData(WC_VEHICLE_VIEW, v->index); } return CommandCost(); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index f670574615..b137921efd 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2287,6 +2287,24 @@ void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileInde ShowVehicleListWindowLocal(company, VL_DEPOT_LIST, vehicle_type, depot_airport_index); } +void DirtyVehicleListWindowForVehicle(const Vehicle *v) +{ + WindowClass cls = static_cast(WC_TRAINS_LIST + v->type); + WindowClass cls2 = (v->type == VEH_TRAIN) ? WC_TRACE_RESTRICT_SLOTS : cls; + Window *w; + FOR_ALL_WINDOWS_FROM_BACK(w) { + if (w->window_class == cls || w->window_class == cls2) { + BaseVehicleListWindow *listwin = static_cast(w); + uint max = min(listwin->vscroll->GetPosition() + listwin->vscroll->GetCapacity(), (uint)listwin->vehicles.size()); + for (uint i = listwin->vscroll->GetPosition(); i < max; ++i) { + if (v == listwin->vehicles[i]) { + listwin->SetWidgetDirty(0); + break; + } + } + } + } +} /* Unified vehicle GUI - Vehicle Details Window */ diff --git a/src/vehicle_gui.h b/src/vehicle_gui.h index 84e51a39a8..9ec0246c3a 100644 --- a/src/vehicle_gui.h +++ b/src/vehicle_gui.h @@ -61,6 +61,8 @@ void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type); void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station); void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile); +void DirtyVehicleListWindowForVehicle(const Vehicle *v); + /** * Get the height of a single vehicle in the GUIs. * @param type the vehicle type to look at diff --git a/src/widgets/group_widget.h b/src/widgets/group_widget.h index e98eea2a12..531ec18ebd 100644 --- a/src/widgets/group_widget.h +++ b/src/widgets/group_widget.h @@ -12,12 +12,12 @@ /** Widgets of the #VehicleGroupWindow class. */ enum GroupListWidgets { + WID_GL_LIST_VEHICLE, ///< List of the vehicles, this must be first, see: DirtyVehicleListWindowForVehicle WID_GL_CAPTION, ///< Caption of the window. WID_GL_SORT_BY_ORDER, ///< Sort order. WID_GL_SORT_BY_DROPDOWN, ///< Sort by dropdown list. WID_GL_FILTER_BY_CARGO, ///< Filter vehicle by cargo type. WID_GL_FILTER_BY_CARGO_SEL, ///< Filter vehicle by cargo type panel selector. - WID_GL_LIST_VEHICLE, ///< List of the vehicles. WID_GL_LIST_VEHICLE_SCROLLBAR, ///< Scrollbar for the list. WID_GL_AVAILABLE_VEHICLES, ///< Available vehicles. WID_GL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. diff --git a/src/widgets/vehicle_widget.h b/src/widgets/vehicle_widget.h index 6079cc3251..9ecb9e466c 100644 --- a/src/widgets/vehicle_widget.h +++ b/src/widgets/vehicle_widget.h @@ -60,12 +60,12 @@ enum VehicleDetailsWidgets { /** Widgets of the #VehicleListWindow class. */ enum VehicleListWidgets { + WID_VL_LIST, ///< List of the vehicles, this must be first, see: DirtyVehicleListWindowForVehicle WID_VL_CAPTION, ///< Caption of window. 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. WID_VL_AVAILABLE_VEHICLES, ///< Available vehicles.