OpenTTD Source  20241108-master-g80f628063a
vehicle_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "company_func.h"
13 #include "gui.h"
14 #include "textbuf_gui.h"
15 #include "command_func.h"
16 #include "vehicle_gui_base.h"
17 #include "viewport_func.h"
18 #include "newgrf_text.h"
19 #include "newgrf_debug.h"
20 #include "roadveh.h"
21 #include "train.h"
22 #include "aircraft.h"
23 #include "depot_map.h"
24 #include "group_gui.h"
25 #include "strings_func.h"
26 #include "vehicle_func.h"
27 #include "autoreplace_gui.h"
28 #include "string_func.h"
29 #include "dropdown_type.h"
30 #include "dropdown_func.h"
31 #include "timetable.h"
32 #include "articulated_vehicles.h"
33 #include "spritecache.h"
34 #include "core/geometry_func.hpp"
35 #include "core/container_func.hpp"
36 #include "company_base.h"
37 #include "engine_func.h"
38 #include "station_base.h"
39 #include "tilehighlight_func.h"
40 #include "zoom_func.h"
41 #include "depot_cmd.h"
42 #include "vehicle_cmd.h"
43 #include "order_cmd.h"
44 #include "roadveh_cmd.h"
45 #include "train_cmd.h"
46 #include "hotkeys.h"
47 #include "group_cmd.h"
48 
49 #include "safeguards.h"
50 
51 
52 BaseVehicleListWindow::GroupBy _grouping[VLT_END][VEH_COMPANY_END];
53 Sorting _sorting[BaseVehicleListWindow::GB_END];
54 
55 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleNumberSorter;
56 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleNameSorter;
57 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleAgeSorter;
58 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleProfitThisYearSorter;
59 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleProfitLastYearSorter;
60 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleCargoSorter;
61 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleReliabilitySorter;
62 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleMaxSpeedSorter;
63 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleModelSorter;
64 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleValueSorter;
65 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleLengthSorter;
66 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleTimeToLiveSorter;
67 static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleTimetableDelaySorter;
68 static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupLengthSorter;
69 static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupTotalProfitThisYearSorter;
70 static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupTotalProfitLastYearSorter;
71 static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupAverageProfitThisYearSorter;
72 static BaseVehicleListWindow::VehicleGroupSortFunction VehicleGroupAverageProfitLastYearSorter;
73 
75 template <BaseVehicleListWindow::VehicleIndividualSortFunction func>
77 {
78  return func(*(a.vehicles_begin), *(b.vehicles_begin));
79 }
80 
81 const std::initializer_list<BaseVehicleListWindow::VehicleGroupSortFunction * const> BaseVehicleListWindow::vehicle_group_none_sorter_funcs = {
82  &VehicleIndividualToGroupSorterWrapper<VehicleNumberSorter>,
83  &VehicleIndividualToGroupSorterWrapper<VehicleNameSorter>,
84  &VehicleIndividualToGroupSorterWrapper<VehicleAgeSorter>,
85  &VehicleIndividualToGroupSorterWrapper<VehicleProfitThisYearSorter>,
86  &VehicleIndividualToGroupSorterWrapper<VehicleProfitLastYearSorter>,
87  &VehicleIndividualToGroupSorterWrapper<VehicleCargoSorter>,
88  &VehicleIndividualToGroupSorterWrapper<VehicleReliabilitySorter>,
89  &VehicleIndividualToGroupSorterWrapper<VehicleMaxSpeedSorter>,
90  &VehicleIndividualToGroupSorterWrapper<VehicleModelSorter>,
91  &VehicleIndividualToGroupSorterWrapper<VehicleValueSorter>,
92  &VehicleIndividualToGroupSorterWrapper<VehicleLengthSorter>,
93  &VehicleIndividualToGroupSorterWrapper<VehicleTimeToLiveSorter>,
94  &VehicleIndividualToGroupSorterWrapper<VehicleTimetableDelaySorter>,
95 };
96 
97 const std::initializer_list<const StringID> BaseVehicleListWindow::vehicle_group_none_sorter_names_calendar = {
98  STR_SORT_BY_NUMBER,
99  STR_SORT_BY_NAME,
100  STR_SORT_BY_AGE,
101  STR_SORT_BY_PROFIT_THIS_YEAR,
102  STR_SORT_BY_PROFIT_LAST_YEAR,
103  STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
104  STR_SORT_BY_RELIABILITY,
105  STR_SORT_BY_MAX_SPEED,
106  STR_SORT_BY_MODEL,
107  STR_SORT_BY_VALUE,
108  STR_SORT_BY_LENGTH,
109  STR_SORT_BY_LIFE_TIME,
110  STR_SORT_BY_TIMETABLE_DELAY,
111 };
112 
113 const std::initializer_list<const StringID> BaseVehicleListWindow::vehicle_group_none_sorter_names_wallclock = {
114  STR_SORT_BY_NUMBER,
115  STR_SORT_BY_NAME,
116  STR_SORT_BY_AGE,
117  STR_SORT_BY_PROFIT_THIS_PERIOD,
118  STR_SORT_BY_PROFIT_LAST_PERIOD,
119  STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
120  STR_SORT_BY_RELIABILITY,
121  STR_SORT_BY_MAX_SPEED,
122  STR_SORT_BY_MODEL,
123  STR_SORT_BY_VALUE,
124  STR_SORT_BY_LENGTH,
125  STR_SORT_BY_LIFE_TIME,
126  STR_SORT_BY_TIMETABLE_DELAY,
127 };
128 
129 const std::initializer_list<BaseVehicleListWindow::VehicleGroupSortFunction * const> BaseVehicleListWindow::vehicle_group_shared_orders_sorter_funcs = {
135 };
136 
137 const std::initializer_list<const StringID> BaseVehicleListWindow::vehicle_group_shared_orders_sorter_names_calendar = {
138  STR_SORT_BY_NUM_VEHICLES,
139  STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR,
140  STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR,
141  STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR,
142  STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR,
143 };
144 
145 const std::initializer_list<const StringID> BaseVehicleListWindow::vehicle_group_shared_orders_sorter_names_wallclock = {
146  STR_SORT_BY_NUM_VEHICLES,
147  STR_SORT_BY_TOTAL_PROFIT_THIS_PERIOD,
148  STR_SORT_BY_TOTAL_PROFIT_LAST_PERIOD,
149  STR_SORT_BY_AVERAGE_PROFIT_THIS_PERIOD,
150  STR_SORT_BY_AVERAGE_PROFIT_LAST_PERIOD,
151 };
152 
153 const std::initializer_list<const StringID> BaseVehicleListWindow::vehicle_group_by_names = {
154  STR_GROUP_BY_NONE,
155  STR_GROUP_BY_SHARED_ORDERS,
156 };
157 
158 const StringID BaseVehicleListWindow::vehicle_depot_name[] = {
159  STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT,
160  STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT,
161  STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT,
162  STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR
163 };
164 
165 BaseVehicleListWindow::BaseVehicleListWindow(WindowDesc &desc, WindowNumber wno) : Window(desc), vli(VehicleListIdentifier::UnPack(wno))
166 {
167  this->vehicle_sel = INVALID_VEHICLE;
168  this->grouping = _grouping[vli.type][vli.vtype];
169  this->UpdateSortingFromGrouping();
170 }
171 
172 std::span<const StringID> BaseVehicleListWindow::GetVehicleSorterNames()
173 {
174  switch (this->grouping) {
175  case GB_NONE:
176  return TimerGameEconomy::UsingWallclockUnits() ? vehicle_group_none_sorter_names_wallclock : vehicle_group_none_sorter_names_calendar;
177  case GB_SHARED_ORDERS:
178  return TimerGameEconomy::UsingWallclockUnits() ? vehicle_group_shared_orders_sorter_names_wallclock : vehicle_group_shared_orders_sorter_names_calendar;
179  default:
180  NOT_REACHED();
181  }
182 }
183 
190 {
191  if (number >= 10000) return 5;
192  if (number >= 1000) return 4;
193  if (number >= 100) return 3;
194 
195  /*
196  * When the smallest unit number is less than 10, it is
197  * quite likely that it will expand to become more than
198  * 10 quite soon.
199  */
200  return 2;
201 }
202 
209 {
210  uint unitnumber = 0;
211  for (const Vehicle *v : vehicles) {
212  unitnumber = std::max<uint>(unitnumber, v->unitnumber);
213  }
214 
215  return CountDigitsForAllocatingSpace(unitnumber);
216 }
217 
218 void BaseVehicleListWindow::BuildVehicleList()
219 {
220  if (!this->vehgroups.NeedRebuild()) return;
221 
222  Debug(misc, 3, "Building vehicle list type {} for company {} given index {}", this->vli.type, this->vli.company, this->vli.index);
223 
224  this->vehgroups.clear();
225 
226  GenerateVehicleSortList(&this->vehicles, this->vli);
227 
228  CargoTypes used = 0;
229  for (const Vehicle *v : this->vehicles) {
230  for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
231  if (u->cargo_cap > 0) SetBit(used, u->cargo_type);
232  }
233  }
234  this->used_cargoes = used;
235 
236  if (this->grouping == GB_NONE) {
237  uint max_unitnumber = 0;
238  for (auto it = this->vehicles.begin(); it != this->vehicles.end(); ++it) {
239  this->vehgroups.emplace_back(it, it + 1);
240 
241  max_unitnumber = std::max<uint>(max_unitnumber, (*it)->unitnumber);
242  }
243  this->unitnumber_digits = CountDigitsForAllocatingSpace(max_unitnumber);
244  } else {
245  /* Sort by the primary vehicle; we just want all vehicles that share the same orders to form a contiguous range. */
246  std::stable_sort(this->vehicles.begin(), this->vehicles.end(), [](const Vehicle * const &u, const Vehicle * const &v) {
247  return u->FirstShared() < v->FirstShared();
248  });
249 
250  uint max_num_vehicles = 0;
251 
252  VehicleList::const_iterator begin = this->vehicles.begin();
253  while (begin != this->vehicles.end()) {
254  VehicleList::const_iterator end = std::find_if_not(begin, this->vehicles.cend(), [first_shared = (*begin)->FirstShared()](const Vehicle * const &v) {
255  return v->FirstShared() == first_shared;
256  });
257 
258  this->vehgroups.emplace_back(begin, end);
259 
260  max_num_vehicles = std::max<uint>(max_num_vehicles, static_cast<uint>(end - begin));
261 
262  begin = end;
263  }
264 
265  this->unitnumber_digits = CountDigitsForAllocatingSpace(max_num_vehicles);
266  }
267  this->FilterVehicleList();
268 
269  this->vehgroups.RebuildDone();
270  this->vscroll->SetCount(this->vehgroups.size());
271 }
272 
280 static bool CargoFilterSingle(const Vehicle *v, const CargoID cid)
281 {
282  if (cid == CargoFilterCriteria::CF_ANY) {
283  return true;
284  } else if (cid == CargoFilterCriteria::CF_NONE) {
285  for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
286  if (w->cargo_cap > 0) {
287  return false;
288  }
289  }
290  return true;
291  } else if (cid == CargoFilterCriteria::CF_FREIGHT) {
292  bool have_capacity = false;
293  for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
294  if (w->cargo_cap > 0) {
295  if (IsCargoInClass(w->cargo_type, CC_PASSENGERS)) {
296  return false;
297  } else {
298  have_capacity = true;
299  }
300  }
301  }
302  return have_capacity;
303  } else {
304  for (const Vehicle *w = v; w != nullptr; w = w->Next()) {
305  if (w->cargo_cap > 0 && w->cargo_type == cid) {
306  return true;
307  }
308  }
309  return false;
310  }
311 }
312 
320 static bool CargoFilter(const GUIVehicleGroup *vehgroup, const CargoID cid)
321 {
322  auto it = vehgroup->vehicles_begin;
323 
324  /* Check if any vehicle in the group matches; if so, the whole group does. */
325  for (; it != vehgroup->vehicles_end; it++) {
326  if (CargoFilterSingle(*it, cid)) return true;
327  }
328 
329  return false;
330 }
331 
337 {
338  return _shift_pressed && _ctrl_pressed;
339 }
340 
348 void AddCargoIconOverlay(std::vector<CargoIconOverlay> &overlays, int x, int width, const Vehicle *v)
349 {
350  bool rtl = _current_text_dir == TD_RTL;
351  if (!v->IsArticulatedPart() || v->cargo_type != v->Previous()->cargo_type) {
352  /* Add new overlay slot. */
353  overlays.emplace_back(rtl ? x - width : x, rtl ? x : x + width, v->cargo_type, v->cargo_cap);
354  } else {
355  /* This is an articulated part with the same cargo type, adjust left or right of last overlay slot. */
356  if (rtl) {
357  overlays.back().left -= width;
358  } else {
359  overlays.back().right += width;
360  }
361  overlays.back().cargo_cap += v->cargo_cap;
362  }
363 }
364 
371 void DrawCargoIconOverlay(int x, int y, CargoID cid)
372 {
373  if (!ShowCargoIconOverlay()) return;
374  if (!IsValidCargoID(cid)) return;
375 
376  const CargoSpec *cs = CargoSpec::Get(cid);
377 
378  SpriteID spr = cs->GetCargoIcon();
379  if (spr == 0) return;
380 
381  Dimension d = GetSpriteSize(spr);
382  d.width /= 2;
383  d.height /= 2;
384  int one = ScaleGUITrad(1);
385 
386  /* Draw the cargo icon in black shifted 4 times to create the outline. */
387  DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width - one, y - d.height);
388  DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width + one, y - d.height);
389  DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width, y - d.height - one);
390  DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width, y - d.height + one);
391  /* Draw the cargo icon normally. */
392  DrawSprite(spr, PAL_NONE, x - d.width, y - d.height);
393 }
394 
400 void DrawCargoIconOverlays(std::span<const CargoIconOverlay> overlays, int y)
401 {
402  for (const auto &cio : overlays) {
403  if (cio.cargo_cap == 0) continue;
404  DrawCargoIconOverlay((cio.left + cio.right) / 2, y, cio.cargo_type);
405  }
406 }
407 
408 static GUIVehicleGroupList::FilterFunction * const _vehicle_group_filter_funcs[] = {
409  &CargoFilter,
410 };
411 
417 {
418  if (this->cargo_filter_criteria != cid) {
419  this->cargo_filter_criteria = cid;
420  /* Deactivate filter if criteria is 'Show All', activate it otherwise. */
422  this->vehgroups.SetFilterType(0);
423  this->vehgroups.ForceRebuild();
424  }
425 }
426 
431 {
433  this->vehgroups.SetFilterFuncs(_vehicle_group_filter_funcs);
435 }
436 
441 {
443  if (this->vehicles.empty()) {
444  /* No vehicle passed through the filter, invalidate the previously selected vehicle */
446  } 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
448  }
449 }
450 
458 Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group, bool show_create)
459 {
460  Dimension d = {0, 0};
461 
462  if (show_autoreplace) d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_REPLACE_VEHICLES));
463  d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_SEND_FOR_SERVICING));
464  d = maxdim(d, GetStringBoundingBox(this->vehicle_depot_name[this->vli.vtype]));
465 
466  if (show_group) {
467  d = maxdim(d, GetStringBoundingBox(STR_GROUP_ADD_SHARED_VEHICLE));
468  d = maxdim(d, GetStringBoundingBox(STR_GROUP_REMOVE_ALL_VEHICLES));
469  } else if (show_create) {
470  d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_CREATE_GROUP));
471  }
472 
473  return d;
474 }
475 
477 {
478  this->order_arrow_width = GetStringBoundingBox(STR_JUST_RIGHT_ARROW, FS_SMALL).width;
479  this->SetCargoFilterArray();
480 }
481 
482 StringID BaseVehicleListWindow::GetCargoFilterLabel(CargoID cid) const
483 {
484  switch (cid) {
485  case CargoFilterCriteria::CF_ANY: return STR_CARGO_TYPE_FILTER_ALL;
486  case CargoFilterCriteria::CF_FREIGHT: return STR_CARGO_TYPE_FILTER_FREIGHT;
487  case CargoFilterCriteria::CF_NONE: return STR_CARGO_TYPE_FILTER_NONE;
488  default: return CargoSpec::Get(cid)->name;
489  }
490 }
491 
498 {
499  DropDownList list;
500 
501  /* Add item for disabling filtering. */
502  list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY));
503  /* Add item for freight (i.e. vehicles with cargo capacity and with no passenger capacity). */
504  list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_FREIGHT), CargoFilterCriteria::CF_FREIGHT));
505  /* Add item for vehicles not carrying anything, e.g. train engines. */
506  list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE));
507 
508  /* Add cargos */
510  for (const CargoSpec *cs : _sorted_cargo_specs) {
511  if (!full && !HasBit(this->used_cargoes, cs->Index())) continue;
512  list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index(), false, !HasBit(this->used_cargoes, cs->Index())));
513  }
514 
515  return list;
516 }
517 
525 DropDownList BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group, bool show_create)
526 {
527  DropDownList list;
528 
529  /* Autoreplace actions. */
530  if (show_autoreplace) {
531  list.push_back(MakeDropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE));
532  list.push_back(MakeDropDownListDividerItem());
533  }
534 
535  /* Group actions. */
536  if (show_group) {
537  list.push_back(MakeDropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, ADI_ADD_SHARED));
538  list.push_back(MakeDropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL));
539  list.push_back(MakeDropDownListDividerItem());
540  } else if (show_create) {
541  list.push_back(MakeDropDownListStringItem(STR_VEHICLE_LIST_CREATE_GROUP, ADI_CREATE_GROUP));
542  list.push_back(MakeDropDownListDividerItem());
543  }
544 
545  /* Depot actions. */
546  list.push_back(MakeDropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE));
547  list.push_back(MakeDropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT));
548 
549  return list;
550 }
551 
552 /* cached values for VehicleNameSorter to spare many GetString() calls */
553 static const Vehicle *_last_vehicle[2] = { nullptr, nullptr };
554 
555 void BaseVehicleListWindow::SortVehicleList()
556 {
557  if (this->vehgroups.Sort()) return;
558 
559  /* invalidate cached values for name sorter - vehicle names could change */
560  _last_vehicle[0] = _last_vehicle[1] = nullptr;
561 }
562 
563 void DepotSortList(VehicleList *list)
564 {
565  if (list->size() < 2) return;
566  std::sort(list->begin(), list->end(), &VehicleNumberSorter);
567 }
568 
570 static void DrawVehicleProfitButton(TimerGameEconomy::Date age, Money display_profit_last_year, uint num_vehicles, int x, int y)
571 {
572  SpriteID spr;
573 
574  /* draw profit-based coloured icons */
575  if (age <= VEHICLE_PROFIT_MIN_AGE) {
576  spr = SPR_PROFIT_NA;
577  } else if (display_profit_last_year < 0) {
578  spr = SPR_PROFIT_NEGATIVE;
579  } else if (display_profit_last_year < VEHICLE_PROFIT_THRESHOLD * num_vehicles) {
580  spr = SPR_PROFIT_SOME;
581  } else {
582  spr = SPR_PROFIT_LOT;
583  }
584  DrawSprite(spr, PAL_NONE, x, y);
585 }
586 
588 static const uint MAX_REFIT_CYCLE = 256;
589 
599 uint8_t GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type)
600 {
601  v_from = v_from->GetFirstEnginePart();
602  v_for = v_for->GetFirstEnginePart();
603 
604  /* Create a list of subtypes used by the various parts of v_for */
605  static std::vector<StringID> subtypes;
606  subtypes.clear();
607  for (; v_from != nullptr; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : nullptr) {
608  const Engine *e_from = v_from->GetEngine();
609  if (!e_from->CanCarryCargo() || !HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue;
610  include(subtypes, GetCargoSubtypeText(v_from));
611  }
612 
613  uint8_t ret_refit_cyc = 0;
614  bool success = false;
615  if (!subtypes.empty()) {
616  /* Check whether any articulated part is refittable to 'dest_cargo_type' with a subtype listed in 'subtypes' */
617  for (Vehicle *v = v_for; v != nullptr; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr) {
618  const Engine *e = v->GetEngine();
619  if (!e->CanCarryCargo() || !HasBit(e->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue;
620  if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue;
621 
622  CargoID old_cargo_type = v->cargo_type;
623  uint8_t old_cargo_subtype = v->cargo_subtype;
624 
625  /* Set the 'destination' cargo */
626  v->cargo_type = dest_cargo_type;
627 
628  /* Cycle through the refits */
629  for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) {
630  v->cargo_subtype = refit_cyc;
631 
632  /* Make sure we don't pick up anything cached. */
633  v->First()->InvalidateNewGRFCache();
634  v->InvalidateNewGRFCache();
635 
636  StringID subtype = GetCargoSubtypeText(v);
637  if (subtype == STR_EMPTY) break;
638 
639  if (std::find(subtypes.begin(), subtypes.end(), subtype) == subtypes.end()) continue;
640 
641  /* We found something matching. */
642  ret_refit_cyc = refit_cyc;
643  success = true;
644  break;
645  }
646 
647  /* Reset the vehicle's cargo type */
648  v->cargo_type = old_cargo_type;
649  v->cargo_subtype = old_cargo_subtype;
650 
651  /* Make sure we don't taint the vehicle. */
652  v->First()->InvalidateNewGRFCache();
653  v->InvalidateNewGRFCache();
654 
655  if (success) break;
656  }
657  }
658 
659  return ret_refit_cyc;
660 }
661 
663 struct RefitOption {
665  uint8_t subtype;
667 
673  inline bool operator != (const RefitOption &other) const
674  {
675  return other.cargo != this->cargo || other.string != this->string;
676  }
677 
683  inline bool operator == (const RefitOption &other) const
684  {
685  return other.cargo == this->cargo && other.string == this->string;
686  }
687 };
688 
689 using RefitOptions = std::map<CargoID, std::vector<RefitOption>, CargoIDComparator>;
690 
700 static void DrawVehicleRefitWindow(const RefitOptions &refits, const RefitOption *sel, uint pos, uint rows, uint delta, const Rect &r)
701 {
702  Rect ir = r.Shrink(WidgetDimensions::scaled.matrix);
703  uint current = 0;
704 
705  bool rtl = _current_text_dir == TD_RTL;
706  uint iconwidth = std::max(GetSpriteSize(SPR_CIRCLE_FOLDED).width, GetSpriteSize(SPR_CIRCLE_UNFOLDED).width);
707  uint iconheight = GetSpriteSize(SPR_CIRCLE_FOLDED).height;
708  int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
709 
710  int iconleft = rtl ? ir.right - iconwidth : ir.left;
711  int iconcenter = rtl ? ir.right - iconwidth / 2 : ir.left + iconwidth / 2;
712  int iconinner = rtl ? ir.right - iconwidth : ir.left + iconwidth;
713 
714  Rect tr = ir.Indent(iconwidth + WidgetDimensions::scaled.hsep_wide, rtl);
715 
716  /* Draw the list of subtypes for each cargo, and find the selected refit option (by its position). */
717  for (const auto &pair : refits) {
718  bool has_subtypes = pair.second.size() > 1;
719  for (const RefitOption &refit : pair.second) {
720  if (current >= pos + rows) break;
721 
722  /* Hide subtypes if selected cargo type does not match */
723  if ((sel == nullptr || sel->cargo != refit.cargo) && refit.subtype != UINT8_MAX) continue;
724 
725  /* Refit options with a position smaller than pos don't have to be drawn. */
726  if (current < pos) {
727  current++;
728  continue;
729  }
730 
731  if (has_subtypes) {
732  if (refit.subtype != UINT8_MAX) {
733  /* Draw tree lines */
734  int ycenter = tr.top + GetCharacterHeight(FS_NORMAL) / 2;
735  GfxDrawLine(iconcenter, tr.top - WidgetDimensions::scaled.matrix.top, iconcenter, (&refit == &pair.second.back()) ? ycenter : tr.top - WidgetDimensions::scaled.matrix.top + delta - 1, linecolour);
736  GfxDrawLine(iconcenter, ycenter, iconinner, ycenter, linecolour);
737  } else {
738  /* Draw expand/collapse icon */
739  DrawSprite((sel != nullptr && sel->cargo == refit.cargo) ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED, PAL_NONE, iconleft, tr.top + (GetCharacterHeight(FS_NORMAL) - iconheight) / 2);
740  }
741  }
742 
743  TextColour colour = (sel != nullptr && sel->cargo == refit.cargo && sel->subtype == refit.subtype) ? TC_WHITE : TC_BLACK;
744  /* Get the cargo name. */
745  SetDParam(0, CargoSpec::Get(refit.cargo)->name);
746  SetDParam(1, refit.string);
747  DrawString(tr, STR_JUST_STRING_STRING, colour);
748 
749  tr.top += delta;
750  current++;
751  }
752  }
753 }
754 
756 struct RefitWindow : public Window {
767  int click_x;
769  uint8_t num_vehicles;
770  bool auto_refit;
771 
776  {
777  /* Store the currently selected RefitOption. */
778  std::optional<RefitOption> current_refit_option;
779  if (this->selected_refit != nullptr) current_refit_option = *(this->selected_refit);
780  this->selected_refit = nullptr;
781 
782  this->refit_list.clear();
783  Vehicle *v = Vehicle::Get(this->window_number);
784 
785  /* Check only the selected vehicles. */
786  VehicleSet vehicles_to_refit;
787  GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles);
788 
789  do {
790  if (v->type == VEH_TRAIN && std::find(vehicles_to_refit.begin(), vehicles_to_refit.end(), v->index) == vehicles_to_refit.end()) continue;
791  const Engine *e = v->GetEngine();
792  CargoTypes cmask = e->info.refit_mask;
793  uint8_t callback_mask = e->info.callback_mask;
794 
795  /* Skip this engine if it does not carry anything */
796  if (!e->CanCarryCargo()) continue;
797  /* Skip this engine if we build the list for auto-refitting and engine doesn't allow it. */
798  if (this->auto_refit && !HasBit(e->info.misc_flags, EF_AUTO_REFIT)) continue;
799 
800  /* Loop through all cargoes in the refit mask */
801  for (const auto &cs : _sorted_cargo_specs) {
802  CargoID cid = cs->Index();
803  /* Skip cargo type if it's not listed */
804  if (!HasBit(cmask, cid)) continue;
805 
806  auto &list = this->refit_list[cid];
807  bool first_vehicle = list.empty();
808  if (first_vehicle) {
809  /* Keeping the current subtype is always an option. It also serves as the option in case of no subtypes */
810  list.push_back({cid, UINT8_MAX, STR_EMPTY});
811  }
812 
813  /* Check the vehicle's callback mask for cargo suffixes.
814  * This is not supported for ordered refits, since subtypes only have a meaning
815  * for a specific vehicle at a specific point in time, which conflicts with shared orders,
816  * autoreplace, autorenew, clone, order restoration, ... */
817  if (this->order == INVALID_VEH_ORDER_ID && HasBit(callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) {
818  /* Make a note of the original cargo type. It has to be
819  * changed to test the cargo & subtype... */
820  CargoID temp_cargo = v->cargo_type;
821  uint8_t temp_subtype = v->cargo_subtype;
822 
823  v->cargo_type = cid;
824 
825  for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) {
826  v->cargo_subtype = refit_cyc;
827 
828  /* Make sure we don't pick up anything cached. */
831 
832  StringID subtype = GetCargoSubtypeText(v);
833 
834  if (first_vehicle) {
835  /* Append new subtype (don't add duplicates though) */
836  if (subtype == STR_EMPTY) break;
837 
838  RefitOption option;
839  option.cargo = cid;
840  option.subtype = refit_cyc;
841  option.string = subtype;
842  include(list, option);
843  } else {
844  /* Intersect the subtypes of earlier vehicles with the subtypes of this vehicle */
845  if (subtype == STR_EMPTY) {
846  /* No more subtypes for this vehicle, delete all subtypes >= refit_cyc */
847  /* UINT8_MAX item is in front, other subtypes are sorted. So just truncate the list in the right spot */
848  for (uint i = 1; i < list.size(); i++) {
849  if (list[i].subtype >= refit_cyc) {
850  list.resize(i);
851  break;
852  }
853  }
854  break;
855  } else {
856  /* Check whether the subtype matches with the subtype of earlier vehicles. */
857  uint pos = 1;
858  while (pos < list.size() && list[pos].subtype != refit_cyc) pos++;
859  if (pos < list.size() && list[pos].string != subtype) {
860  /* String mismatch, remove item keeping the order */
861  list.erase(list.begin() + pos);
862  }
863  }
864  }
865  }
866 
867  /* Reset the vehicle's cargo type */
868  v->cargo_type = temp_cargo;
869  v->cargo_subtype = temp_subtype;
870 
871  /* And make sure we haven't tainted the cache */
874  }
875  }
876  } while (v->IsGroundVehicle() && (v = v->Next()) != nullptr);
877 
878  /* Restore the previously selected RefitOption. */
879  if (current_refit_option.has_value()) {
880  for (const auto &pair : this->refit_list) {
881  for (const auto &refit : pair.second) {
882  if (refit.cargo == current_refit_option->cargo && refit.subtype == current_refit_option->subtype) {
883  this->selected_refit = &refit;
884  break;
885  }
886  }
887  if (this->selected_refit != nullptr) break;
888  }
889  }
890 
891  this->SetWidgetDisabledState(WID_VR_REFIT, this->selected_refit == nullptr);
892  }
893 
898  {
899  size_t scroll_row = 0;
900  size_t rows = 0;
901  CargoID cargo = this->selected_refit == nullptr ? INVALID_CARGO : this->selected_refit->cargo;
902 
903  for (const auto &pair : this->refit_list) {
904  if (pair.first == cargo) {
905  /* selected_refit points to an element in the vector so no need to search for it. */
906  scroll_row = rows + (this->selected_refit - pair.second.data());
907  rows += pair.second.size();
908  } else {
909  rows++; /* Unselected cargo type is collapsed into one row. */
910  }
911  }
912 
913  this->vscroll->SetCount(rows);
914  this->vscroll->ScrollTowards(static_cast<int>(scroll_row));
915  }
916 
921  void SetSelection(uint click_row)
922  {
923  uint row = 0;
924 
925  for (const auto &pair : refit_list) {
926  for (const RefitOption &refit : pair.second) {
927  if (row == click_row) {
928  this->selected_refit = &refit;
929  return;
930  }
931  row++;
932  /* If this cargo type is not already selected then its subtypes are not visible, so skip the rest. */
933  if (this->selected_refit == nullptr || this->selected_refit->cargo != refit.cargo) break;
934  }
935  }
936 
937  /* No selection made */
938  this->selected_refit = nullptr;
939  }
940 
941  RefitWindow(WindowDesc &desc, const Vehicle *v, VehicleOrderID order, bool auto_refit) : Window(desc)
942  {
943  this->auto_refit = auto_refit;
944  this->order = order;
945  this->CreateNestedTree();
946 
947  this->vscroll = this->GetScrollbar(WID_VR_SCROLLBAR);
948  this->hscroll = (v->IsGroundVehicle() ? this->GetScrollbar(WID_VR_HSCROLLBAR) : nullptr);
949  this->GetWidget<NWidgetCore>(WID_VR_SELECT_HEADER)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type;
950  this->GetWidget<NWidgetCore>(WID_VR_MATRIX)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type;
951  NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_VR_REFIT);
952  nwi->widget_data = STR_REFIT_TRAIN_REFIT_BUTTON + v->type;
953  nwi->tool_tip = STR_REFIT_TRAIN_REFIT_TOOLTIP + v->type;
954  this->GetWidget<NWidgetStacked>(WID_VR_SHOW_HSCROLLBAR)->SetDisplayedPlane(v->IsGroundVehicle() ? 0 : SZSP_HORIZONTAL);
955  this->GetWidget<NWidgetCore>(WID_VR_VEHICLE_PANEL_DISPLAY)->tool_tip = (v->type == VEH_TRAIN) ? STR_REFIT_SELECT_VEHICLES_TOOLTIP : STR_NULL;
956 
957  this->FinishInitNested(v->index);
958  this->owner = v->owner;
959 
960  this->SetWidgetDisabledState(WID_VR_REFIT, this->selected_refit == nullptr);
961  }
962 
963  void OnInit() override
964  {
965  /* (Re)build the refit list */
967  }
968 
969  void OnPaint() override
970  {
971  /* Determine amount of items for scroller. */
972  if (this->hscroll != nullptr) this->hscroll->SetCount(this->vehicle_width);
973 
974  /* Calculate sprite position. */
975  NWidgetCore *vehicle_panel_display = this->GetWidget<NWidgetCore>(WID_VR_VEHICLE_PANEL_DISPLAY);
976  int sprite_width = std::max(0, ((int)vehicle_panel_display->current_x - this->vehicle_width) / 2);
977  this->sprite_left = vehicle_panel_display->pos_x;
978  this->sprite_right = vehicle_panel_display->pos_x + vehicle_panel_display->current_x - 1;
979  if (_current_text_dir == TD_RTL) {
980  this->sprite_right -= sprite_width;
981  this->vehicle_margin = vehicle_panel_display->current_x - sprite_right;
982  } else {
983  this->sprite_left += sprite_width;
984  this->vehicle_margin = sprite_left;
985  }
986 
987  this->DrawWidgets();
988  }
989 
990  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
991  {
992  switch (widget) {
993  case WID_VR_MATRIX:
994  resize.height = GetCharacterHeight(FS_NORMAL) + padding.height;
995  size.height = resize.height * 8;
996  break;
997 
999  size.height = ScaleGUITrad(GetVehicleHeight(Vehicle::Get(this->window_number)->type));
1000  break;
1001 
1002  case WID_VR_INFO:
1003  size.width = this->information_width + padding.height;
1004  break;
1005  }
1006  }
1007 
1008  void SetStringParameters(WidgetID widget) const override
1009  {
1010  if (widget == WID_VR_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index);
1011  }
1012 
1020  {
1021  assert(_current_company == _local_company);
1022  auto [cost, refit_capacity, mail_capacity, cargo_capacities] = Command<CMD_REFIT_VEHICLE>::Do(DC_QUERY_COST, this->selected_vehicle, option.cargo, option.subtype, this->auto_refit, false, this->num_vehicles);
1023 
1024  if (cost.Failed()) return INVALID_STRING_ID;
1025 
1026  SetDParam(0, option.cargo);
1027  SetDParam(1, refit_capacity);
1028 
1029  Money money = cost.GetCost();
1030  if (mail_capacity > 0) {
1031  SetDParam(2, GetCargoIDByLabel(CT_MAIL));
1032  SetDParam(3, mail_capacity);
1033  if (this->order != INVALID_VEH_ORDER_ID) {
1034  /* No predictable cost */
1035  return STR_PURCHASE_INFO_AIRCRAFT_CAPACITY;
1036  } else if (money <= 0) {
1037  SetDParam(4, -money);
1038  return STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT;
1039  } else {
1040  SetDParam(4, money);
1041  return STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT;
1042  }
1043  } else {
1044  if (this->order != INVALID_VEH_ORDER_ID) {
1045  /* No predictable cost */
1046  SetDParam(2, STR_EMPTY);
1047  return STR_PURCHASE_INFO_CAPACITY;
1048  } else if (money <= 0) {
1049  SetDParam(2, -money);
1050  return STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT;
1051  } else {
1052  SetDParam(2, money);
1053  return STR_REFIT_NEW_CAPACITY_COST_OF_REFIT;
1054  }
1055  }
1056  }
1057 
1058  void DrawWidget(const Rect &r, WidgetID widget) const override
1059  {
1060  switch (widget) {
1062  Vehicle *v = Vehicle::Get(this->window_number);
1063  DrawVehicleImage(v, {this->sprite_left, r.top, this->sprite_right, r.bottom},
1064  INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != nullptr ? this->hscroll->GetPosition() : 0);
1065 
1066  /* Highlight selected vehicles. */
1067  if (this->order != INVALID_VEH_ORDER_ID) break;
1068  int x = 0;
1069  switch (v->type) {
1070  case VEH_TRAIN: {
1071  VehicleSet vehicles_to_refit;
1072  GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles);
1073 
1074  int left = INT32_MIN;
1075  int width = 0;
1076 
1077  /* Determine top & bottom position of the highlight.*/
1078  const int height = ScaleSpriteTrad(12);
1079  const int highlight_top = CenterBounds(r.top, r.bottom, height);
1080  const int highlight_bottom = highlight_top + height - 1;
1081 
1082  for (Train *u = Train::From(v); u != nullptr; u = u->Next()) {
1083  /* Start checking. */
1084  const bool contained = std::find(vehicles_to_refit.begin(), vehicles_to_refit.end(), u->index) != vehicles_to_refit.end();
1085  if (contained && left == INT32_MIN) {
1086  left = x - this->hscroll->GetPosition() + r.left + this->vehicle_margin;
1087  width = 0;
1088  }
1089 
1090  /* Draw a selection. */
1091  if ((!contained || u->Next() == nullptr) && left != INT32_MIN) {
1092  if (u->Next() == nullptr && contained) {
1093  int current_width = u->GetDisplayImageWidth();
1094  width += current_width;
1095  x += current_width;
1096  }
1097 
1098  int right = Clamp(left + width, 0, r.right);
1099  left = std::max(0, left);
1100 
1101  if (_current_text_dir == TD_RTL) {
1102  right = r.Width() - left;
1103  left = right - width;
1104  }
1105 
1106  if (left != right) {
1107  Rect hr = {left, highlight_top, right, highlight_bottom};
1109  }
1110 
1111  left = INT32_MIN;
1112  }
1113 
1114  int current_width = u->GetDisplayImageWidth();
1115  width += current_width;
1116  x += current_width;
1117  }
1118  break;
1119  }
1120 
1121  default: break;
1122  }
1123  break;
1124  }
1125 
1126  case WID_VR_MATRIX:
1127  DrawVehicleRefitWindow(this->refit_list, this->selected_refit, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->resize.step_height, r);
1128  break;
1129 
1130  case WID_VR_INFO:
1131  if (this->selected_refit != nullptr) {
1132  StringID string = this->GetCapacityString(*this->selected_refit);
1133  if (string != INVALID_STRING_ID) {
1135  }
1136  }
1137  break;
1138  }
1139  }
1140 
1146  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1147  {
1148  switch (data) {
1149  case VIWD_AUTOREPLACE: // Autoreplace replaced the vehicle; selected_vehicle became invalid.
1150  case VIWD_CONSIST_CHANGED: { // The consist has changed; rebuild the entire list.
1151  /* Clear the selection. */
1152  Vehicle *v = Vehicle::Get(this->window_number);
1153  this->selected_vehicle = v->index;
1154  this->num_vehicles = UINT8_MAX;
1155  [[fallthrough]];
1156  }
1157 
1158  case 2: { // The vehicle selection has changed; rebuild the entire list.
1159  if (!gui_scope) break;
1160  this->BuildRefitList();
1161 
1162  /* The vehicle width has changed too. */
1163  this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS);
1164  uint max_width = 0;
1165 
1166  /* Check the width of all cargo information strings. */
1167  for (const auto &list : this->refit_list) {
1168  for (const RefitOption &refit : list.second) {
1169  StringID string = this->GetCapacityString(refit);
1170  if (string != INVALID_STRING_ID) {
1171  Dimension dim = GetStringBoundingBox(string);
1172  max_width = std::max(dim.width, max_width);
1173  }
1174  }
1175  }
1176 
1177  if (this->information_width < max_width) {
1178  this->information_width = max_width;
1179  this->ReInit();
1180  }
1181  [[fallthrough]];
1182  }
1183 
1184  case 1: // A new cargo has been selected.
1185  if (!gui_scope) break;
1186  this->RefreshScrollbar();
1187  break;
1188  }
1189  }
1190 
1191  int GetClickPosition(int click_x)
1192  {
1193  const NWidgetCore *matrix_widget = this->GetWidget<NWidgetCore>(WID_VR_VEHICLE_PANEL_DISPLAY);
1194  if (_current_text_dir == TD_RTL) click_x = matrix_widget->current_x - click_x;
1195  click_x -= this->vehicle_margin;
1196  if (this->hscroll != nullptr) click_x += this->hscroll->GetPosition();
1197 
1198  return click_x;
1199  }
1200 
1201  void SetSelectedVehicles(int drag_x)
1202  {
1203  drag_x = GetClickPosition(drag_x);
1204 
1205  int left_x = std::min(this->click_x, drag_x);
1206  int right_x = std::max(this->click_x, drag_x);
1207  this->num_vehicles = 0;
1208 
1209  Vehicle *v = Vehicle::Get(this->window_number);
1210  /* Find the vehicle part that was clicked. */
1211  switch (v->type) {
1212  case VEH_TRAIN: {
1213  /* Don't select anything if we are not clicking in the vehicle. */
1214  if (left_x >= 0) {
1215  const Train *u = Train::From(v);
1216  bool start_counting = false;
1217  for (; u != nullptr; u = u->Next()) {
1218  int current_width = u->GetDisplayImageWidth();
1219  left_x -= current_width;
1220  right_x -= current_width;
1221 
1222  if (left_x < 0 && !start_counting) {
1223  this->selected_vehicle = u->index;
1224  start_counting = true;
1225 
1226  /* Count the first vehicle, even if articulated part */
1227  this->num_vehicles++;
1228  } else if (start_counting && !u->IsArticulatedPart()) {
1229  /* Do not count articulated parts */
1230  this->num_vehicles++;
1231  }
1232 
1233  if (right_x < 0) break;
1234  }
1235  }
1236 
1237  /* If the selection is not correct, clear it. */
1238  if (this->num_vehicles != 0) {
1239  if (_ctrl_pressed) this->num_vehicles = UINT8_MAX;
1240  break;
1241  }
1242  [[fallthrough]];
1243  }
1244 
1245  default:
1246  /* Clear the selection. */
1247  this->selected_vehicle = v->index;
1248  this->num_vehicles = UINT8_MAX;
1249  break;
1250  }
1251  }
1252 
1253  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1254  {
1255  switch (widget) {
1256  case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image.
1257  if (this->order != INVALID_VEH_ORDER_ID) break;
1258  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_VR_VEHICLE_PANEL_DISPLAY);
1259  this->click_x = GetClickPosition(pt.x - nwi->pos_x);
1260  this->SetSelectedVehicles(pt.x - nwi->pos_x);
1262  if (!_ctrl_pressed) {
1263  SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
1264  } else {
1265  /* The vehicle selection has changed. */
1266  this->InvalidateData(2);
1267  }
1268  break;
1269  }
1270 
1271  case WID_VR_MATRIX: { // listbox
1272  this->SetSelection(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VR_MATRIX));
1273  this->SetWidgetDisabledState(WID_VR_REFIT, this->selected_refit == nullptr);
1274  this->InvalidateData(1);
1275 
1276  if (click_count == 1) break;
1277  [[fallthrough]];
1278  }
1279 
1280  case WID_VR_REFIT: // refit button
1281  if (this->selected_refit != nullptr) {
1282  const Vehicle *v = Vehicle::Get(this->window_number);
1283 
1284  if (this->order == INVALID_VEH_ORDER_ID) {
1285  bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX;
1286  if (Command<CMD_REFIT_VEHICLE>::Post(GetCmdRefitVehMsg(v), v->tile, this->selected_vehicle, this->selected_refit->cargo, this->selected_refit->subtype, false, false, this->num_vehicles) && delete_window) this->Close();
1287  } else {
1288  if (Command<CMD_ORDER_REFIT>::Post(v->tile, v->index, this->order, this->selected_refit->cargo)) this->Close();
1289  }
1290  }
1291  break;
1292  }
1293  }
1294 
1295  void OnMouseDrag(Point pt, WidgetID widget) override
1296  {
1297  switch (widget) {
1298  case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image.
1299  if (this->order != INVALID_VEH_ORDER_ID) break;
1300  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_VR_VEHICLE_PANEL_DISPLAY);
1301  this->SetSelectedVehicles(pt.x - nwi->pos_x);
1303  break;
1304  }
1305  }
1306  }
1307 
1308  void OnDragDrop(Point pt, WidgetID widget) override
1309  {
1310  switch (widget) {
1311  case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image.
1312  if (this->order != INVALID_VEH_ORDER_ID) break;
1313  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_VR_VEHICLE_PANEL_DISPLAY);
1314  this->SetSelectedVehicles(pt.x - nwi->pos_x);
1315  this->InvalidateData(2);
1316  break;
1317  }
1318  }
1319  }
1320 
1321  void OnResize() override
1322  {
1323  this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS);
1324  this->vscroll->SetCapacityFromWidget(this, WID_VR_MATRIX);
1325  if (this->hscroll != nullptr) this->hscroll->SetCapacityFromWidget(this, WID_VR_VEHICLE_PANEL_DISPLAY);
1326  }
1327 };
1328 
1329 static constexpr NWidgetPart _nested_vehicle_refit_widgets[] = {
1331  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1332  NWidget(WWT_CAPTION, COLOUR_GREY, WID_VR_CAPTION), SetDataTip(STR_REFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1333  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1334  EndContainer(),
1335  /* Vehicle display + scrollbar. */
1338  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VR_SHOW_HSCROLLBAR),
1339  NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_VR_HSCROLLBAR),
1340  EndContainer(),
1341  EndContainer(),
1342  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VR_SELECT_HEADER), SetDataTip(STR_REFIT_TITLE, STR_NULL), SetResize(1, 0),
1343  /* Matrix + scrollbar. */
1345  NWidget(WWT_MATRIX, COLOUR_GREY, WID_VR_MATRIX), SetMinimalSize(228, 112), SetResize(1, 14), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VR_SCROLLBAR),
1346  NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VR_SCROLLBAR),
1347  EndContainer(),
1348  NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_INFO), SetMinimalTextLines(2, WidgetDimensions::unscaled.framerect.Vertical()), SetResize(1, 0), EndContainer(),
1350  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VR_REFIT), SetFill(1, 0), SetResize(1, 0),
1351  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1352  EndContainer(),
1353 };
1354 
1355 static WindowDesc _vehicle_refit_desc(
1356  WDP_AUTO, "view_vehicle_refit", 240, 174,
1359  _nested_vehicle_refit_widgets
1360 );
1361 
1369 void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit)
1370 {
1372  RefitWindow *w = new RefitWindow(_vehicle_refit_desc, v, order, auto_refit);
1373  w->parent = parent;
1374 }
1375 
1377 uint ShowRefitOptionsList(int left, int right, int y, EngineID engine)
1378 {
1379  /* List of cargo types of this engine */
1380  CargoTypes cmask = GetUnionOfArticulatedRefitMasks(engine, false);
1381  /* List of cargo types available in this climate */
1382  CargoTypes lmask = _cargo_mask;
1383 
1384  /* Draw nothing if the engine is not refittable */
1385  if (HasAtMostOneBit(cmask)) return y;
1386 
1387  if (cmask == lmask) {
1388  /* Engine can be refitted to all types in this climate */
1389  SetDParam(0, STR_PURCHASE_INFO_ALL_TYPES);
1390  } else {
1391  /* Check if we are able to refit to more cargo types and unable to. If
1392  * so, invert the cargo types to list those that we can't refit to. */
1393  if (CountBits(cmask ^ lmask) < CountBits(cmask) && CountBits(cmask ^ lmask) <= 7) {
1394  cmask ^= lmask;
1395  SetDParam(0, STR_PURCHASE_INFO_ALL_BUT);
1396  } else {
1397  SetDParam(0, STR_JUST_CARGO_LIST);
1398  }
1399  SetDParam(1, cmask);
1400  }
1401 
1402  return DrawStringMultiLine(left, right, y, INT32_MAX, STR_PURCHASE_INFO_REFITTABLE_TO);
1403 }
1404 
1407 {
1409  uint16_t cb = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v->engine_type, v);
1410  if (cb != CALLBACK_FAILED) {
1412  if (cb >= 0x400 || (v->GetGRF()->grf_version < 8 && cb == 0xFF)) cb = CALLBACK_FAILED;
1413  }
1414  if (cb != CALLBACK_FAILED) {
1415  return GetGRFStringID(v->GetGRFID(), 0xD000 + cb);
1416  }
1417  }
1418  return STR_EMPTY;
1419 }
1420 
1423 {
1424  return a.NumVehicles() < b.NumVehicles();
1425 }
1426 
1429 {
1430  return a.GetDisplayProfitThisYear() < b.GetDisplayProfitThisYear();
1431 }
1432 
1435 {
1436  return a.GetDisplayProfitLastYear() < b.GetDisplayProfitLastYear();
1437 }
1438 
1441 {
1442  return a.GetDisplayProfitThisYear() * static_cast<uint>(b.NumVehicles()) < b.GetDisplayProfitThisYear() * static_cast<uint>(a.NumVehicles());
1443 }
1444 
1447 {
1448  return a.GetDisplayProfitLastYear() * static_cast<uint>(b.NumVehicles()) < b.GetDisplayProfitLastYear() * static_cast<uint>(a.NumVehicles());
1449 }
1450 
1452 static bool VehicleNumberSorter(const Vehicle * const &a, const Vehicle * const &b)
1453 {
1454  return a->unitnumber < b->unitnumber;
1455 }
1456 
1458 static bool VehicleNameSorter(const Vehicle * const &a, const Vehicle * const &b)
1459 {
1460  static std::string last_name[2] = { {}, {} };
1461 
1462  if (a != _last_vehicle[0]) {
1463  _last_vehicle[0] = a;
1464  SetDParam(0, a->index);
1465  last_name[0] = GetString(STR_VEHICLE_NAME);
1466  }
1467 
1468  if (b != _last_vehicle[1]) {
1469  _last_vehicle[1] = b;
1470  SetDParam(0, b->index);
1471  last_name[1] = GetString(STR_VEHICLE_NAME);
1472  }
1473 
1474  int r = StrNaturalCompare(last_name[0], last_name[1]); // Sort by name (natural sorting).
1475  return (r != 0) ? r < 0: VehicleNumberSorter(a, b);
1476 }
1477 
1479 static bool VehicleAgeSorter(const Vehicle * const &a, const Vehicle * const &b)
1480 {
1481  auto r = a->age - b->age;
1482  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1483 }
1484 
1486 static bool VehicleProfitThisYearSorter(const Vehicle * const &a, const Vehicle * const &b)
1487 {
1488  int r = ClampTo<int32_t>(a->GetDisplayProfitThisYear() - b->GetDisplayProfitThisYear());
1489  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1490 }
1491 
1493 static bool VehicleProfitLastYearSorter(const Vehicle * const &a, const Vehicle * const &b)
1494 {
1495  int r = ClampTo<int32_t>(a->GetDisplayProfitLastYear() - b->GetDisplayProfitLastYear());
1496  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1497 }
1498 
1500 static bool VehicleCargoSorter(const Vehicle * const &a, const Vehicle * const &b)
1501 {
1502  const Vehicle *v;
1503  CargoArray diff{};
1504 
1505  /* Append the cargo of the connected waggons */
1506  for (v = a; v != nullptr; v = v->Next()) diff[v->cargo_type] += v->cargo_cap;
1507  for (v = b; v != nullptr; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap;
1508 
1509  int r = 0;
1510  for (uint d : diff) {
1511  r = d;
1512  if (r != 0) break;
1513  }
1514 
1515  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1516 }
1517 
1519 static bool VehicleReliabilitySorter(const Vehicle * const &a, const Vehicle * const &b)
1520 {
1521  int r = a->reliability - b->reliability;
1522  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1523 }
1524 
1526 static bool VehicleMaxSpeedSorter(const Vehicle * const &a, const Vehicle * const &b)
1527 {
1529  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1530 }
1531 
1533 static bool VehicleModelSorter(const Vehicle * const &a, const Vehicle * const &b)
1534 {
1535  int r = a->engine_type - b->engine_type;
1536  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1537 }
1538 
1540 static bool VehicleValueSorter(const Vehicle * const &a, const Vehicle * const &b)
1541 {
1542  const Vehicle *u;
1543  Money diff = 0;
1544 
1545  for (u = a; u != nullptr; u = u->Next()) diff += u->value;
1546  for (u = b; u != nullptr; u = u->Next()) diff -= u->value;
1547 
1548  int r = ClampTo<int32_t>(diff);
1549  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1550 }
1551 
1553 static bool VehicleLengthSorter(const Vehicle * const &a, const Vehicle * const &b)
1554 {
1556  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1557 }
1558 
1560 static bool VehicleTimeToLiveSorter(const Vehicle * const &a, const Vehicle * const &b)
1561 {
1562  int r = ClampTo<int32_t>((a->max_age - a->age) - (b->max_age - b->age));
1563  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1564 }
1565 
1567 static bool VehicleTimetableDelaySorter(const Vehicle * const &a, const Vehicle * const &b)
1568 {
1569  int r = a->lateness_counter - b->lateness_counter;
1570  return (r != 0) ? r < 0 : VehicleNumberSorter(a, b);
1571 }
1572 
1573 void InitializeGUI()
1574 {
1575  MemSetT(&_grouping, 0);
1576  MemSetT(&_sorting, 0);
1577 }
1578 
1585 static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_index, VehicleID to_index)
1586 {
1587  Window *w = FindWindowById(window_class, from_index);
1588  if (w != nullptr) {
1589  /* Update window_number */
1590  w->window_number = to_index;
1591  if (w->viewport != nullptr) w->viewport->follow_vehicle = to_index;
1592 
1593  /* Update vehicle drag data */
1594  if (_thd.window_class == window_class && _thd.window_number == (WindowNumber)from_index) {
1595  _thd.window_number = to_index;
1596  }
1597 
1598  /* Notify the window. */
1599  w->InvalidateData(VIWD_AUTOREPLACE, false);
1600  }
1601 }
1602 
1608 void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index)
1609 {
1610  ChangeVehicleWindow(WC_VEHICLE_VIEW, from_index, to_index);
1611  ChangeVehicleWindow(WC_VEHICLE_ORDERS, from_index, to_index);
1612  ChangeVehicleWindow(WC_VEHICLE_REFIT, from_index, to_index);
1613  ChangeVehicleWindow(WC_VEHICLE_DETAILS, from_index, to_index);
1614  ChangeVehicleWindow(WC_VEHICLE_TIMETABLE, from_index, to_index);
1615 }
1616 
1617 static constexpr NWidgetPart _nested_vehicle_list[] = {
1619  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1621  NWidget(WWT_CAPTION, COLOUR_GREY, WID_VL_CAPTION),
1624  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_ORDER_VIEW), SetMinimalSize(61, 14), SetDataTip(STR_GOTO_ORDER_VIEW, STR_GOTO_ORDER_VIEW_TOOLTIP),
1625  EndContainer(),
1626  EndContainer(),
1627  NWidget(WWT_SHADEBOX, COLOUR_GREY),
1628  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1629  NWidget(WWT_STICKYBOX, COLOUR_GREY),
1630  EndContainer(),
1631 
1634  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VL_GROUP_ORDER), SetMinimalSize(0, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, STR_TOOLTIP_GROUP_ORDER),
1635  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_SORT_ORDER), SetMinimalSize(0, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
1636  EndContainer(),
1638  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_GROUP_BY_PULLDOWN), SetMinimalSize(0, 12), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
1639  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_SORT_BY_PULLDOWN), SetMinimalSize(0, 12), SetFill(1, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
1640  EndContainer(),
1642  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(),
1645  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_FILTER_BY_CARGO), SetMinimalSize(0, 12), SetFill(0, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
1646  EndContainer(),
1647  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(),
1648  EndContainer(),
1649  EndContainer(),
1650  EndContainer(),
1651 
1653  NWidget(WWT_MATRIX, COLOUR_GREY, WID_VL_LIST), SetMinimalSize(248, 0), SetFill(1, 0), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VL_SCROLLBAR),
1654  NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VL_SCROLLBAR),
1655  EndContainer(),
1656 
1658  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VL_HIDE_BUTTONS),
1660  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1),
1661  SetDataTip(STR_JUST_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP),
1662  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), SetFill(1, 1), EndContainer(),
1664  SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP),
1665  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_STOP_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG), SetFill(0, 1),
1666  SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP),
1667  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_START_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG), SetFill(0, 1),
1668  SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP),
1669  EndContainer(),
1670  /* Widget to be shown for other companies hiding the previous 5 widgets. */
1671  NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(),
1672  EndContainer(),
1673  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1674  EndContainer(),
1675 };
1676 
1677 static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, uint order_arrow_width, VehicleOrderID start)
1678 {
1679  const Order *order = v->GetOrder(start);
1680  if (order == nullptr) return;
1681 
1682  bool rtl = _current_text_dir == TD_RTL;
1683  int l_offset = rtl ? 0 : order_arrow_width;
1684  int r_offset = rtl ? order_arrow_width : 0;
1685  int i = 0;
1686  VehicleOrderID oid = start;
1687 
1688  do {
1689  if (oid == v->cur_real_order_index) DrawString(left, right, y, STR_JUST_RIGHT_ARROW, TC_BLACK, SA_LEFT, false, FS_SMALL);
1690 
1691  if (order->IsType(OT_GOTO_STATION)) {
1692  SetDParam(0, order->GetDestination());
1693  DrawString(left + l_offset, right - r_offset, y, STR_STATION_NAME, TC_BLACK, SA_LEFT, false, FS_SMALL);
1694 
1696  if (++i == 4) break;
1697  }
1698 
1699  oid++;
1700  order = order->next;
1701  if (order == nullptr) {
1702  order = v->orders->GetFirstOrder();
1703  oid = 0;
1704  }
1705  } while (oid != start);
1706 }
1707 
1709 static void DrawSmallOrderList(const Order *order, int left, int right, int y, uint order_arrow_width)
1710 {
1711  bool rtl = _current_text_dir == TD_RTL;
1712  int l_offset = rtl ? 0 : order_arrow_width;
1713  int r_offset = rtl ? order_arrow_width : 0;
1714  int i = 0;
1715  while (order != nullptr) {
1716  if (order->IsType(OT_GOTO_STATION)) {
1717  SetDParam(0, order->GetDestination());
1718  DrawString(left + l_offset, right - r_offset, y, STR_STATION_NAME, TC_BLACK, SA_LEFT, false, FS_SMALL);
1719 
1721  if (++i == 4) break;
1722  }
1723  order = order->next;
1724  }
1725 }
1726 
1734 void DrawVehicleImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type, int skip)
1735 {
1736  switch (v->type) {
1737  case VEH_TRAIN: DrawTrainImage(Train::From(v), r, selection, image_type, skip); break;
1738  case VEH_ROAD: DrawRoadVehImage(v, r, selection, image_type, skip); break;
1739  case VEH_SHIP: DrawShipImage(v, r, selection, image_type); break;
1740  case VEH_AIRCRAFT: DrawAircraftImage(v, r, selection, image_type); break;
1741  default: NOT_REACHED();
1742  }
1743 }
1744 
1751 uint GetVehicleListHeight(VehicleType type, uint divisor)
1752 {
1753  /* Name + vehicle + profit */
1755  /* Drawing of the 4 small orders + profit*/
1756  if (type >= VEH_SHIP) base = std::max(base, 6U * GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.matrix.Vertical());
1757 
1758  if (divisor == 1) return base;
1759 
1760  /* Make sure the height is dividable by divisor */
1761  uint rem = base % divisor;
1762  return base + (rem == 0 ? 0 : divisor - rem);
1763 }
1764 
1770 static int GetUnitNumberWidth(int digits)
1771 {
1772  SetDParamMaxDigits(0, digits);
1773  return GetStringBoundingBox(STR_JUST_COMMA).width;
1774 }
1775 
1782 void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const
1783 {
1784  Rect ir = r.WithHeight(line_height).Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
1785  bool rtl = _current_text_dir == TD_RTL;
1786 
1787  Dimension profit = GetSpriteSize(SPR_PROFIT_LOT);
1788  int text_offset = std::max<int>(profit.width, GetUnitNumberWidth(this->unitnumber_digits)) + WidgetDimensions::scaled.hsep_normal;
1789  Rect tr = ir.Indent(text_offset, rtl);
1790 
1791  bool show_orderlist = this->vli.vtype >= VEH_SHIP;
1792  Rect olr = ir.Indent(std::max(ScaleGUITrad(100) + text_offset, ir.Width() / 2), rtl);
1793 
1794  int image_left = (rtl && show_orderlist) ? olr.right : tr.left;
1795  int image_right = (!rtl && show_orderlist) ? olr.left : tr.right;
1796 
1797  int vehicle_button_x = rtl ? ir.right - profit.width : ir.left;
1798 
1799  auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->vehgroups);
1800  for (auto it = first; it != last; ++it) {
1801  const GUIVehicleGroup &vehgroup = *it;
1802 
1803  SetDParam(0, vehgroup.GetDisplayProfitThisYear());
1804  SetDParam(1, vehgroup.GetDisplayProfitLastYear());
1805  DrawString(tr.left, tr.right, ir.bottom - GetCharacterHeight(FS_SMALL) - WidgetDimensions::scaled.framerect.bottom,
1806  TimerGameEconomy::UsingWallclockUnits() ? STR_VEHICLE_LIST_PROFIT_THIS_PERIOD_LAST_PERIOD : STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR);
1807 
1808  DrawVehicleProfitButton(vehgroup.GetOldestVehicleAge(), vehgroup.GetDisplayProfitLastYear(), vehgroup.NumVehicles(), vehicle_button_x, ir.top + GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal);
1809 
1810  switch (this->grouping) {
1811  case GB_NONE: {
1812  const Vehicle *v = vehgroup.GetSingleVehicle();
1813 
1815  DrawSprite(SPR_WARNING_SIGN, PAL_NONE, vehicle_button_x, ir.top + GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal + profit.height);
1816  }
1817 
1818  DrawVehicleImage(v, {image_left, ir.top, image_right, ir.bottom}, selected_vehicle, EIT_IN_LIST, 0);
1819 
1821  /* Get the cargoes the vehicle can carry */
1822  CargoTypes vehicle_cargoes = 0;
1823 
1824  for (auto u = v; u != nullptr; u = u->Next()) {
1825  if (u->cargo_cap == 0) continue;
1826 
1827  SetBit(vehicle_cargoes, u->cargo_type);
1828  }
1829 
1830  if (!v->name.empty()) {
1831  /* The vehicle got a name so we will print it and the cargoes */
1832  SetDParam(0, STR_VEHICLE_NAME);
1833  SetDParam(1, v->index);
1834  SetDParam(2, STR_VEHICLE_LIST_CARGO);
1835  SetDParam(3, vehicle_cargoes);
1836  DrawString(tr.left, tr.right, ir.top, STR_VEHICLE_LIST_NAME_AND_CARGO, TC_BLACK, SA_LEFT, false, FS_SMALL);
1837  } else if (v->group_id != DEFAULT_GROUP) {
1838  /* The vehicle has no name, but is member of a group, so print group name and the cargoes */
1839  SetDParam(0, STR_GROUP_NAME);
1840  SetDParam(1, v->group_id);
1841  SetDParam(2, STR_VEHICLE_LIST_CARGO);
1842  SetDParam(3, vehicle_cargoes);
1843  DrawString(tr.left, tr.right, ir.top, STR_VEHICLE_LIST_NAME_AND_CARGO, TC_BLACK, SA_LEFT, false, FS_SMALL);
1844  } else {
1845  /* The vehicle has no name, and is not a member of a group, so just print the cargoes */
1846  SetDParam(0, vehicle_cargoes);
1847  DrawString(tr.left, tr.right, ir.top, STR_VEHICLE_LIST_CARGO, TC_BLACK, SA_LEFT, false, FS_SMALL);
1848  }
1849  } else if (!v->name.empty()) {
1850  /* The vehicle got a name so we will print it */
1851  SetDParam(0, v->index);
1852  DrawString(tr.left, tr.right, ir.top, STR_VEHICLE_NAME, TC_BLACK, SA_LEFT, false, FS_SMALL);
1853  } else if (v->group_id != DEFAULT_GROUP) {
1854  /* The vehicle has no name, but is member of a group, so print group name */
1855  SetDParam(0, v->group_id);
1856  DrawString(tr.left, tr.right, ir.top, STR_GROUP_NAME, TC_BLACK, SA_LEFT, false, FS_SMALL);
1857  }
1858 
1859  if (show_orderlist) DrawSmallOrderList(v, olr.left, olr.right, ir.top + GetCharacterHeight(FS_SMALL), this->order_arrow_width, v->cur_real_order_index);
1860 
1861  TextColour tc;
1862  if (v->IsChainInDepot()) {
1863  tc = TC_BLUE;
1864  } else {
1865  tc = (v->age > v->max_age - CalendarTime::DAYS_IN_LEAP_YEAR) ? TC_RED : TC_BLACK;
1866  }
1867 
1868  SetDParam(0, v->unitnumber);
1869  DrawString(ir.left, ir.right, ir.top + WidgetDimensions::scaled.framerect.top, STR_JUST_COMMA, tc);
1870  break;
1871  }
1872 
1873  case GB_SHARED_ORDERS:
1874  assert(vehgroup.NumVehicles() > 0);
1875 
1876  for (int i = 0; i < static_cast<int>(vehgroup.NumVehicles()); ++i) {
1877  if (image_left + WidgetDimensions::scaled.hsep_wide * i >= image_right) break; // Break if there is no more space to draw any more vehicles anyway.
1878  DrawVehicleImage(vehgroup.vehicles_begin[i], {image_left + WidgetDimensions::scaled.hsep_wide * i, ir.top, image_right, ir.bottom}, selected_vehicle, EIT_IN_LIST, 0);
1879  }
1880 
1881  if (show_orderlist) DrawSmallOrderList((vehgroup.vehicles_begin[0])->GetFirstOrder(), olr.left, olr.right, ir.top + GetCharacterHeight(FS_SMALL), this->order_arrow_width);
1882 
1883  SetDParam(0, vehgroup.NumVehicles());
1884  DrawString(ir.left, ir.right, ir.top + WidgetDimensions::scaled.framerect.top, STR_JUST_COMMA, TC_BLACK);
1885  break;
1886 
1887  default:
1888  NOT_REACHED();
1889  }
1890 
1891  ir = ir.Translate(0, line_height);
1892  }
1893 }
1894 
1895 void BaseVehicleListWindow::UpdateSortingFromGrouping()
1896 {
1897  /* Set up sorting. Make the window-specific _sorting variable
1898  * point to the correct global _sorting struct so we are freed
1899  * from having conditionals during window operation */
1900  switch (this->vli.vtype) {
1901  case VEH_TRAIN: this->sorting = &_sorting[this->grouping].train; break;
1902  case VEH_ROAD: this->sorting = &_sorting[this->grouping].roadveh; break;
1903  case VEH_SHIP: this->sorting = &_sorting[this->grouping].ship; break;
1904  case VEH_AIRCRAFT: this->sorting = &_sorting[this->grouping].aircraft; break;
1905  default: NOT_REACHED();
1906  }
1907  this->vehgroups.SetSortFuncs(this->GetVehicleSorterFuncs());
1908  this->vehgroups.SetListing(*this->sorting);
1909  this->vehgroups.ForceRebuild();
1910  this->vehgroups.NeedResort();
1911 }
1912 
1913 void BaseVehicleListWindow::UpdateVehicleGroupBy(GroupBy group_by)
1914 {
1915  if (this->grouping != group_by) {
1916  /* Save the old sorting option, so that if we change the grouping option back later on,
1917  * UpdateSortingFromGrouping() will automatically restore the saved sorting option. */
1918  *this->sorting = this->vehgroups.GetListing();
1919 
1920  this->grouping = group_by;
1921  _grouping[this->vli.type][this->vli.vtype] = group_by;
1922  this->UpdateSortingFromGrouping();
1923  }
1924 }
1925 
1936 private:
1941  };
1942 
1947  };
1948 
1949 public:
1951  {
1952  this->CreateNestedTree();
1953 
1954  this->GetWidget<NWidgetStacked>(WID_VL_FILTER_BY_CARGO_SEL)->SetDisplayedPlane((this->vli.type == VL_SHARED_ORDERS) ? SZSP_NONE : 0);
1955 
1956  this->vscroll = this->GetScrollbar(WID_VL_SCROLLBAR);
1957 
1958  /* Set up the window widgets */
1959  this->GetWidget<NWidgetCore>(WID_VL_LIST)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype;
1960 
1961  NWidgetStacked *nwi = this->GetWidget<NWidgetStacked>(WID_VL_CAPTION_SELECTION);
1962  if (this->vli.type == VL_SHARED_ORDERS) {
1963  this->GetWidget<NWidgetCore>(WID_VL_CAPTION_SHARED_ORDERS)->widget_data = STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION;
1964  /* If we are in the shared orders window, then disable the group-by dropdown menu.
1965  * Remove this when the group-by dropdown menu has another option apart from grouping by shared orders. */
1969  } else {
1970  this->GetWidget<NWidgetCore>(WID_VL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype;
1972  }
1973 
1974  this->FinishInitNested(window_number);
1975  if (this->vli.company != OWNER_NONE) this->owner = this->vli.company;
1976 
1977  this->BuildVehicleList();
1978  this->SortVehicleList();
1979  }
1980 
1982  {
1983  *this->sorting = this->vehgroups.GetListing();
1984  }
1985 
1986  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1987  {
1988  switch (widget) {
1989  case WID_VL_LIST:
1990  resize.height = GetVehicleListHeight(this->vli.vtype, 1);
1991 
1992  switch (this->vli.vtype) {
1993  case VEH_TRAIN:
1994  case VEH_ROAD:
1995  size.height = 6 * resize.height;
1996  break;
1997  case VEH_SHIP:
1998  case VEH_AIRCRAFT:
1999  size.height = 4 * resize.height;
2000  break;
2001  default: NOT_REACHED();
2002  }
2003  break;
2004 
2005  case WID_VL_SORT_ORDER: {
2006  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
2007  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
2008  d.height += padding.height;
2009  size = maxdim(size, d);
2010  break;
2011  }
2012 
2014  size.width = GetStringListWidth(this->vehicle_group_by_names) + padding.width;
2015  break;
2016 
2018  size.width = GetStringListWidth(this->vehicle_group_none_sorter_names_calendar);
2019  size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_none_sorter_names_wallclock));
2020  size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_calendar));
2021  size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_wallclock));
2022  size.width += padding.width;
2023  break;
2024 
2026  size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList(true)).width + padding.width);
2027  break;
2028 
2030  Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false, true);
2031  d.height += padding.height;
2032  d.width += padding.width;
2033  size = maxdim(size, d);
2034  break;
2035  }
2036  }
2037  }
2038 
2039  void SetStringParameters(WidgetID widget) const override
2040  {
2041  switch (widget) {
2043  SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype);
2044  break;
2045 
2047  SetDParam(0, this->GetCargoFilterLabel(this->cargo_filter_criteria));
2048  break;
2049 
2050  case WID_VL_CAPTION:
2052  switch (this->vli.type) {
2053  case VL_SHARED_ORDERS: // Shared Orders
2054  SetDParam(0, this->vehicles.size());
2055  break;
2056 
2057  case VL_STANDARD: // Company Name
2058  SetDParam(0, STR_COMPANY_NAME);
2059  SetDParam(1, this->vli.index);
2060  SetDParam(3, this->vehicles.size());
2061  break;
2062 
2063  case VL_STATION_LIST: // Station/Waypoint Name
2064  SetDParam(0, Station::IsExpected(BaseStation::Get(this->vli.index)) ? STR_STATION_NAME : STR_WAYPOINT_NAME);
2065  SetDParam(1, this->vli.index);
2066  SetDParam(3, this->vehicles.size());
2067  break;
2068 
2069  case VL_DEPOT_LIST:
2070  SetDParam(0, STR_DEPOT_CAPTION);
2071  SetDParam(1, this->vli.vtype);
2072  SetDParam(2, this->vli.index);
2073  SetDParam(3, this->vehicles.size());
2074  break;
2075  default: NOT_REACHED();
2076  }
2077  break;
2078  }
2079  }
2080  }
2081 
2082  void DrawWidget(const Rect &r, WidgetID widget) const override
2083  {
2084  switch (widget) {
2085  case WID_VL_SORT_ORDER:
2086  /* draw arrow pointing up/down for ascending/descending sorting */
2087  this->DrawSortButtonState(widget, this->vehgroups.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
2088  break;
2089 
2090  case WID_VL_LIST:
2091  this->DrawVehicleListItems(INVALID_VEHICLE, this->resize.step_height, r);
2092  break;
2093  }
2094  }
2095 
2096  void OnPaint() override
2097  {
2098  this->BuildVehicleList();
2099  this->SortVehicleList();
2100 
2101  if (this->vehicles.empty() && this->IsWidgetLowered(WID_VL_MANAGE_VEHICLES_DROPDOWN)) {
2103  }
2104 
2105  /* Hide the widgets that we will not use in this window
2106  * Some windows contains actions only fit for the owner */
2107  int plane_to_show = (this->owner == _local_company) ? BP_SHOW_BUTTONS : BP_HIDE_BUTTONS;
2108  NWidgetStacked *nwi = this->GetWidget<NWidgetStacked>(WID_VL_HIDE_BUTTONS);
2109  if (plane_to_show != nwi->shown_plane) {
2110  nwi->SetDisplayedPlane(plane_to_show);
2111  nwi->SetDirty(this);
2112  }
2113  if (this->owner == _local_company) {
2114  this->SetWidgetDisabledState(WID_VL_AVAILABLE_VEHICLES, this->vli.type != VL_STANDARD);
2115  this->SetWidgetsDisabledState(this->vehicles.empty(),
2119  }
2120 
2121  /* Set text of group by dropdown widget. */
2122  this->GetWidget<NWidgetCore>(WID_VL_GROUP_BY_PULLDOWN)->widget_data = std::data(this->vehicle_group_by_names)[this->grouping];
2123 
2124  /* Set text of sort by dropdown widget. */
2125  this->GetWidget<NWidgetCore>(WID_VL_SORT_BY_PULLDOWN)->widget_data = this->GetVehicleSorterNames()[this->vehgroups.SortType()];
2126 
2127  this->GetWidget<NWidgetCore>(WID_VL_FILTER_BY_CARGO)->widget_data = this->GetCargoFilterLabel(this->cargo_filter_criteria);
2128 
2129  this->DrawWidgets();
2130  }
2131 
2132  bool last_overlay_state;
2133  void OnMouseLoop() override
2134  {
2135  if (last_overlay_state != ShowCargoIconOverlay()) {
2136  last_overlay_state = ShowCargoIconOverlay();
2137  this->SetDirty();
2138  }
2139  }
2140 
2141  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2142  {
2143  switch (widget) {
2144  case WID_VL_ORDER_VIEW: // Open the shared orders window
2145  assert(this->vli.type == VL_SHARED_ORDERS);
2146  assert(!this->vehicles.empty());
2147  ShowOrdersWindow(this->vehicles[0]);
2148  break;
2149 
2150  case WID_VL_SORT_ORDER: // Flip sorting method ascending/descending
2151  this->vehgroups.ToggleSortOrder();
2152  this->SetDirty();
2153  break;
2154 
2155  case WID_VL_GROUP_BY_PULLDOWN: // Select sorting criteria dropdown menu
2156  ShowDropDownMenu(this, this->vehicle_group_by_names, this->grouping, WID_VL_GROUP_BY_PULLDOWN, 0, 0);
2157  return;
2158 
2159  case WID_VL_SORT_BY_PULLDOWN: // Select sorting criteria dropdown menu
2160  ShowDropDownMenu(this, this->GetVehicleSorterNames(), this->vehgroups.SortType(), WID_VL_SORT_BY_PULLDOWN, 0,
2161  (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10));
2162  return;
2163 
2164  case WID_VL_FILTER_BY_CARGO: // Cargo filter dropdown
2165  ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria, widget);
2166  break;
2167 
2168  case WID_VL_LIST: { // Matrix to show vehicles
2169  auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_VL_LIST);
2170  if (it == this->vehgroups.end()) return; // click out of list bound
2171 
2172  const GUIVehicleGroup &vehgroup = *it;
2173  switch (this->grouping) {
2174  case GB_NONE: {
2175  const Vehicle *v = vehgroup.GetSingleVehicle();
2176  if (!VehicleClicked(v)) {
2177  if (_ctrl_pressed) {
2179  } else {
2181  }
2182  }
2183  break;
2184  }
2185 
2186  case GB_SHARED_ORDERS: {
2187  assert(vehgroup.NumVehicles() > 0);
2188  if (!VehicleClicked(vehgroup)) {
2189  const Vehicle *v = vehgroup.vehicles_begin[0];
2190  if (_ctrl_pressed) {
2191  ShowOrdersWindow(v);
2192  } else {
2193  if (vehgroup.NumVehicles() == 1) {
2195  } else {
2196  ShowVehicleListWindow(v);
2197  }
2198  }
2199  }
2200  break;
2201  }
2202 
2203  default: NOT_REACHED();
2204  }
2205 
2206  break;
2207  }
2208 
2210  ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype);
2211  break;
2212 
2214  ShowDropDownList(this, this->BuildActionDropdownList(VehicleListIdentifier::UnPack(this->window_number).type == VL_STANDARD, false, true), 0, WID_VL_MANAGE_VEHICLES_DROPDOWN);
2215  break;
2216  }
2217 
2218  case WID_VL_STOP_ALL:
2219  case WID_VL_START_ALL:
2220  Command<CMD_MASS_START_STOP>::Post(0, widget == WID_VL_START_ALL, true, this->vli);
2221  break;
2222  }
2223  }
2224 
2225  void OnDropdownSelect(WidgetID widget, int index) override
2226  {
2227  switch (widget) {
2229  this->UpdateVehicleGroupBy(static_cast<GroupBy>(index));
2230  break;
2231 
2233  this->vehgroups.SetSortType(index);
2234  break;
2235 
2237  this->SetCargoFilter(index);
2238  break;
2239 
2241  assert(!this->vehicles.empty());
2242 
2243  switch (index) {
2244  case ADI_REPLACE: // Replace window
2246  break;
2247  case ADI_SERVICE: // Send for servicing
2248  case ADI_DEPOT: // Send to Depots
2249  Command<CMD_SEND_VEHICLE_TO_DEPOT>::Post(GetCmdSendToDepotMsg(this->vli.vtype), 0, DepotCommand::MassSend | (index == ADI_SERVICE ? DepotCommand::Service : DepotCommand::None), this->vli);
2250  break;
2251 
2252  case ADI_CREATE_GROUP: // Create group
2254  break;
2255 
2256  default: NOT_REACHED();
2257  }
2258  break;
2259 
2260  default: NOT_REACHED();
2261  }
2262  this->SetDirty();
2263  }
2264 
2265  void OnGameTick() override
2266  {
2267  if (this->vehgroups.NeedResort()) {
2268  StationID station = (this->vli.type == VL_STATION_LIST) ? this->vli.index : INVALID_STATION;
2269 
2270  Debug(misc, 3, "Periodic resort {} list company {} at station {}", this->vli.vtype, this->owner, station);
2271  this->SetDirty();
2272  }
2273  }
2274 
2275  void OnResize() override
2276  {
2277  this->vscroll->SetCapacityFromWidget(this, WID_VL_LIST);
2278  }
2279 
2285  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2286  {
2287  if (!gui_scope && HasBit(data, 31) && this->vli.type == VL_SHARED_ORDERS) {
2288  /* Needs to be done in command-scope, so everything stays valid */
2289  this->vli.index = GB(data, 0, 20);
2290  this->window_number = this->vli.Pack();
2291  this->vehgroups.ForceRebuild();
2292  return;
2293  }
2294 
2295  if (data == 0) {
2296  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
2297  this->vehgroups.ForceRebuild();
2298  } else {
2299  this->vehgroups.ForceResort();
2300  }
2301  }
2302 };
2303 
2304 static WindowDesc _vehicle_list_other_desc(
2305  WDP_AUTO, "list_vehicles", 260, 246,
2307  0,
2308  _nested_vehicle_list
2309 );
2310 
2311 static WindowDesc _vehicle_list_train_desc(
2312  WDP_AUTO, "list_vehicles_train", 325, 246,
2314  0,
2315  _nested_vehicle_list
2316 );
2317 
2318 static void ShowVehicleListWindowLocal(CompanyID company, VehicleListType vlt, VehicleType vehicle_type, uint32_t unique_number)
2319 {
2320  if (!Company::IsValidID(company) && company != OWNER_NONE) return;
2321 
2322  WindowNumber num = VehicleListIdentifier(vlt, vehicle_type, company, unique_number).Pack();
2323  if (vehicle_type == VEH_TRAIN) {
2324  AllocateWindowDescFront<VehicleListWindow>(_vehicle_list_train_desc, num);
2325  } else {
2326  _vehicle_list_other_desc.cls = GetWindowClassForVehicleType(vehicle_type);
2327  AllocateWindowDescFront<VehicleListWindow>(_vehicle_list_other_desc, num);
2328  }
2329 }
2330 
2331 void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type)
2332 {
2333  /* If _settings_client.gui.advanced_vehicle_list > 1, display the Advanced list
2334  * if _settings_client.gui.advanced_vehicle_list == 1, display Advanced list only for local company
2335  * if _ctrl_pressed, do the opposite action (Advanced list x Normal list)
2336  */
2337 
2338  if ((_settings_client.gui.advanced_vehicle_list > (uint)(company != _local_company)) != _ctrl_pressed) {
2339  ShowCompanyGroup(company, vehicle_type);
2340  } else {
2341  ShowVehicleListWindowLocal(company, VL_STANDARD, vehicle_type, company);
2342  }
2343 }
2344 
2345 void ShowVehicleListWindow(const Vehicle *v)
2346 {
2347  ShowVehicleListWindowLocal(v->owner, VL_SHARED_ORDERS, v->type, v->FirstShared()->index);
2348 }
2349 
2350 void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station)
2351 {
2352  ShowVehicleListWindowLocal(company, VL_STATION_LIST, vehicle_type, station);
2353 }
2354 
2355 void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile)
2356 {
2357  uint16_t depot_airport_index;
2358 
2359  if (vehicle_type == VEH_AIRCRAFT) {
2360  depot_airport_index = GetStationIndex(depot_tile);
2361  } else {
2362  depot_airport_index = GetDepotIndex(depot_tile);
2363  }
2364  ShowVehicleListWindowLocal(company, VL_DEPOT_LIST, vehicle_type, depot_airport_index);
2365 }
2366 
2367 
2368 /* Unified vehicle GUI - Vehicle Details Window */
2369 
2374 
2378  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2379  NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2380  NWidget(WWT_SHADEBOX, COLOUR_GREY),
2381  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
2382  NWidget(WWT_STICKYBOX, COLOUR_GREY),
2383  EndContainer(),
2384  NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetMinimalSize(405, 42), SetResize(1, 0), EndContainer(),
2385  NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_MIDDLE_DETAILS), SetMinimalSize(405, 45), SetResize(1, 0), EndContainer(),
2388  SetDataTip(AWV_DECREASE, STR_NULL),
2390  SetDataTip(AWV_INCREASE, STR_NULL),
2392  SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP),
2393  NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(),
2394  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
2395  EndContainer(),
2396 };
2397 
2401  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2402  NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2403  NWidget(WWT_SHADEBOX, COLOUR_GREY),
2404  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
2405  NWidget(WWT_STICKYBOX, COLOUR_GREY),
2406  EndContainer(),
2407  NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetResize(1, 0), SetMinimalSize(405, 42), EndContainer(),
2409  NWidget(WWT_MATRIX, COLOUR_GREY, WID_VD_MATRIX), SetResize(1, 1), SetMinimalSize(393, 45), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 0), SetScrollbar(WID_VD_SCROLLBAR),
2410  NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VD_SCROLLBAR),
2411  EndContainer(),
2414  SetDataTip(AWV_DECREASE, STR_NULL),
2416  SetDataTip(AWV_INCREASE, STR_NULL),
2418  SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP),
2419  NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(),
2420  EndContainer(),
2423  SetDataTip(STR_VEHICLE_DETAIL_TAB_CARGO, STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2425  SetDataTip(STR_VEHICLE_DETAIL_TAB_INFORMATION, STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2427  SetDataTip(STR_VEHICLE_DETAIL_TAB_CAPACITIES, STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2429  SetDataTip(STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
2430  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
2431  EndContainer(),
2432 };
2433 
2434 
2435 extern int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab);
2436 extern void DrawTrainDetails(const Train *v, const Rect &r, int vscroll_pos, uint16_t vscroll_cap, TrainDetailsWindowTabs det_tab);
2437 extern void DrawRoadVehDetails(const Vehicle *v, const Rect &r);
2438 extern void DrawShipDetails(const Vehicle *v, const Rect &r);
2439 extern void DrawAircraftDetails(const Aircraft *v, const Rect &r);
2440 
2441 static StringID _service_interval_dropdown_calendar[] = {
2442  STR_VEHICLE_DETAILS_DEFAULT,
2443  STR_VEHICLE_DETAILS_DAYS,
2444  STR_VEHICLE_DETAILS_PERCENT,
2445 };
2446 
2447 static StringID _service_interval_dropdown_wallclock[] = {
2448  STR_VEHICLE_DETAILS_DEFAULT,
2449  STR_VEHICLE_DETAILS_MINUTES,
2450  STR_VEHICLE_DETAILS_PERCENT,
2451 };
2452 
2456  Scrollbar *vscroll;
2457 
2460  {
2461  const Vehicle *v = Vehicle::Get(window_number);
2462 
2463  this->CreateNestedTree();
2464  this->vscroll = (v->type == VEH_TRAIN ? this->GetScrollbar(WID_VD_SCROLLBAR) : nullptr);
2465  this->FinishInitNested(window_number);
2466 
2467  this->owner = v->owner;
2468  this->tab = TDW_TAB_CARGO;
2469  }
2470 
2476  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2477  {
2478  if (data == VIWD_AUTOREPLACE) {
2479  /* Autoreplace replaced the vehicle.
2480  * Nothing to do for this window. */
2481  return;
2482  }
2483  if (!gui_scope) return;
2484  const Vehicle *v = Vehicle::Get(this->window_number);
2485  if (v->type == VEH_ROAD) {
2486  const NWidgetBase *nwid_info = this->GetWidget<NWidgetBase>(WID_VD_MIDDLE_DETAILS);
2487  uint aimed_height = this->GetRoadVehDetailsHeight(v);
2488  /* If the number of articulated parts changes, the size of the window must change too. */
2489  if (aimed_height != nwid_info->current_y) {
2490  this->ReInit();
2491  }
2492  }
2493  }
2494 
2501  {
2502  uint desired_height;
2503  if (v->HasArticulatedPart()) {
2504  /* An articulated RV has its text drawn under the sprite instead of after it, hence 15 pixels extra. */
2506  /* Add space for the cargo amount for each part. */
2507  for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
2508  if (u->cargo_cap != 0) desired_height += GetCharacterHeight(FS_NORMAL);
2509  }
2510  } else {
2512  }
2513  return desired_height;
2514  }
2515 
2516  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2517  {
2518  switch (widget) {
2519  case WID_VD_TOP_DETAILS: {
2520  Dimension dim = { 0, 0 };
2521  size.height = 4 * GetCharacterHeight(FS_NORMAL) + padding.height;
2522 
2523  for (uint i = 0; i < 4; i++) SetDParamMaxValue(i, INT16_MAX);
2524  static const StringID info_strings[] = {
2525  STR_VEHICLE_INFO_MAX_SPEED,
2526  STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED,
2527  STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE,
2528  STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_MIN_PERFORMANCE,
2529  STR_VEHICLE_INFO_PROFIT_THIS_PERIOD_LAST_PERIOD_MIN_PERFORMANCE,
2530  STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS
2531  };
2532  for (const auto &info_string : info_strings) {
2533  dim = maxdim(dim, GetStringBoundingBox(info_string));
2534  }
2535  SetDParam(0, STR_VEHICLE_INFO_AGE);
2536  dim = maxdim(dim, GetStringBoundingBox(TimerGameEconomy::UsingWallclockUnits() ? STR_VEHICLE_INFO_AGE_RUNNING_COST_PERIOD : STR_VEHICLE_INFO_AGE_RUNNING_COST_YR));
2537  size.width = dim.width + padding.width;
2538  break;
2539  }
2540 
2541  case WID_VD_MIDDLE_DETAILS: {
2542  const Vehicle *v = Vehicle::Get(this->window_number);
2543  switch (v->type) {
2544  case VEH_ROAD:
2545  size.height = this->GetRoadVehDetailsHeight(v) + padding.height;
2546  break;
2547 
2548  case VEH_SHIP:
2549  size.height = 4 * GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal * 2 + padding.height;
2550  break;
2551 
2552  case VEH_AIRCRAFT:
2553  size.height = 5 * GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal * 2 + padding.height;
2554  break;
2555 
2556  default:
2557  NOT_REACHED(); // Train uses WID_VD_MATRIX instead.
2558  }
2559  break;
2560  }
2561 
2562  case WID_VD_MATRIX:
2563  resize.height = std::max<uint>(ScaleGUITrad(14), GetCharacterHeight(FS_NORMAL) + padding.height);
2564  size.height = 4 * resize.height;
2565  break;
2566 
2568  Dimension d = maxdim(GetStringListBoundingBox(_service_interval_dropdown_calendar), GetStringListBoundingBox(_service_interval_dropdown_wallclock));
2569  d.width += padding.width;
2570  d.height += padding.height;
2571  size = maxdim(size, d);
2572  break;
2573  }
2574 
2576  SetDParamMaxValue(0, MAX_SERVINT_DAYS); // Roughly the maximum interval
2577 
2578  /* Do we show the last serviced value as a date or minutes since service? */
2580  SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_MINUTES_AGO);
2581  /*/ Vehicle was last serviced at year 0, and we're at max year */
2583  } else {
2584  SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_DATE);
2585  /*/ Vehicle was last serviced at year 0, and we're at max year */
2587  }
2588  size.width = std::max(
2589  GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width,
2590  GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width
2591  ) + padding.width;
2592  size.height = GetCharacterHeight(FS_NORMAL) + padding.height;
2593  break;
2594  }
2595  }
2596 
2598  static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type, CompanyID company_id)
2599  {
2600  const VehicleDefaultSettings *vds = &Company::Get(company_id)->settings.vehicle;
2601  switch (vehicle_type) {
2602  default: NOT_REACHED();
2603  case VEH_TRAIN: return vds->servint_trains != 0;
2604  case VEH_ROAD: return vds->servint_roadveh != 0;
2605  case VEH_SHIP: return vds->servint_ships != 0;
2606  case VEH_AIRCRAFT: return vds->servint_aircraft != 0;
2607  }
2608  }
2609 
2619  static void DrawVehicleDetails(const Vehicle *v, const Rect &r, int vscroll_pos, uint vscroll_cap, TrainDetailsWindowTabs det_tab)
2620  {
2621  switch (v->type) {
2622  case VEH_TRAIN: DrawTrainDetails(Train::From(v), r, vscroll_pos, vscroll_cap, det_tab); break;
2623  case VEH_ROAD: DrawRoadVehDetails(v, r); break;
2624  case VEH_SHIP: DrawShipDetails(v, r); break;
2625  case VEH_AIRCRAFT: DrawAircraftDetails(Aircraft::From(v), r); break;
2626  default: NOT_REACHED();
2627  }
2628  }
2629 
2630  void SetStringParameters(WidgetID widget) const override
2631  {
2632  if (widget == WID_VD_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index);
2633  }
2634 
2635  void DrawWidget(const Rect &r, WidgetID widget) const override
2636  {
2637  const Vehicle *v = Vehicle::Get(this->window_number);
2638 
2639  switch (widget) {
2640  case WID_VD_TOP_DETAILS: {
2641  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
2642 
2643  /* Draw running cost */
2645  SetDParam(0, (v->age + CalendarTime::DAYS_IN_YEAR < v->max_age) ? STR_VEHICLE_INFO_AGE : STR_VEHICLE_INFO_AGE_RED);
2648  DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_VEHICLE_INFO_AGE_RUNNING_COST_PERIOD : STR_VEHICLE_INFO_AGE_RUNNING_COST_YR);
2649  tr.top += GetCharacterHeight(FS_NORMAL);
2650 
2651  /* Draw max speed */
2652  StringID string;
2653  if (v->type == VEH_TRAIN ||
2654  (v->type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL)) {
2655  const GroundVehicleCache *gcache = v->GetGroundVehicleCache();
2657  SetDParam(1, gcache->cached_power);
2658  SetDParam(0, gcache->cached_weight);
2659  SetDParam(3, gcache->cached_max_te);
2660  if (v->type == VEH_TRAIN && (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ||
2661  GetRailTypeInfo(Train::From(v)->railtype)->acceleration_type == 2)) {
2662  string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED;
2663  } else {
2664  string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE;
2665  }
2666  } else {
2668  if (v->type == VEH_AIRCRAFT) {
2670  if (Aircraft::From(v)->GetRange() > 0) {
2671  SetDParam(2, Aircraft::From(v)->GetRange());
2672  string = STR_VEHICLE_INFO_MAX_SPEED_TYPE_RANGE;
2673  } else {
2674  string = STR_VEHICLE_INFO_MAX_SPEED_TYPE;
2675  }
2676  } else {
2677  string = STR_VEHICLE_INFO_MAX_SPEED;
2678  }
2679  }
2680  DrawString(tr, string);
2681  tr.top += GetCharacterHeight(FS_NORMAL);
2682 
2683  /* Draw profit */
2686  if (v->IsGroundVehicle()) {
2688  DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_VEHICLE_INFO_PROFIT_THIS_PERIOD_LAST_PERIOD_MIN_PERFORMANCE : STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_MIN_PERFORMANCE);
2689  } else {
2690  DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_VEHICLE_INFO_PROFIT_THIS_PERIOD_LAST_PERIOD : STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR);
2691  }
2692  tr.top += GetCharacterHeight(FS_NORMAL);
2693 
2694  /* Draw breakdown & reliability */
2697  DrawString(tr, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS);
2698  break;
2699  }
2700 
2701  case WID_VD_MATRIX: {
2702  /* For trains only. */
2703  DrawVehicleDetails(v, r.Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero).WithHeight(this->resize.step_height), this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->tab);
2704  break;
2705  }
2706 
2707  case WID_VD_MIDDLE_DETAILS: {
2708  /* For other vehicles, at the place of the matrix. */
2709  bool rtl = _current_text_dir == TD_RTL;
2711  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
2712 
2713  /* Articulated road vehicles use a complete line. */
2714  if (v->type == VEH_ROAD && v->HasArticulatedPart()) {
2716  } else {
2717  Rect sr = tr.WithWidth(sprite_width, rtl);
2719  }
2720 
2721  DrawVehicleDetails(v, tr.Indent(sprite_width, rtl), 0, 0, this->tab);
2722  break;
2723  }
2724 
2726  /* Draw service interval text */
2727  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
2728 
2729  SetDParam(0, v->GetServiceInterval());
2730 
2731  /* We're using wallclock units. Show minutes since last serviced. */
2733  int minutes_since_serviced = (TimerGameEconomy::date - v->date_of_last_service).base() / EconomyTime::DAYS_IN_ECONOMY_MONTH;
2734  SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_MINUTES_AGO);
2735  SetDParam(2, minutes_since_serviced);
2736  DrawString(tr.left, tr.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)),
2737  v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_MINUTES);
2738  break;
2739  }
2740 
2741  /* We're using calendar dates. Show the date of last service. */
2742  SetDParam(1, STR_VEHICLE_DETAILS_LAST_SERVICE_DATE);
2744  DrawString(tr.left, tr.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)),
2745  v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS);
2746  break;
2747  }
2748  }
2749  }
2750 
2752  void OnPaint() override
2753  {
2754  const Vehicle *v = Vehicle::Get(this->window_number);
2755 
2756  if (v->type == VEH_TRAIN) {
2757  this->LowerWidget(WID_VD_DETAILS_CARGO_CARRIED + this->tab);
2758  this->vscroll->SetCount(GetTrainDetailsWndVScroll(v->index, this->tab));
2759  }
2760 
2761  /* Disable service-scroller when interval is set to disabled */
2765 
2766  StringID str =
2767  !v->ServiceIntervalIsCustom() ? STR_VEHICLE_DETAILS_DEFAULT :
2768  v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_PERCENT :
2769  TimerGameEconomy::UsingWallclockUnits() ? STR_VEHICLE_DETAILS_MINUTES : STR_VEHICLE_DETAILS_DAYS;
2770  this->GetWidget<NWidgetCore>(WID_VD_SERVICE_INTERVAL_DROPDOWN)->widget_data = str;
2771 
2772  this->DrawWidgets();
2773  }
2774 
2775  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2776  {
2777  switch (widget) {
2778  case WID_VD_INCREASE_SERVICING_INTERVAL: // increase int
2779  case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int
2780  const Vehicle *v = Vehicle::Get(this->window_number);
2781  int mod;
2782  if (!v->ServiceIntervalIsPercent() && TimerGameEconomy::UsingWallclockUnits()) {
2783  mod = _ctrl_pressed ? 1 : 5;
2784  } else {
2785  mod = _ctrl_pressed ? 5 : 10;
2786  }
2787 
2788  mod = (widget == WID_VD_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
2789  mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent());
2790  if (mod == v->GetServiceInterval()) return;
2791 
2792  Command<CMD_CHANGE_SERVICE_INT>::Post(STR_ERROR_CAN_T_CHANGE_SERVICING, v->index, mod, true, v->ServiceIntervalIsPercent());
2793  break;
2794  }
2795 
2797  const Vehicle *v = Vehicle::Get(this->window_number);
2798  ShowDropDownMenu(this,
2799  TimerGameEconomy::UsingWallclockUnits() ? _service_interval_dropdown_wallclock : _service_interval_dropdown_calendar,
2800  v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0);
2801  break;
2802  }
2803 
2808  this->SetWidgetsLoweredState(false,
2813 
2814  this->tab = (TrainDetailsWindowTabs)(widget - WID_VD_DETAILS_CARGO_CARRIED);
2815  this->SetDirty();
2816  break;
2817  }
2818  }
2819 
2820  bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
2821  {
2823  const Vehicle *v = Vehicle::Get(this->window_number);
2824  StringID tool_tip;
2825  if (v->ServiceIntervalIsPercent()) {
2826  tool_tip = widget == WID_VD_INCREASE_SERVICING_INTERVAL ? STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP_PERCENT : STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP_PERCENT;
2828  tool_tip = widget == WID_VD_INCREASE_SERVICING_INTERVAL ? STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP_MINUTES : STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP_MINUTES;
2829  } else {
2830  tool_tip = widget == WID_VD_INCREASE_SERVICING_INTERVAL ? STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP_DAYS : STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP_DAYS;
2831  }
2832  GuiShowTooltips(this, tool_tip, close_cond);
2833  return true;
2834  }
2835 
2836  return false;
2837  }
2838 
2839  void OnDropdownSelect(WidgetID widget, int index) override
2840  {
2841  switch (widget) {
2843  const Vehicle *v = Vehicle::Get(this->window_number);
2844  bool iscustom = index != 0;
2845  bool ispercent = iscustom ? (index == 2) : Company::Get(v->owner)->settings.vehicle.servint_ispercent;
2846  uint16_t interval = GetServiceIntervalClamped(v->GetServiceInterval(), ispercent);
2847  Command<CMD_CHANGE_SERVICE_INT>::Post(STR_ERROR_CAN_T_CHANGE_SERVICING, v->index, interval, iscustom, ispercent);
2848  break;
2849  }
2850  }
2851  }
2852 
2853  void OnResize() override
2854  {
2855  NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_VD_MATRIX);
2856  if (nwi != nullptr) {
2857  this->vscroll->SetCapacityFromWidget(this, WID_VD_MATRIX);
2858  }
2859  }
2860 };
2861 
2864  WDP_AUTO, "view_vehicle_details_train", 405, 178,
2866  0,
2868 );
2869 
2872  WDP_AUTO, "view_vehicle_details", 405, 113,
2874  0,
2876 );
2877 
2879 static void ShowVehicleDetailsWindow(const Vehicle *v)
2880 {
2883  AllocateWindowDescFront<VehicleDetailsWindow>((v->type == VEH_TRAIN) ? _train_vehicle_details_desc : _nontrain_vehicle_details_desc, v->index);
2884 }
2885 
2886 
2887 /* Unified vehicle GUI - Vehicle View Window */
2888 
2892  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2893  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_RENAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetDataTip(SPR_RENAME, STR_NULL /* filled in later */),
2894  NWidget(WWT_CAPTION, COLOUR_GREY, WID_VV_CAPTION), SetDataTip(STR_VEHICLE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2895  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_LOCATION), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetDataTip(SPR_GOTO_LOCATION, STR_NULL /* filled in later */),
2896  NWidget(WWT_DEBUGBOX, COLOUR_GREY),
2897  NWidget(WWT_SHADEBOX, COLOUR_GREY),
2898  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
2899  NWidget(WWT_STICKYBOX, COLOUR_GREY),
2900  EndContainer(),
2902  NWidget(WWT_PANEL, COLOUR_GREY),
2903  NWidget(WWT_INSET, COLOUR_GREY), SetPadding(2, 2, 2, 2),
2904  NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_VV_VIEWPORT), SetMinimalSize(226, 84), SetResize(1, 1),
2905  EndContainer(),
2906  EndContainer(),
2909  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_GOTO_DEPOT), SetMinimalSize(18, 18), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */),
2910  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CLONE), SetMinimalSize(18, 18), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */),
2911  EndContainer(),
2912  /* For trains only, 'ignore signal' button. */
2914  SetDataTip(SPR_IGNORE_SIGNALS, STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP),
2916  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_REFIT), SetMinimalSize(18, 18), SetDataTip(SPR_REFIT_VEHICLE, 0x0 /* filled later */),
2917  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_TURN_AROUND), SetMinimalSize(18, 18),
2918  SetDataTip(SPR_FORCE_VEHICLE_TURN, STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP),
2919  EndContainer(),
2920  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_ORDERS), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_ORDERS, 0x0 /* filled later */),
2921  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_DETAILS), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_VEHICLE_DETAILS, 0x0 /* filled later */),
2922  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(18, 0), SetResize(0, 1), EndContainer(),
2923  EndContainer(),
2924  EndContainer(),
2926  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_VV_START_STOP), SetResize(1, 0), SetFill(1, 0),
2927  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_ORDER_LOCATION), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetDataTip(SPR_GOTO_LOCATION, STR_VEHICLE_VIEW_ORDER_LOCATION_TOOLTIP),
2928  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
2929  EndContainer(),
2930 };
2931 
2932 /* Just to make sure, nobody has changed the vehicle type constants, as we are
2933  using them for array indexing in a number of places here. */
2934 static_assert(VEH_TRAIN == 0);
2935 static_assert(VEH_ROAD == 1);
2936 static_assert(VEH_SHIP == 2);
2937 static_assert(VEH_AIRCRAFT == 3);
2938 
2943  ZOOM_LVL_SHIP,
2945 };
2946 
2947 /* Constants for geometry of vehicle view viewport */
2948 static const int VV_INITIAL_VIEWPORT_WIDTH = 226;
2949 static const int VV_INITIAL_VIEWPORT_HEIGHT = 84;
2950 static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102;
2951 
2954  VCT_CMD_START_STOP = 0,
2955  VCT_CMD_CLONE_VEH,
2956  VCT_CMD_TURN_AROUND,
2957 };
2958 
2961  { // VCT_CMD_START_STOP
2962  STR_ERROR_CAN_T_STOP_START_TRAIN,
2963  STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE,
2964  STR_ERROR_CAN_T_STOP_START_SHIP,
2965  STR_ERROR_CAN_T_STOP_START_AIRCRAFT
2966  },
2967  { // VCT_CMD_CLONE_VEH
2968  STR_ERROR_CAN_T_BUY_TRAIN,
2969  STR_ERROR_CAN_T_BUY_ROAD_VEHICLE,
2970  STR_ERROR_CAN_T_BUY_SHIP,
2971  STR_ERROR_CAN_T_BUY_AIRCRAFT
2972  },
2973  { // VCT_CMD_TURN_AROUND
2974  STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN,
2975  STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN,
2976  INVALID_STRING_ID, // invalid for ships
2977  INVALID_STRING_ID // invalid for aircraft
2978  },
2979 };
2980 
2986 void CcStartStopVehicle(Commands, const CommandCost &result, VehicleID veh_id, bool)
2987 {
2988  if (result.Failed()) return;
2989 
2990  const Vehicle *v = Vehicle::GetIfValid(veh_id);
2991  if (v == nullptr || !v->IsPrimaryVehicle() || v->owner != _local_company) return;
2992 
2993  StringID msg = (v->vehstatus & VS_STOPPED) ? STR_VEHICLE_COMMAND_STOPPED : STR_VEHICLE_COMMAND_STARTED;
2994  Point pt = RemapCoords(v->x_pos, v->y_pos, v->z_pos);
2995  AddTextEffect(msg, pt.x, pt.y, Ticks::DAY_TICKS, TE_RISING);
2996 }
2997 
3003 void StartStopVehicle(const Vehicle *v, bool texteffect)
3004 {
3005  assert(v->IsPrimaryVehicle());
3006  Command<CMD_START_STOP_VEHICLE>::Post(_vehicle_msg_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : nullptr, v->tile, v->index, false);
3007 }
3008 
3010 static bool IsVehicleRefitable(const Vehicle *v)
3011 {
3012  if (!v->IsStoppedInDepot()) return false;
3013 
3014  do {
3015  if (IsEngineRefittable(v->engine_type)) return true;
3016  } while (v->IsGroundVehicle() && (v = v->Next()) != nullptr);
3017 
3018  return false;
3019 }
3020 
3023 private:
3028 
3031 
3034  };
3035  bool mouse_over_start_stop = false;
3036 
3042  {
3043  switch (plane) {
3044  case SEL_DC_GOTO_DEPOT:
3045  case SEL_DC_CLONE:
3046  this->GetWidget<NWidgetStacked>(WID_VV_SELECT_DEPOT_CLONE)->SetDisplayedPlane(plane - SEL_DC_BASEPLANE);
3047  break;
3048 
3049  case SEL_RT_REFIT:
3050  case SEL_RT_TURN_AROUND:
3051  this->GetWidget<NWidgetStacked>(WID_VV_SELECT_REFIT_TURN)->SetDisplayedPlane(plane - SEL_RT_BASEPLANE);
3052  break;
3053 
3054  default:
3055  NOT_REACHED();
3056  }
3057  }
3058 
3059 public:
3061  {
3062  this->flags |= WF_DISABLE_VP_SCROLL;
3063  this->CreateNestedTree();
3064 
3065  /* Sprites for the 'send to depot' button indexed by vehicle type. */
3066  static const SpriteID vehicle_view_goto_depot_sprites[] = {
3067  SPR_SEND_TRAIN_TODEPOT,
3068  SPR_SEND_ROADVEH_TODEPOT,
3069  SPR_SEND_SHIP_TODEPOT,
3070  SPR_SEND_AIRCRAFT_TODEPOT,
3071  };
3072  const Vehicle *v = Vehicle::Get(window_number);
3073  this->GetWidget<NWidgetCore>(WID_VV_GOTO_DEPOT)->widget_data = vehicle_view_goto_depot_sprites[v->type];
3074 
3075  /* Sprites for the 'clone vehicle' button indexed by vehicle type. */
3076  static const SpriteID vehicle_view_clone_sprites[] = {
3078  SPR_CLONE_ROADVEH,
3079  SPR_CLONE_SHIP,
3080  SPR_CLONE_AIRCRAFT,
3081  };
3082  this->GetWidget<NWidgetCore>(WID_VV_CLONE)->widget_data = vehicle_view_clone_sprites[v->type];
3083 
3084  switch (v->type) {
3085  case VEH_TRAIN:
3086  this->GetWidget<NWidgetCore>(WID_VV_TURN_AROUND)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP;
3087  break;
3088 
3089  case VEH_ROAD:
3090  break;
3091 
3092  case VEH_SHIP:
3093  case VEH_AIRCRAFT:
3094  this->SelectPlane(SEL_RT_REFIT);
3095  break;
3096 
3097  default: NOT_REACHED();
3098  }
3099  this->FinishInitNested(window_number);
3100  this->owner = v->owner;
3101  this->GetWidget<NWidgetViewport>(WID_VV_VIEWPORT)->InitializeViewport(this, static_cast<VehicleID>(this->window_number), ScaleZoomGUI(_vehicle_view_zoom_levels[v->type]));
3102 
3103  this->GetWidget<NWidgetCore>(WID_VV_START_STOP)->tool_tip = STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP + v->type;
3104  this->GetWidget<NWidgetCore>(WID_VV_RENAME)->tool_tip = STR_VEHICLE_DETAILS_TRAIN_RENAME + v->type;
3105  this->GetWidget<NWidgetCore>(WID_VV_LOCATION)->tool_tip = STR_VEHICLE_VIEW_TRAIN_CENTER_TOOLTIP + v->type;
3106  this->GetWidget<NWidgetCore>(WID_VV_REFIT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP + v->type;
3107  this->GetWidget<NWidgetCore>(WID_VV_GOTO_DEPOT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + v->type;
3108  this->GetWidget<NWidgetCore>(WID_VV_SHOW_ORDERS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP + v->type;
3109  this->GetWidget<NWidgetCore>(WID_VV_SHOW_DETAILS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP + v->type;
3110  this->GetWidget<NWidgetCore>(WID_VV_CLONE)->tool_tip = STR_VEHICLE_VIEW_CLONE_TRAIN_INFO + v->type;
3111 
3112  this->UpdateButtonStatus();
3113  }
3114 
3115  void Close([[maybe_unused]] int data = 0) override
3116  {
3117  CloseWindowById(WC_VEHICLE_ORDERS, this->window_number, false);
3118  CloseWindowById(WC_VEHICLE_REFIT, this->window_number, false);
3119  CloseWindowById(WC_VEHICLE_DETAILS, this->window_number, false);
3120  CloseWindowById(WC_VEHICLE_TIMETABLE, this->window_number, false);
3121  this->Window::Close();
3122  }
3123 
3124  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
3125  {
3126  const Vehicle *v = Vehicle::Get(this->window_number);
3127  switch (widget) {
3128  case WID_VV_START_STOP:
3129  size.height = std::max<uint>({size.height, (uint)GetCharacterHeight(FS_NORMAL), GetScaledSpriteSize(SPR_WARNING_SIGN).height, GetScaledSpriteSize(SPR_FLAG_VEH_STOPPED).height, GetScaledSpriteSize(SPR_FLAG_VEH_RUNNING).height}) + padding.height;
3130  break;
3131 
3132  case WID_VV_FORCE_PROCEED:
3133  if (v->type != VEH_TRAIN) {
3134  size.height = 0;
3135  size.width = 0;
3136  }
3137  break;
3138 
3139  case WID_VV_VIEWPORT:
3140  size.width = VV_INITIAL_VIEWPORT_WIDTH;
3141  size.height = (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT;
3142  break;
3143  }
3144  }
3145 
3146  void OnPaint() override
3147  {
3148  const Vehicle *v = Vehicle::Get(this->window_number);
3149  bool is_localcompany = v->owner == _local_company;
3150  bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
3151 
3152  this->SetWidgetDisabledState(WID_VV_RENAME, !is_localcompany);
3153  this->SetWidgetDisabledState(WID_VV_GOTO_DEPOT, !is_localcompany);
3154  this->SetWidgetDisabledState(WID_VV_REFIT, !refitable_and_stopped_in_depot || !is_localcompany);
3155  this->SetWidgetDisabledState(WID_VV_CLONE, !is_localcompany);
3156 
3157  if (v->type == VEH_TRAIN) {
3159  this->SetWidgetDisabledState(WID_VV_FORCE_PROCEED, !is_localcompany);
3160  }
3161 
3162  if (v->type == VEH_TRAIN || v->type == VEH_ROAD) {
3163  this->SetWidgetDisabledState(WID_VV_TURN_AROUND, !is_localcompany);
3164  }
3165 
3167 
3168  this->DrawWidgets();
3169  }
3170 
3171  void SetStringParameters(WidgetID widget) const override
3172  {
3173  if (widget != WID_VV_CAPTION) return;
3174 
3175  const Vehicle *v = Vehicle::Get(this->window_number);
3176  SetDParam(0, v->index);
3177  }
3178 
3179  void DrawWidget(const Rect &r, WidgetID widget) const override
3180  {
3181  if (widget != WID_VV_START_STOP) return;
3182 
3183  Vehicle *v = Vehicle::Get(this->window_number);
3184  StringID str;
3185  TextColour text_colour = TC_FROMSTRING;
3186  if (v->vehstatus & VS_CRASHED) {
3187  str = STR_VEHICLE_STATUS_CRASHED;
3188  } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary?
3189  str = STR_VEHICLE_STATUS_BROKEN_DOWN;
3190  } else if (v->vehstatus & VS_STOPPED && (!mouse_over_start_stop || v->IsStoppedInDepot())) {
3191  if (v->type == VEH_TRAIN) {
3192  if (v->cur_speed == 0) {
3193  if (Train::From(v)->gcache.cached_power == 0) {
3194  str = STR_VEHICLE_STATUS_TRAIN_NO_POWER;
3195  } else {
3196  str = STR_VEHICLE_STATUS_STOPPED;
3197  }
3198  } else {
3200  str = STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL;
3201  }
3202  } else { // no train
3203  str = STR_VEHICLE_STATUS_STOPPED;
3204  }
3205  } else if (v->IsInDepot() && v->IsWaitingForUnbunching()) {
3206  str = STR_VEHICLE_STATUS_WAITING_UNBUNCHING;
3207  } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) {
3208  str = STR_VEHICLE_STATUS_TRAIN_STUCK;
3209  } else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) {
3210  str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR;
3211  } else { // vehicle is in a "normal" state, show current order
3212  if (mouse_over_start_stop) {
3213  if (v->vehstatus & VS_STOPPED) {
3214  text_colour = TC_RED | TC_FORCED;
3215  } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) {
3216  text_colour = TC_ORANGE | TC_FORCED;
3217  }
3218  }
3219  switch (v->current_order.GetType()) {
3220  case OT_GOTO_STATION: {
3223  str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_STATION_VEL : STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL;
3224  break;
3225  }
3226 
3227  case OT_GOTO_DEPOT: {
3228  SetDParam(0, v->type);
3231  if (v->current_order.GetDestination() == INVALID_DEPOT) {
3232  /* This case *only* happens when multiple nearest depot orders
3233  * follow each other (including an order list only one order: a
3234  * nearest depot order) and there are no reachable depots.
3235  * It is primarily to guard for the case that there is no
3236  * depot with index 0, which would be used as fallback for
3237  * evaluating the string in the status bar. */
3238  str = STR_EMPTY;
3239  } else if (v->current_order.GetDepotActionType() & ODATFB_HALT) {
3240  str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_VEL : STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL;
3241  } else if (v->current_order.GetDepotActionType() & ODATFB_UNBUNCH) {
3242  str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_SERVICE_VEL : STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_UNBUNCH_VEL;
3243  } else {
3244  str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_SERVICE_VEL : STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL;
3245  }
3246  break;
3247  }
3248 
3249  case OT_LOADING:
3250  str = STR_VEHICLE_STATUS_LOADING_UNLOADING;
3251  break;
3252 
3253  case OT_GOTO_WAYPOINT: {
3254  assert(v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP);
3256  str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_WAYPOINT_VEL : STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL;
3258  break;
3259  }
3260 
3261  case OT_LEAVESTATION:
3262  if (v->type != VEH_AIRCRAFT) {
3263  str = STR_VEHICLE_STATUS_LEAVING;
3264  break;
3265  }
3266  [[fallthrough]];
3267  default:
3268  if (v->GetNumManualOrders() == 0) {
3269  str = STR_VEHICLE_STATUS_NO_ORDERS_VEL;
3271  } else {
3272  str = STR_EMPTY;
3273  }
3274  break;
3275  }
3276  }
3277 
3278  /* Draw the flag plus orders. */
3279  bool rtl = (_current_text_dir == TD_RTL);
3280  uint icon_width = std::max({GetScaledSpriteSize(SPR_WARNING_SIGN).width, GetScaledSpriteSize(SPR_FLAG_VEH_STOPPED).width, GetScaledSpriteSize(SPR_FLAG_VEH_RUNNING).width});
3281  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
3282  SpriteID image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : (HasBit(v->vehicle_flags, VF_PATHFINDER_LOST)) ? SPR_WARNING_SIGN : SPR_FLAG_VEH_RUNNING;
3283  DrawSpriteIgnorePadding(image, PAL_NONE, tr.WithWidth(icon_width, rtl), SA_CENTER);
3284  tr = tr.Indent(icon_width + WidgetDimensions::scaled.imgbtn.Horizontal(), rtl);
3285  DrawString(tr.left, tr.right, CenterBounds(tr.top, tr.bottom, GetCharacterHeight(FS_NORMAL)), str, text_colour, SA_HOR_CENTER);
3286  }
3287 
3288  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
3289  {
3290  const Vehicle *v = Vehicle::Get(this->window_number);
3291 
3292  switch (widget) {
3293  case WID_VV_RENAME: { // rename
3294  SetDParam(0, v->index);
3295  ShowQueryString(STR_VEHICLE_NAME, STR_QUERY_RENAME_TRAIN_CAPTION + v->type,
3297  break;
3298  }
3299 
3300  case WID_VV_START_STOP: // start stop
3301  StartStopVehicle(v, false);
3302  break;
3303 
3304  case WID_VV_ORDER_LOCATION: {
3305  /* Scroll to current order destination */
3306  TileIndex tile = v->current_order.GetLocation(v);
3307  if (tile == INVALID_TILE) break;
3308 
3309  if (_ctrl_pressed) {
3311  } else {
3312  ScrollMainWindowToTile(tile);
3313  }
3314  break;
3315  }
3316 
3317  case WID_VV_LOCATION: // center main view
3318  if (_ctrl_pressed) {
3320  } else {
3321  const Window *mainwindow = GetMainWindow();
3322  if (click_count > 1) {
3323  /* main window 'follows' vehicle */
3324  mainwindow->viewport->follow_vehicle = v->index;
3325  } else {
3326  ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos);
3327  }
3328  }
3329  break;
3330 
3331  case WID_VV_GOTO_DEPOT: // goto hangar
3333  break;
3334  case WID_VV_REFIT: // refit
3336  break;
3337  case WID_VV_SHOW_ORDERS: // show orders
3338  if (_ctrl_pressed) {
3340  } else {
3341  ShowOrdersWindow(v);
3342  }
3343  break;
3344  case WID_VV_SHOW_DETAILS: // show details
3345  if (_ctrl_pressed) {
3347  } else {
3349  }
3350  break;
3351  case WID_VV_CLONE: // clone vehicle
3352  /* Suppress the vehicle GUI when share-cloning.
3353  * There is no point to it except for starting the vehicle.
3354  * For starting the vehicle the player has to open the depot GUI, which is
3355  * most likely already open, but is also visible in the vehicle viewport. */
3357  _ctrl_pressed ? nullptr : CcCloneVehicle,
3358  v->tile, v->index, _ctrl_pressed);
3359  break;
3360  case WID_VV_TURN_AROUND: // turn around
3361  assert(v->IsGroundVehicle());
3362  if (v->type == VEH_ROAD) {
3364  } else {
3366  }
3367  break;
3368  case WID_VV_FORCE_PROCEED: // force proceed
3369  assert(v->type == VEH_TRAIN);
3370  Command<CMD_FORCE_TRAIN_PROCEED>::Post(STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL, v->tile, v->index);
3371  break;
3372  }
3373  }
3374 
3375  EventState OnHotkey(int hotkey) override
3376  {
3377  /* If the hotkey is not for any widget in the UI (i.e. for honking) */
3378  if (hotkey == WID_VV_HONK_HORN) {
3379  const Window *mainwindow = GetMainWindow();
3380  const Vehicle *v = Vehicle::Get(window_number);
3381  /* Only play the sound if we're following this vehicle */
3382  if (mainwindow->viewport->follow_vehicle == v->index) {
3383  v->PlayLeaveStationSound(true);
3384  }
3385  }
3386  return Window::OnHotkey(hotkey);
3387  }
3388 
3389  void OnQueryTextFinished(std::optional<std::string> str) override
3390  {
3391  if (!str.has_value()) return;
3392 
3393  Command<CMD_RENAME_VEHICLE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type, this->window_number, *str);
3394  }
3395 
3396  void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
3397  {
3398  bool start_stop = widget == WID_VV_START_STOP;
3399  if (start_stop != mouse_over_start_stop) {
3400  mouse_over_start_stop = start_stop;
3402  }
3403  }
3404 
3405  void OnMouseWheel(int wheel) override
3406  {
3408  DoZoomInOutWindow(wheel < 0 ? ZOOM_IN : ZOOM_OUT, this);
3409  }
3410  }
3411 
3412  void OnResize() override
3413  {
3414  if (this->viewport != nullptr) {
3415  NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_VV_VIEWPORT);
3416  nvp->UpdateViewportCoordinates(this);
3417  }
3418  }
3419 
3420  void UpdateButtonStatus()
3421  {
3422  const Vehicle *v = Vehicle::Get(this->window_number);
3423  bool veh_stopped = v->IsStoppedInDepot();
3424 
3425  /* Widget WID_VV_GOTO_DEPOT must be hidden if the vehicle is already stopped in depot.
3426  * Widget WID_VV_CLONE_VEH should then be shown, since cloning is allowed only while in depot and stopped.
3427  */
3428  PlaneSelections plane = veh_stopped ? SEL_DC_CLONE : SEL_DC_GOTO_DEPOT;
3429  NWidgetStacked *nwi = this->GetWidget<NWidgetStacked>(WID_VV_SELECT_DEPOT_CLONE); // Selection widget 'send to depot' / 'clone'.
3430  if (nwi->shown_plane + SEL_DC_BASEPLANE != plane) {
3431  this->SelectPlane(plane);
3433  }
3434  /* The same system applies to widget WID_VV_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/
3435  if (v->IsGroundVehicle()) {
3436  plane = veh_stopped ? SEL_RT_REFIT : SEL_RT_TURN_AROUND;
3437  nwi = this->GetWidget<NWidgetStacked>(WID_VV_SELECT_REFIT_TURN);
3438  if (nwi->shown_plane + SEL_RT_BASEPLANE != plane) {
3439  this->SelectPlane(plane);
3441  }
3442  }
3443  }
3444 
3450  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
3451  {
3452  if (data == VIWD_AUTOREPLACE) {
3453  /* Autoreplace replaced the vehicle.
3454  * Nothing to do for this window. */
3455  return;
3456  }
3457 
3458  this->UpdateButtonStatus();
3459  }
3460 
3461  bool IsNewGRFInspectable() const override
3462  {
3463  return ::IsNewGRFInspectable(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number);
3464  }
3465 
3466  void ShowNewGRFInspectWindow() const override
3467  {
3468  ::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number);
3469  }
3470 
3471  static inline HotkeyList hotkeys{"vehicleview", {
3472  Hotkey('H', "honk", WID_VV_HONK_HORN),
3473  }};
3474 };
3475 
3478  WDP_AUTO, "view_vehicle", 250, 116,
3480  0,
3482  &VehicleViewWindow::hotkeys
3483 );
3484 
3490  WDP_AUTO, "view_vehicle_train", 250, 134,
3492  0,
3494  &VehicleViewWindow::hotkeys
3495 );
3496 
3499 {
3500  AllocateWindowDescFront<VehicleViewWindow>((v->type == VEH_TRAIN) ? _train_view_desc : _vehicle_view_desc, v->index);
3501 }
3502 
3508 bool VehicleClicked(const Vehicle *v)
3509 {
3510  assert(v != nullptr);
3511  if (!(_thd.place_mode & HT_VEHICLE)) return false;
3512 
3513  v = v->First();
3514  if (!v->IsPrimaryVehicle()) return false;
3515 
3516  return _thd.GetCallbackWnd()->OnVehicleSelect(v);
3517 }
3518 
3525 bool VehicleClicked(VehicleList::const_iterator begin, VehicleList::const_iterator end)
3526 {
3527  assert(begin != end);
3528  if (!(_thd.place_mode & HT_VEHICLE)) return false;
3529 
3530  /* If there is only one vehicle in the group, act as if we clicked a single vehicle */
3531  if (begin + 1 == end) return _thd.GetCallbackWnd()->OnVehicleSelect(*begin);
3532 
3533  return _thd.GetCallbackWnd()->OnVehicleSelect(begin, end);
3534 }
3535 
3541 bool VehicleClicked(const GUIVehicleGroup &vehgroup)
3542 {
3543  return VehicleClicked(vehgroup.vehicles_begin, vehgroup.vehicles_end);
3544 }
3545 
3546 void StopGlobalFollowVehicle(const Vehicle *v)
3547 {
3548  Window *w = GetMainWindow();
3549  if (w->viewport->follow_vehicle == v->index) {
3550  ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos, true); // lock the main view on the vehicle's last position
3552  }
3553 }
3554 
3555 
3561 void CcBuildPrimaryVehicle(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray)
3562 {
3563  if (result.Failed()) return;
3564 
3565  const Vehicle *v = Vehicle::Get(new_veh_id);
3567 }
3568 
3575 {
3576  switch (v->type) {
3577  case VEH_TRAIN:
3578  return Train::From(v)->GetDisplayImageWidth();
3579 
3580  case VEH_ROAD:
3581  return RoadVehicle::From(v)->GetDisplayImageWidth();
3582 
3583  default:
3584  bool rtl = _current_text_dir == TD_RTL;
3585  VehicleSpriteSeq seq;
3586  v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq);
3587  Rect rec;
3588  seq.GetBounds(&rec);
3589  return UnScaleGUI(rec.Width());
3590  }
3591 }
3592 
3598 int GetVehicleWidth(const Vehicle *v, EngineImageType image_type)
3599 {
3600  if (v->type == VEH_TRAIN || v->type == VEH_ROAD) {
3601  int vehicle_width = 0;
3602  for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
3603  vehicle_width += GetSingleVehicleWidth(u, image_type);
3604  }
3605  return vehicle_width;
3606  } else {
3607  return GetSingleVehicleWidth(v, image_type);
3608  }
3609 }
3610 
3617 {
3618  bool rtl = _current_text_dir == TD_RTL;
3619 
3620  _cursor.sprites.clear();
3621  int total_width = 0;
3622  int y_offset = 0;
3623  bool rotor_seq = false; // Whether to draw the rotor of the vehicle in this step.
3624  bool is_ground_vehicle = v->IsGroundVehicle();
3625 
3626  while (v != nullptr) {
3627  if (total_width >= ScaleSpriteTrad(2 * (int)VEHICLEINFO_FULL_VEHICLE_WIDTH)) break;
3628 
3630  VehicleSpriteSeq seq;
3631 
3632  if (rotor_seq) {
3633  GetCustomRotorSprite(Aircraft::From(v), image_type, &seq);
3634  if (!seq.IsValid()) seq.Set(SPR_ROTOR_STOPPED);
3635  y_offset = -ScaleSpriteTrad(5);
3636  } else {
3637  v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq);
3638  }
3639 
3640  int x_offs = 0;
3641  if (v->type == VEH_TRAIN) x_offs = Train::From(v)->GetCursorImageOffset();
3642 
3643  for (uint i = 0; i < seq.count; ++i) {
3644  PaletteID pal2 = (v->vehstatus & VS_CRASHED) || !seq.seq[i].pal ? pal : seq.seq[i].pal;
3645  _cursor.sprites.emplace_back(seq.seq[i].sprite, pal2, rtl ? (-total_width + x_offs) : (total_width + x_offs), y_offset);
3646  }
3647 
3648  if (v->type == VEH_AIRCRAFT && v->subtype == AIR_HELICOPTER && !rotor_seq) {
3649  /* Draw rotor part in the next step. */
3650  rotor_seq = true;
3651  } else {
3652  total_width += GetSingleVehicleWidth(v, image_type);
3653  v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr;
3654  }
3655  }
3656 
3657  if (is_ground_vehicle) {
3658  /* Center trains and road vehicles on the front vehicle */
3659  int offs = (ScaleSpriteTrad(VEHICLEINFO_FULL_VEHICLE_WIDTH) - total_width) / 2;
3660  if (rtl) offs = -offs;
3661  for (auto &cs : _cursor.sprites) {
3662  cs.pos.x += offs;
3663  }
3664  }
3665 
3666  UpdateCursorSize();
3667 }
Base for aircraft.
@ VAF_DEST_TOO_FAR
Next destination is too far away.
Definition: aircraft.h:37
@ AIR_HELICOPTER
an helicopter
Definition: aircraft.h:29
void DrawAircraftImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type)
Draws an image of an aircraft.
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
Ors the refit_masks of all articulated parts.
Functions related to articulated vehicles.
void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype)
Show the autoreplace configuration window for a particular group.
Functions related to the autoreplace GUIs.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool HasAtMostOneBit(T value)
Test whether value has at most 1 bit set.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition: cargo_type.h:107
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
Definition: cargotype.cpp:153
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Definition: cargotype.cpp:180
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition: cargotype.cpp:31
bool IsCargoInClass(CargoID c, CargoClass cc)
Does cargo c have cargo class cc?
Definition: cargotype.h:232
@ CC_PASSENGERS
Passengers.
Definition: cargotype.h:50
Common return value for all commands.
Definition: command_type.h:23
bool Failed() const
Did this command fail?
Definition: command_type.h:171
static constexpr int DAYS_IN_ECONOMY_MONTH
Days in an economy month, when in wallclock timekeeping mode.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetListing(Listing l)
Import sort conditions.
void SetFilterState(bool state)
Enable or disable the filter.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
bool(const GUIVehicleGroup *, CargoID) FilterFunction
Signature of filter function.
Definition: sortlist_type.h:50
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
bool NeedRebuild() const
Check if a rebuild is needed.
void SetFilterType(uint8_t n_type)
Set the filtertype of the list.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
Listing GetListing() const
Export current sort conditions.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
Baseclass for nested widgets.
Definition: widget_type.h:144
virtual void SetDirty(const Window *w) const
Mark the widget as 'dirty' (in need of repaint).
Definition: widget.cpp:903
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:243
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:248
uint current_y
Current vertical size (after resizing).
Definition: widget_type.h:244
Base class for a 'real' widget.
Definition: widget_type.h:370
uint32_t widget_data
Data of the widget.
Definition: widget_type.h:393
StringID tool_tip
Tooltip of the widget.
Definition: widget_type.h:394
Stacked widgets, widgets all occupying the same space in the window.
Definition: widget_type.h:498
int shown_plane
Plane being displayed (for NWID_SELECTION only).
Definition: widget_type.h:512
bool SetDisplayedPlane(int plane)
Select which plane to show (for NWID_SELECTION only).
Definition: widget.cpp:1342
Nested widget to display a viewport in a window.
Definition: widget_type.h:680
void UpdateViewportCoordinates(Window *w)
Update the position and size of the viewport (after eg a resize).
Definition: widget.cpp:2297
Scrollbar data structure.
Definition: widget_type.h:694
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
Definition: widget_type.h:879
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:2320
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition: widget.cpp:2394
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
Definition: widget_type.h:841
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Definition: widget_type.h:860
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:740
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr int MONTHS_IN_YEAR
months per year
static constexpr TimerGame< struct Economy >::Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date,...
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
static Date date
Current date in days (day counter).
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static constexpr Year DateToYear(Date date)
Calculate the year of a given date.
static constexpr Date DateAtStartOfYear(Year year)
Calculate the date of the first day of a given year.
RectPadding framerect
Standard padding inside many panels.
Definition: window_gui.h:42
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
int vsep_normal
Normal vertical spacing.
Definition: window_gui.h:60
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
RectPadding matrix
Padding of WWT_MATRIX items.
Definition: window_gui.h:44
int hsep_normal
Normal horizontal spacing.
Definition: window_gui.h:63
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition: window_gui.h:40
Functions related to commands.
@ DC_QUERY_COST
query cost only, don't build.
Definition: command_type.h:378
Commands
List of commands.
Definition: command_type.h:187
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ OWNER_NONE
The tile has no ownership.
Definition: company_type.h:25
Some simple functions to help with accessing containers.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
Command definitions related to depots.
void CcCloneVehicle(Commands cmd, const CommandCost &result, VehicleID veh_id)
This is the Callback method after the cloning attempt of a vehicle.
Definition: depot_gui.cpp:123
Map related accessors for depots.
DepotID GetDepotIndex(Tile t)
Get the index of which depot is attached to the tile.
Definition: depot_map.h:52
@ DIR_W
West.
@ DIR_E
East.
void ShowDropDownMenu(Window *w, std::span< const StringID > strings, int selected, WidgetID button, uint32_t disabled_mask, uint32_t hidden_mask, uint width)
Show a dropdown menu window near a widget of the parent window.
Definition: dropdown.cpp:441
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition: dropdown.cpp:404
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
Definition: dropdown.cpp:363
Functions related to the drop down widget.
Types related to the drop down widget.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
Definition: dropdown_type.h:50
bool IsEngineRefittable(EngineID engine)
Check if an engine is refittable.
Definition: engine.cpp:1259
Functions related to engines.
uint16_t EngineID
Unique identification number of an engine.
Definition: engine_type.h:21
@ EF_AUTO_REFIT
Automatic refitting is allowed.
Definition: engine_type.h:173
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:77
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
void UpdateCursorSize()
Update cursor dimension.
Definition: gfx.cpp:1598
bool _shift_pressed
Is Shift pressed?
Definition: gfx.cpp:39
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:851
Dimension GetStringListBoundingBox(std::span< const StringID > list, FontSize fontsize)
Get maximum dimension of a list of strings.
Definition: gfx.cpp:889
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:38
uint GetStringListWidth(std::span< const StringID > list, FontSize fontsize)
Get maximum width of a list of strings.
Definition: gfx.cpp:874
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:988
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:774
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition: widget.cpp:54
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition: gfx_func.h:166
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
@ SA_LEFT
Left align the text.
Definition: gfx_type.h:343
@ SA_HOR_CENTER
Horizontally center the text.
Definition: gfx_type.h:344
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_type.h:353
@ FS_SMALL
Index of the small font in the font tables.
Definition: gfx_type.h:210
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:260
@ TC_FORCED
Ignore colour changes from strings.
Definition: gfx_type.h:285
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition: widget_type.h:1181
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1284
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
Definition: widget_type.h:1228
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1137
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
Definition: widget_type.h:1214
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
Definition: widget_type.h:1149
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlags::ResizeX)
Widget part function for setting the aspect ratio.
Definition: widget_type.h:1295
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
Command definitions related to engine groups.
void CcAddVehicleNewGroup(Commands cmd, const CommandCost &result, GroupID new_group, GroupID, VehicleID veh_id, bool, const VehicleListIdentifier &)
Open rename window after adding a vehicle to a new group via drag and drop.
Definition: group_gui.cpp:1240
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:940
void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group, bool need_existing_window)
Show the group window for the given company and vehicle type.
Definition: group_gui.cpp:1175
void ShowCompanyGroupForVehicle(const Vehicle *v)
Show the group window for the given vehicle.
Definition: group_gui.cpp:1194
Functions/definitions that have something to do with groups.
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition: group_type.h:17
static const GroupID NEW_GROUP
Sentinel for a to-be-created group.
Definition: group_type.h:15
static const GroupID ALL_GROUP
All vehicles are in this group.
Definition: group_type.h:16
GUI functions that shouldn't be here.
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Hotkey related functions.
Point RemapCoords(int x, int y, int z)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap.
Definition: landscape.h:79
bool DoZoomInOutWindow(ZoomStateChange how, Window *w)
Zooms a viewport in a window in or out.
Definition: main_gui.cpp:93
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:404
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
Definition: math_func.hpp:306
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
void MemSetT(T *ptr, uint8_t value, size_t num=1)
Type-safe version of memset().
Definition: mem_func.hpp:49
void GuiShowTooltips(Window *parent, StringID str, TooltipCloseCondition close_tooltip, uint paramcount)
Shows a tooltip.
Definition: misc_gui.cpp:760
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1079
static constexpr CargoID CF_NONE
Show only items which do not carry cargo (e.g. train engines)
Definition: cargo_type.h:95
static constexpr CargoID CF_ANY
Show all items independent of carried cargo (i.e. no filtering)
Definition: cargo_type.h:94
static constexpr CargoID CF_FREIGHT
Show only vehicles which carry any freight (non-passenger) cargo.
Definition: cargo_type.h:97
@ CBID_VEHICLE_CARGO_SUFFIX
Determine the cargo "suffixes" for each refit possibility of a cargo.
@ CBM_VEHICLE_CARGO_SUFFIX
Show suffix after cargo name.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
Functions/types related to NewGRF debugging.
GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
Get the GrfSpecFeature associated with the tile.
bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
Can we inspect the data given a certain feature and index.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
StringID GetGRFStringID(uint32_t grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
Clamp the service interval to the correct min/max.
Definition: order_cmd.cpp:1901
Command definitions related to orders.
@ ODATFB_UNBUNCH
Service the vehicle and then unbunch it.
Definition: order_type.h:106
@ ODATFB_HALT
Service the vehicle and then halt it.
Definition: order_type.h:104
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition: order_type.h:15
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition: order_type.h:21
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition: palette.cpp:314
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:307
Road vehicle states.
Command definitions related to road vehicles.
void DrawRoadVehImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type, int skip)
Draws an image of a road vehicle chain.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
@ SWS_OFF
Scroll wheel has no effect.
void DrawShipImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type)
Draws an image of a ship.
Definition: ship_gui.cpp:30
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
Scrolls the main window to given coordinates.
Functions to cache sprites in memory.
static const PaletteID PALETTE_ALL_BLACK
Exchange any color by black, needed for painting fictive tiles outside map.
Definition: sprites.h:1611
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1605
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition: sprites.h:1390
static const SpriteID SPR_CLONE_TRAIN
Clone vehicles stuff.
Definition: sprites.h:100
Base classes/functions for stations.
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition: station_map.h:28
Definition of base types and functions in a cross-platform compatible way.
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:589
Functions related to low-level strings.
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:25
void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:127
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:319
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:56
void SetDParamMaxDigits(size_t n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:143
Functions related to OTTD's strings.
int64_t PackVelocity(uint speed, VehicleType type)
Pack velocity and vehicle type for use with SCC_VELOCITY string parameter.
Definition: strings_func.h:75
@ TD_RTL
Text is written right-to-left by default.
Definition: strings_type.h:24
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition: aircraft.h:72
std::string name
Name of vehicle.
Definition: base_consist.h:18
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition: base_consist.h:31
TimerGameTick::Ticks lateness_counter
How many ticks late (or early if negative) this vehicle is.
Definition: base_consist.h:22
uint16_t vehicle_flags
Used for gradual loading and other miscellaneous things (.
Definition: base_consist.h:34
CargoID cargo_filter_criteria
Selected cargo filter index.
VehicleListIdentifier vli
Identifier of the vehicle list we want to currently show.
void DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const
Draw all the vehicle list items.
VehicleID vehicle_sel
Selected vehicle.
Listing * sorting
Pointer to the vehicle type related sorting.
void SetCargoFilter(uint8_t index)
Set cargo filter for the vehicle group list.
GroupBy grouping
How we want to group the list.
Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group, bool show_create)
Compute the size for the Action dropdown.
uint order_arrow_width
Width of the arrow in the small order list.
uint8_t unitnumber_digits
The number of digits of the highest unit number.
DropDownList BuildActionDropdownList(bool show_autoreplace, bool show_group, bool show_create)
Display the Action dropdown window.
VehicleList vehicles
List of vehicles. This is the buffer for vehgroups to point into; if this is structurally modified,...
GUIVehicleGroupList vehgroups
List of (groups of) vehicles. This stores iterators of vehicles, and should be rebuilt if vehicles is...
void SetCargoFilterArray()
Populate the filter list and set the cargo filter criteria.
DropDownList BuildCargoDropDownList(bool full) const
Build drop down list for cargo filter selection.
void OnInit() override
Notification that the nested widget tree gets initialized.
void FilterVehicleList()
Filter the engine list against the currently selected cargo filter.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
Class for storing amounts of cargo.
Definition: cargo_type.h:114
Comparator to sort CargoID by according to desired order.
Definition: cargotype.h:240
Specification of a cargo type.
Definition: cargotype.h:71
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition: cargotype.cpp:166
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:134
StringID name
Name of this type of cargo.
Definition: cargotype.h:88
GUISettings gui
settings related to the GUI
std::vector< CursorSprite > sprites
Sprites comprising cursor.
Definition: gfx_type.h:136
Dimensions (a width and height) of a rectangle in 2D.
uint8_t misc_flags
Miscellaneous flags.
Definition: engine_type.h:155
uint16_t callback_mask
Bitmask of vehicle callbacks that have to be called.
Definition: engine_type.h:156
StringID GetAircraftTypeText() const
Get the name of the aircraft type for display purposes.
Definition: engine.cpp:467
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition: engine.cpp:168
bool show_cargo_in_vehicle_lists
Show the cargoes the vehicles can carry in the list windows.
uint8_t scrollwheel_scrolling
scrolling using the scroll wheel?
uint8_t advanced_vehicle_list
use the "advanced" vehicle list
VehicleList::const_iterator vehicles_end
Pointer to past-the-end element of this vehicle group.
VehicleList::const_iterator vehicles_begin
Pointer to beginning element of this vehicle group.
VehicleSettings vehicle
options for vehicles
Cached, frequently calculated values.
uint32_t cached_weight
Total weight of the consist (valid only for the first engine).
uint32_t cached_power
Total power of the consist (valid only for the first engine).
uint16_t cached_total_length
Length of the whole vehicle (valid only for the first engine).
uint32_t cached_max_te
Maximum tractive effort of consist (valid only for the first engine).
List of hotkeys for a window.
Definition: hotkeys.h:37
All data for a single hotkey.
Definition: hotkeys.h:21
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
Order * GetFirstOrder() const
Get the first order of the order chain.
Definition: order_base.h:297
TileIndex GetLocation(const Vehicle *v, bool airport=false) const
Returns a tile somewhat representing the order destination (not suitable for pathfinding).
Definition: order_cmd.cpp:642
DestinationID GetDestination() const
Gets the destination of this order.
Definition: order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:70
OrderType GetType() const
Get the type of order of this order.
Definition: order_base.h:76
Order * next
Pointer to next order. If nullptr, end of list.
Definition: order_base.h:59
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition: order_base.h:146
SpriteID sprite
The 'real' sprite.
Definition: gfx_type.h:24
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition: gfx_type.h:25
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:350
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
Rect Expand(int s) const
Copy and expand Rect by s pixels.
Option to refit a vehicle chain.
StringID string
GRF-local String to display for the cargo.
uint8_t subtype
Subcargo to use.
CargoID cargo
Cargo to refit to.
bool operator!=(const RefitOption &other) const
Inequality operator for RefitOption.
bool operator==(const RefitOption &other) const
Equality operator for RefitOption.
Refit cargo window.
void OnInit() override
Notification that the nested widget tree gets initialized.
uint information_width
Width required for correctly displaying all cargoes in the information panel.
void SetSelection(uint click_row)
Select a row.
void BuildRefitList()
Collects all (cargo, subcargo) refit options of a vehicle chain.
int sprite_left
Left position of the vehicle sprite.
void RefreshScrollbar()
Refresh scrollbar after selection changed.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
RefitOptions refit_list
List of refit subtypes available for each sorted cargo.
void OnResize() override
Called after the window got resized.
const RefitOption * selected_refit
Selected refit option.
StringID GetCapacityString(const RefitOption &option) const
Gets the StringID to use for displaying capacity.
uint vehicle_margin
Margin to use while selecting vehicles when the vehicle image is centered.
uint8_t num_vehicles
Number of selected vehicles.
bool auto_refit
Select cargo for auto-refitting.
int sprite_right
Right position of the vehicle sprite.
VehicleOrderID order
If not INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly).
VehicleID selected_vehicle
First vehicle in the current selection.
void OnPaint() override
The window must be repainted.
Scrollbar * hscroll
Only used for long vehicles.
int vehicle_width
Width of the vehicle being drawn.
Scrollbar * vscroll
The main scrollbar.
int click_x
Position of the first click while dragging.
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
T * Next() const
Get next vehicle in the chain.
Window * GetCallbackWnd()
Get the window that started the current highlighting.
Definition: viewport.cpp:2588
HighLightStyle place_mode
Method which is used to place the selection.
WindowClass window_class
The WindowClass of the window that is responsible for the selection mode.
WindowNumber window_number
The WindowNumber of the window that is responsible for the selection mode.
'Train' is either a loco or a wagon.
Definition: train.h:89
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a train vehicle image in the GUI.
Definition: train_cmd.cpp:460
uint16_t cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
Definition: vehicle_base.h:126
Default settings for vehicles.
uint16_t servint_aircraft
service interval for aircraft
uint16_t servint_roadveh
service interval for road vehicles
uint16_t servint_ships
service interval for ships
uint16_t servint_trains
service interval for trains
Class for managing the vehicle details window.
uint GetRoadVehDetailsHeight(const Vehicle *v)
Gets the desired height for the road vehicle details panel.
static void DrawVehicleDetails(const Vehicle *v, const Rect &r, int vscroll_pos, uint vscroll_cap, TrainDetailsWindowTabs det_tab)
Draw the details for the given vehicle at the position of the Details windows.
void OnPaint() override
Repaint vehicle details window.
static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type, CompanyID company_id)
Checks whether service interval is enabled for the vehicle.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
void OnResize() override
Called after the window got resized.
VehicleDetailsWindow(WindowDesc &desc, WindowNumber window_number)
Initialize a newly created vehicle details window.
TrainDetailsWindowTabs tab
For train vehicles: which tab is displayed.
The information about a vehicle list.
Definition: vehiclelist.h:28
VehicleListType type
The type of vehicle list.
Definition: vehiclelist.h:29
CompanyID company
The company associated with this list.
Definition: vehiclelist.h:31
uint32_t Pack() const
Pack a VehicleListIdentifier in a single uint32.
Definition: vehiclelist.cpp:23
VehicleType vtype
The vehicle type associated with this list.
Definition: vehiclelist.h:30
static VehicleListIdentifier UnPack(uint32_t data)
Decode a packed vehicle list identifier into a new one.
Definition: vehiclelist.cpp:55
uint32_t index
A vehicle list type specific index.
Definition: vehiclelist.h:32
Window for the (old) vehicle listing.
void OnMouseLoop() override
Called for every mouse loop run, which is at least once per (game) tick.
void OnResize() override
Called after the window got resized.
void OnPaint() override
The window must be repainted.
ButtonPlanes
Enumeration of planes of the button row at the bottom.
@ BP_HIDE_BUTTONS
Show the empty panel.
@ BP_SHOW_BUTTONS
Show the buttons.
CaptionPlanes
Enumeration of planes of the title row at the top.
@ BP_SHARED_ORDERS
Show the normal caption.
@ BP_NORMAL
Show shared orders caption and buttons.
void OnGameTick() override
Called once per (game) tick.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
uint8_t roadveh_acceleration_model
realistic acceleration for road vehicles
uint8_t train_acceleration_model
realistic acceleration for trains
Sprite sequence for a vehicle part.
Definition: vehicle_base.h:135
bool IsValid() const
Check whether the sequence contains any sprites.
Definition: vehicle_base.h:152
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition: vehicle.cpp:103
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
Definition: vehicle_base.h:168
Window manager class for viewing a vehicle.
void OnResize() override
Called after the window got resized.
void ShowNewGRFInspectWindow() const override
Show the NewGRF inspection window.
PlaneSelections
Display planes available in the vehicle view window.
@ SEL_RT_BASEPLANE
First plane of the WID_VV_SELECT_REFIT_TURN stacked widget.
@ SEL_RT_TURN_AROUND
Display 'turn around' button in WID_VV_SELECT_REFIT_TURN stacked widget.
@ SEL_DC_BASEPLANE
First plane of the WID_VV_SELECT_DEPOT_CLONE stacked widget.
@ SEL_RT_REFIT
Display 'refit' button in WID_VV_SELECT_REFIT_TURN stacked widget.
@ SEL_DC_GOTO_DEPOT
Display 'goto depot' button in WID_VV_SELECT_DEPOT_CLONE stacked widget.
@ SEL_DC_CLONE
Display 'clone vehicle' button in WID_VV_SELECT_DEPOT_CLONE stacked widget.
void SelectPlane(PlaneSelections plane)
Display a plane in the window.
void OnPaint() override
The window must be repainted.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
EventState OnHotkey(int hotkey) override
A hotkey has been pressed.
bool IsNewGRFInspectable() const override
Is the data related to this window NewGRF inspectable?
Vehicle data structure.
Definition: vehicle_base.h:244
Money GetDisplayProfitThisYear() const
Gets the profit vehicle had this year.
Definition: vehicle_base.h:617
EngineID engine_type
The type of engine used for this vehicle.
Definition: vehicle_base.h:323
virtual int GetDisplaySpeed() const
Gets the speed in km-ish/h that can be sent into SetDParam for string processing.
Definition: vehicle_base.h:524
Vehicle * Previous() const
Get the previous vehicle of this vehicle.
Definition: vehicle_base.h:639
int32_t z_pos
z coordinate.
Definition: vehicle_base.h:306
Vehicle * GetNextArticulatedPart() const
Get the next part of an articulated engine.
Definition: vehicle_base.h:973
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition: vehicle.cpp:747
bool IsStoppedInDepot() const
Check whether the vehicle is in the depot and stopped.
Definition: vehicle_base.h:560
virtual bool IsChainInDepot() const
Check whether the whole vehicle chain is in the depot.
Definition: vehicle_base.h:554
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Definition: vehicle_base.h:645
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
Definition: vehicle_base.h:295
uint16_t cargo_cap
total capacity
Definition: vehicle_base.h:344
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
Definition: vehicle_base.h:355
virtual void GetImage([[maybe_unused]] Direction direction, [[maybe_unused]] EngineImageType image_type, [[maybe_unused]] VehicleSpriteSeq *result) const
Gets the sprite to show for the given direction.
Definition: vehicle_base.h:486
bool HasArticulatedPart() const
Check if an engine has an articulated part.
Definition: vehicle_base.h:963
uint8_t breakdown_ctr
Counter for managing breakdown events.
Definition: vehicle_base.h:299
GroupID group_id
Index of group Pool array.
Definition: vehicle_base.h:366
virtual int GetDisplayMaxSpeed() const
Gets the maximum speed in km-ish/h that can be sent into SetDParam for string processing.
Definition: vehicle_base.h:530
Order * GetOrder(int index) const
Returns order 'index' of a vehicle or nullptr when it doesn't exists.
Definition: vehicle_base.h:922
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
Definition: vehicle_base.h:954
Vehicle * GetFirstEnginePart()
Get the first part of an articulated engine.
Definition: vehicle_base.h:983
Vehicle * Next() const
Get the next vehicle of this vehicle.
Definition: vehicle_base.h:632
VehicleOrderID GetNumManualOrders() const
Get the number of manually added orders this vehicle has.
Definition: vehicle_base.h:744
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:356
CargoID cargo_type
type of cargo this vehicle is carrying
Definition: vehicle_base.h:342
int32_t y_pos
y coordinate.
Definition: vehicle_base.h:305
int32_t x_pos
x coordinate.
Definition: vehicle_base.h:304
const GRFFile * GetGRF() const
Retrieve the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:757
OrderList * orders
Pointer to the order list for this vehicle.
Definition: vehicle_base.h:359
uint32_t GetDisplayMinPowerToWeight() const
Calculates the minimum power-to-weight ratio using the maximum weight of the ground vehicle.
Definition: vehicle.cpp:3259
Money value
Value of the vehicle.
Definition: vehicle_base.h:275
void InvalidateNewGRFCache()
Invalidates cached NewGRF variables.
Definition: vehicle_base.h:495
uint8_t vehstatus
Status.
Definition: vehicle_base.h:354
VehicleCache vcache
Cache of often used vehicle values.
Definition: vehicle_base.h:364
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:767
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition: vehicle.cpp:3155
virtual void PlayLeaveStationSound([[maybe_unused]] bool force=false) const
Play the sound associated with leaving the station.
Definition: vehicle_base.h:472
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
Definition: vehicle_base.h:477
Money GetDisplayProfitLastYear() const
Gets the profit vehicle had last year.
Definition: vehicle_base.h:623
uint16_t cur_speed
current speed
Definition: vehicle_base.h:328
uint8_t cargo_subtype
Used for livery refits (NewGRF variations)
Definition: vehicle_base.h:343
TimerGameCalendar::Date age
Age in calendar days.
Definition: vehicle_base.h:292
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition: vehicle.cpp:2561
Money GetDisplayRunningCost() const
Gets the running cost of a vehicle that can be sent into SetDParam for string processing.
Definition: vehicle_base.h:611
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
Definition: vehicle_base.h:726
uint8_t breakdowns_since_last_service
Counter for the amount of breakdowns.
Definition: vehicle_base.h:301
TimerGameCalendar::Date max_age
Maximum age.
Definition: vehicle_base.h:294
uint16_t reliability
Reliability.
Definition: vehicle_base.h:297
debug_inline bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
Definition: vehicle_base.h:515
virtual bool IsInDepot() const
Check whether the vehicle is in the depot.
Definition: vehicle_base.h:548
TileIndex tile
Current tile index.
Definition: vehicle_base.h:264
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:309
UnitID unitnumber
unit number, for display purposes only
Definition: vehicle_base.h:326
VehicleID follow_vehicle
VehicleID to follow if following a vehicle, INVALID_VEHICLE otherwise.
Definition: window_gui.h:253
High level window description.
Definition: window_gui.h:159
WindowClass cls
Class of the window,.
Definition: window_gui.h:170
Data structure for an opened window.
Definition: window_gui.h:273
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition: window.cpp:952
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition: window.cpp:1047
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:780
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1733
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition: window.cpp:3151
Window * parent
Parent window.
Definition: window_gui.h:328
virtual bool OnVehicleSelect([[maybe_unused]] const struct Vehicle *v)
The user clicked on a vehicle while HT_VEHICLE has been set.
Definition: window_gui.h:802
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:551
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition: widget.cpp:763
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition: window.cpp:1035
ResizeInfo resize
Resize information.
Definition: window_gui.h:314
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition: window_gui.h:521
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1723
ViewportData * viewport
Pointer to viewport data, if present.
Definition: window_gui.h:318
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition: window_gui.h:532
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition: window_gui.h:316
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition: window_gui.h:447
int left
x position of left edge of the window
Definition: window_gui.h:309
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition: window_gui.h:466
WindowFlags flags
Window flags.
Definition: window_gui.h:300
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:314
virtual EventState OnHotkey(int hotkey)
A hotkey has been pressed.
Definition: window.cpp:565
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:387
int height
Height of the window (number of pixels down in y direction)
Definition: window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:302
Stuff related to the text buffer GUI.
@ QSF_ENABLE_DEFAULT
enable the 'Default' button ("\0" is returned)
Definition: textbuf_gui.h:21
@ QSF_LEN_IN_CHARS
the length of the string is counted in characters
Definition: textbuf_gui.h:22
@ TE_RISING
Make the text effect slowly go upwards.
Definition: texteff.hpp:21
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
Functions related to tile highlights.
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
Definition: viewport.cpp:3435
@ HT_DRAG
dragging items in the depot windows
@ HT_VEHICLE
vehicle is accepted as target as well (bitmask)
Functions related to time tabling.
void ShowTimetableWindow(const Vehicle *v)
Show the timetable for a given vehicle.
Base for the train class.
@ VRF_TRAIN_STUCK
Train can't get a path reservation.
Definition: train.h:32
@ TFP_SIGNAL
Ignore next signal, after the signal ignore being stuck.
Definition: train.h:40
Command definitions related to trains.
void DrawTrainImage(const Train *v, const Rect &r, VehicleID selection, EngineImageType image_type, int skip, VehicleID drag_dest)
Draws an image of a whole train.
Definition: train_gui.cpp:93
PaletteID GetVehiclePalette(const Vehicle *v)
Get the colour map for a vehicle.
Definition: vehicle.cpp:2152
void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles)
Calculates the set of vehicles that will be affected by a given selection.
Definition: vehicle.cpp:3218
@ VF_PATHFINDER_LOST
Vehicle's pathfinder is lost.
Definition: vehicle_base.h:52
@ VS_STOPPED
Vehicle is stopped by the player.
Definition: vehicle_base.h:34
@ VS_CRASHED
Vehicle is crashed.
Definition: vehicle_base.h:40
Command definitions for vehicles.
Functions related to vehicles.
static const TimerGameEconomy::Date VEHICLE_PROFIT_MIN_AGE
Only vehicles older than this have a meaningful profit.
Definition: vehicle_func.h:28
static const Money VEHICLE_PROFIT_THRESHOLD
Threshold for a vehicle to be considered making good profit.
Definition: vehicle_func.h:29
void DrawAircraftDetails(const Aircraft *v, const Rect &r)
Draw the details for the given vehicle at the given position.
int GetSingleVehicleWidth(const Vehicle *v, EngineImageType image_type)
Get the width of a vehicle (part) in pixels.
static bool CargoFilterSingle(const Vehicle *v, const CargoID cid)
Check whether a single vehicle should pass the filter.
void DrawShipDetails(const Vehicle *v, const Rect &r)
Draw the details for the given vehicle at the given position.
Definition: ship_gui.cpp:63
static bool VehicleTimetableDelaySorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by the timetable delay.
VehicleCommandTranslation
Command indices for the _vehicle_command_translation_table.
int GetVehicleWidth(const Vehicle *v, EngineImageType image_type)
Get the width of a vehicle (including all parts of the consist) in pixels.
StringID GetCargoSubtypeText(const Vehicle *v)
Get the cargo subtype text from NewGRF for the vehicle details window.
static void ChangeVehicleWindow(WindowClass window_class, VehicleID from_index, VehicleID to_index)
Assign a vehicle window a new vehicle.
static bool VehicleAgeSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their age.
static bool VehicleGroupLengthSorter(const GUIVehicleGroup &a, const GUIVehicleGroup &b)
Sort vehicle groups by the number of vehicles in the group.
std::map< CargoID, std::vector< RefitOption >, CargoIDComparator > RefitOptions
Available refit options (subtype and string) associated with each cargo type.
static bool VehicleCargoSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their cargo.
void CcBuildPrimaryVehicle(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray)
This is the Callback method after the construction attempt of a primary vehicle.
uint GetUnitNumberDigits(VehicleList &vehicles)
Get the number of digits the biggest unit number of a set of vehicles has.
static bool VehicleGroupTotalProfitThisYearSorter(const GUIVehicleGroup &a, const GUIVehicleGroup &b)
Sort vehicle groups by the total profit this year.
static constexpr NWidgetPart _nested_vehicle_view_widgets[]
Vehicle view widgets.
void ShowVehicleViewWindow(const Vehicle *v)
Shows the vehicle view window of the given vehicle.
static const StringID _vehicle_msg_translation_table[][4]
Command codes for the shared buttons indexed by VehicleCommandTranslation and vehicle type.
uint CountDigitsForAllocatingSpace(uint number)
Get the number of digits of space required for the given number.
static const uint MAX_REFIT_CYCLE
Maximum number of refit cycles we try, to prevent infinite loops.
static bool VehicleProfitThisYearSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by this year profit.
uint ShowRefitOptionsList(int left, int right, int y, EngineID engine)
Display list of cargo types of the engine, for the purchase information window.
void DrawVehicleImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type, int skip)
Draws an image of a vehicle chain.
void DrawTrainDetails(const Train *v, const Rect &r, int vscroll_pos, uint16_t vscroll_cap, TrainDetailsWindowTabs det_tab)
Draw the details for the given vehicle at the given position.
Definition: train_gui.cpp:362
static const ZoomLevel _vehicle_view_zoom_levels[]
Zoom levels for vehicle views indexed by vehicle type.
uint8_t GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type)
Get the best fitting subtype when 'cloning'/'replacing' v_from with v_for.
static bool CargoFilter(const GUIVehicleGroup *vehgroup, const CargoID cid)
Check whether a vehicle can carry a specific cargo.
static constexpr NWidgetPart _nested_nontrain_vehicle_details_widgets[]
Vehicle details widgets (other than train).
static bool IsVehicleRefitable(const Vehicle *v)
Checks whether the vehicle may be refitted at the moment.
static void DrawVehicleProfitButton(TimerGameEconomy::Date age, Money display_profit_last_year, uint num_vehicles, int x, int y)
draw the vehicle profit button in the vehicle list window.
static bool VehicleGroupAverageProfitLastYearSorter(const GUIVehicleGroup &a, const GUIVehicleGroup &b)
Sort vehicle groups by the average profit last year.
static int GetUnitNumberWidth(int digits)
Get width required for the formatted unit number display.
static bool VehicleLengthSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their length.
void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index)
Report a change in vehicle IDs (due to autoreplace) to affected vehicle windows.
static bool VehicleGroupAverageProfitThisYearSorter(const GUIVehicleGroup &a, const GUIVehicleGroup &b)
Sort vehicle groups by the average profit this year.
static bool VehicleNameSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their name.
static WindowDesc _train_view_desc(WDP_AUTO, "view_vehicle_train", 250, 134, WC_VEHICLE_VIEW, WC_NONE, 0, _nested_vehicle_view_widgets, &VehicleViewWindow::hotkeys)
Vehicle view window descriptor for trains.
static void DrawSmallOrderList(const Order *order, int left, int right, int y, uint order_arrow_width)
Draw small order list in the vehicle GUI, but without the little black arrow.
int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab)
Determines the number of lines in the train details window.
Definition: train_gui.cpp:328
static WindowDesc _vehicle_view_desc(WDP_AUTO, "view_vehicle", 250, 116, WC_VEHICLE_VIEW, WC_NONE, 0, _nested_vehicle_view_widgets, &VehicleViewWindow::hotkeys)
Vehicle view window descriptor for all vehicles but trains.
bool VehicleClicked(const Vehicle *v)
Dispatch a "vehicle selected" event if any window waits for it.
uint GetVehicleListHeight(VehicleType type, uint divisor)
Get the height of a vehicle in the vehicle list GUIs.
void StartStopVehicle(const Vehicle *v, bool texteffect)
Executes CMD_START_STOP_VEHICLE for given vehicle.
static constexpr NWidgetPart _nested_train_vehicle_details_widgets[]
Train details widgets.
void SetMouseCursorVehicle(const Vehicle *v, EngineImageType image_type)
Set the mouse cursor to look like a vehicle.
static bool VehicleProfitLastYearSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by last year profit.
void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit)
Show the refit window for a vehicle.
static WindowDesc _nontrain_vehicle_details_desc(WDP_AUTO, "view_vehicle_details", 405, 113, WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, 0, _nested_nontrain_vehicle_details_widgets)
Vehicle details window descriptor for other vehicles than a train.
void DrawCargoIconOverlays(std::span< const CargoIconOverlay > overlays, int y)
Draw a list of cargo icon overlays.
void AddCargoIconOverlay(std::vector< CargoIconOverlay > &overlays, int x, int width, const Vehicle *v)
Add a cargo icon to the list of overlays.
static bool VehicleIndividualToGroupSorterWrapper(GUIVehicleGroup const &a, GUIVehicleGroup const &b)
Wrapper to convert a VehicleIndividualSortFunction to a VehicleGroupSortFunction.
Definition: vehicle_gui.cpp:76
static bool VehicleGroupTotalProfitLastYearSorter(const GUIVehicleGroup &a, const GUIVehicleGroup &b)
Sort vehicle groups by the total profit last year.
static bool VehicleModelSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by model.
static bool VehicleValueSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their value.
static bool VehicleTimeToLiveSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by the time they can still live.
static bool VehicleNumberSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their number.
bool ShowCargoIconOverlay()
Test if cargo icon overlays should be drawn.
static void DrawVehicleRefitWindow(const RefitOptions &refits, const RefitOption *sel, uint pos, uint rows, uint delta, const Rect &r)
Draw the list of available refit options for a consist and highlight the selected refit option (if an...
static bool VehicleMaxSpeedSorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their max speed.
static void ShowVehicleDetailsWindow(const Vehicle *v)
Shows the vehicle details window of the given vehicle.
void DrawCargoIconOverlay(int x, int y, CargoID cid)
Draw a cargo icon overlaying an existing sprite, with a black contrast outline.
void DrawRoadVehDetails(const Vehicle *v, const Rect &r)
Draw the details for the given vehicle at the given position.
Definition: roadveh_gui.cpp:29
void CcStartStopVehicle(Commands, const CommandCost &result, VehicleID veh_id, bool)
This is the Callback method after attempting to start/stop a vehicle.
static WindowDesc _train_vehicle_details_desc(WDP_AUTO, "view_vehicle_details_train", 405, 178, WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, 0, _nested_train_vehicle_details_widgets)
Vehicle details window descriptor.
static bool VehicleReliabilitySorter(const Vehicle *const &a, const Vehicle *const &b)
Sort vehicles by their reliability.
uint GetVehicleHeight(VehicleType type)
Get the height of a single vehicle in the GUIs.
Definition: vehicle_gui.h:74
TrainDetailsWindowTabs
The tabs in the train details window.
Definition: vehicle_gui.h:25
@ TDW_TAB_CAPACITY
Tab with cargo capacity of the vehicles.
Definition: vehicle_gui.h:28
@ TDW_TAB_TOTALS
Tab with sum of total cargo transported.
Definition: vehicle_gui.h:29
@ TDW_TAB_INFO
Tab with name and value of the vehicles.
Definition: vehicle_gui.h:27
@ TDW_TAB_CARGO
Tab with cargo carried by the vehicles.
Definition: vehicle_gui.h:26
@ VIWD_CONSIST_CHANGED
Vehicle composition was changed.
Definition: vehicle_gui.h:37
@ VIWD_AUTOREPLACE
Autoreplace replaced the vehicle.
Definition: vehicle_gui.h:38
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition: vehicle_gui.h:97
Functions/classes shared between the different vehicle list GUIs.
EngineImageType
Visualisation contexts of vehicles and engines.
Definition: vehicle_type.h:78
@ EIT_IN_DETAILS
Vehicle drawn in vehicle details, refit window, ...
Definition: vehicle_type.h:81
@ EIT_IN_LIST
Vehicle drawn in vehicle list, group list, ...
Definition: vehicle_type.h:82
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
@ VEH_ROAD
Road vehicle type.
Definition: vehicle_type.h:25
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition: vehicle_type.h:27
@ VEH_SHIP
Ship vehicle type.
Definition: vehicle_type.h:26
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
@ VEH_COMPANY_END
Last company-ownable type.
Definition: vehicle_type.h:29
uint32_t VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
static const uint MAX_LENGTH_VEHICLE_NAME_CHARS
The maximum length of a vehicle name in characters including '\0'.
Definition: vehicle_type.h:66
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
Definition: vehicle_type.h:54
@ None
No special flags.
@ MassSend
Tells that it's a mass send to depot command (type in VLW flag)
@ Service
The vehicle will leave the depot right after arrival (service only)
@ WID_VR_MATRIX
Options to refit to.
@ WID_VR_SCROLLBAR
Scrollbar for the refit options.
@ WID_VR_SHOW_HSCROLLBAR
Selection widget for the horizontal scrollbar.
@ WID_VR_VEHICLE_PANEL_DISPLAY
Display with a representation of the vehicle to refit.
@ WID_VR_HSCROLLBAR
Horizontal scrollbar or the vehicle display.
@ WID_VR_REFIT
Perform the refit.
@ WID_VR_SELECT_HEADER
Header with question about the cargo to carry.
@ WID_VR_INFO
Information about the currently selected refit option.
@ WID_VR_CAPTION
Caption of window.
@ WID_VL_SORT_BY_PULLDOWN
Sort by dropdown list.
@ WID_VL_START_ALL
Start all button.
@ WID_VL_FILTER_BY_CARGO_SEL
Cargo filter dropdown list panel selector.
@ WID_VL_MANAGE_VEHICLES_DROPDOWN
Manage vehicles dropdown list.
@ WID_VL_HIDE_BUTTONS
Selection to hide the buttons.
@ WID_VL_GROUP_BY_PULLDOWN
Group by dropdown list.
@ WID_VL_AVAILABLE_VEHICLES
Available vehicles.
@ WID_VL_STOP_ALL
Stop all button.
@ WID_VL_CAPTION_SELECTION
Selection for caption.
@ WID_VL_FILTER_BY_CARGO
Cargo filter dropdown list.
@ WID_VL_SORT_ORDER
Sort order.
@ WID_VL_GROUP_ORDER
Group order.
@ WID_VL_SCROLLBAR
Scrollbar for the list.
@ WID_VL_CAPTION
Caption of window (for non shared orders windows).
@ WID_VL_LIST
List of the vehicles.
@ WID_VL_CAPTION_SHARED_ORDERS
Caption of window (for shared orders windows).
@ WID_VL_ORDER_VIEW
Button to open order window (for shared orders windows).
@ WID_VV_GOTO_DEPOT
Order this vehicle to go to the depot.
@ WID_VV_LOCATION
Center the main view on this vehicle.
@ WID_VV_TURN_AROUND
Turn this vehicle around.
@ WID_VV_SELECT_DEPOT_CLONE
Selection widget between 'goto depot', and 'clone vehicle' buttons.
@ WID_VV_FORCE_PROCEED
Force this vehicle to pass a signal at danger.
@ WID_VV_RENAME
Rename vehicle.
@ WID_VV_ORDER_LOCATION
Center the main view on the order's target location.
@ WID_VV_SHOW_ORDERS
Show the orders of this vehicle.
@ WID_VV_CLONE
Clone this vehicle.
@ WID_VV_CAPTION
Caption of window.
@ WID_VV_REFIT
Open the refit window.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
@ WID_VV_SELECT_REFIT_TURN
Selection widget between 'refit' and 'turn around' buttons.
@ WID_VV_SHOW_DETAILS
Show details of this vehicle.
@ WID_VV_VIEWPORT
Viewport widget.
@ WID_VV_HONK_HORN
Honk the vehicles horn (not drawn on UI, only used for hotkey).
@ WID_VD_DECREASE_SERVICING_INTERVAL
Decrease the servicing interval.
@ WID_VD_CAPTION
Caption of window.
@ WID_VD_SERVICE_INTERVAL_DROPDOWN
Dropdown to select default/days/percent service interval.
@ WID_VD_INCREASE_SERVICING_INTERVAL
Increase the servicing interval.
@ WID_VD_MATRIX
List of details for trains.
@ WID_VD_SERVICING_INTERVAL
Information about the servicing interval.
@ WID_VD_DETAILS_TRAIN_VEHICLES
Show all parts of the train with their description.
@ WID_VD_SCROLLBAR
Scrollbar for train details.
@ WID_VD_DETAILS_TOTAL_CARGO
Show the capacity and carried cargo amounts aggregated per cargo of the train.
@ WID_VD_TOP_DETAILS
Panel with generic details.
@ WID_VD_MIDDLE_DETAILS
Details for non-trains.
@ WID_VD_DETAILS_CAPACITY_OF_EACH
Show the capacity of all train parts.
@ WID_VD_DETAILS_CARGO_CARRIED
Show carried cargo per part of the train.
bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli)
Generate a list of vehicles based on window type.
std::vector< const Vehicle * > VehicleList
A list of vehicles.
Definition: vehiclelist.h:54
VehicleListType
Vehicle List type flags.
Definition: vehiclelist.h:18
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2515
Functions related to (drawing on) viewports.
@ ZOOM_IN
Zoom in (get more detailed view).
Definition: viewport_type.h:77
@ ZOOM_OUT
Zoom out (get helicopter view).
Definition: viewport_type.h:78
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:281
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
Definition: widget_type.h:482
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
Definition: widget_type.h:483
@ AWV_DECREASE
Arrow to the left or in case of RTL to the right.
Definition: widget_type.h:31
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition: widget_type.h:32
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:524
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:112
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition: widget_type.h:51
@ WWT_PUSHBTN
Normal push-button (no toggle button) with custom drawing.
Definition: widget_type.h:111
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
Definition: widget_type.h:113
@ WWT_PUSHARROWBTN
Normal push-button (no toggle button) with arrow caption.
Definition: widget_type.h:114
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_TEXTBTN
(Toggle) Button with text
Definition: widget_type.h:55
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
@ WWT_MATRIX
Grid of rows and columns.
Definition: widget_type.h:59
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:84
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:69
@ NWID_HSCROLLBAR
Horizontal scrollbar.
Definition: widget_type.h:83
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:65
@ NWID_VIEWPORT
Nested widget containing a viewport.
Definition: widget_type.h:81
@ WWT_DROPDOWN
Drop down list.
Definition: widget_type.h:70
@ WWT_DEBUGBOX
NewGRF debug box (at top-right of a window, between WWT_CAPTION and WWT_SHADEBOX)
Definition: widget_type.h:63
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:80
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1098
Window * GetMainWindow()
Get the main window, i.e.
Definition: window.cpp:1127
@ SBS_DOWN
Sort ascending.
Definition: window_gui.h:220
@ SBS_UP
Sort descending.
Definition: window_gui.h:221
@ WF_DISABLE_VP_SCROLL
Window does not do autoscroll,.
Definition: window_gui.h:235
@ FR_BORDERONLY
Draw border only, no background.
Definition: window_gui.h:27
@ WDF_CONSTRUCTION
This window is used for construction; close it whenever changing company.
Definition: window_gui.h:203
@ WDP_AUTO
Find a place automatically.
Definition: window_gui.h:147
int WidgetID
Widget ID.
Definition: window_type.h:18
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:737
EventState
State of handling an event.
Definition: window_type.h:743
WindowClass
Window classes.
Definition: window_type.h:44
@ WC_INVALID
Invalid window.
Definition: window_type.h:724
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
Definition: window_type.h:212
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_TRAINS_LIST
Trains list; Window numbers:
Definition: window_type.h:308
@ WC_VEHICLE_REFIT
Vehicle refit; Window numbers:
Definition: window_type.h:206
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
Definition: window_type.h:156
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
Definition: window_type.h:200
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Definition: window_type.h:339
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
Definition: window_type.h:224
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition: zoom_func.h:107
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:117
ZoomLevel ScaleZoomGUI(ZoomLevel value)
Scale zoom level relative to GUI zoom.
Definition: zoom_func.h:87
int UnScaleGUI(int value)
Short-hand to apply GUI zoom level.
Definition: zoom_func.h:77
ZoomLevel
All zoom levels we know.
Definition: zoom_type.h:16
@ ZOOM_LVL_ROADVEH
Default zoom level for the road vehicle view.
Definition: zoom_type.h:35
@ ZOOM_LVL_AIRCRAFT
Default zoom level for the aircraft view.
Definition: zoom_type.h:32
@ ZOOM_LVL_TRAIN
Default zoom level for the train view.
Definition: zoom_type.h:34
@ ZOOM_LVL_SHIP
Default zoom level for the ship view.
Definition: zoom_type.h:33