OpenTTD Source 20260218-master-g2123fca5ea
build_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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "engine_base.h"
12#include "engine_func.h"
13#include "station_base.h"
14#include "network/network.h"
16#include "textbuf_gui.h"
17#include "command_func.h"
18#include "company_func.h"
19#include "vehicle_gui.h"
20#include "newgrf_badge.h"
21#include "newgrf_badge_config.h"
22#include "newgrf_badge_gui.h"
23#include "newgrf_engine.h"
24#include "newgrf_text.h"
25#include "group.h"
26#include "string_func.h"
27#include "strings_func.h"
28#include "window_func.h"
30#include "vehicle_func.h"
31#include "dropdown_type.h"
32#include "dropdown_func.h"
33#include "engine_gui.h"
34#include "cargotype.h"
36#include "autoreplace_func.h"
37#include "engine_cmd.h"
38#include "train_cmd.h"
39#include "vehicle_cmd.h"
40#include "zoom_func.h"
41#include "querystring_gui.h"
42#include "stringfilter_type.h"
43#include "hotkeys.h"
44
46
47#include "table/strings.h"
48
49#include "safeguards.h"
50
57{
58 return std::max<uint>(GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.matrix.Vertical(), GetVehicleImageCellSize(type, EIT_PURCHASE).height);
59}
60
61static constexpr std::initializer_list<NWidgetPart> _nested_build_vehicle_widgets = {
63 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
64 NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetTextStyle(TC_WHITE),
65 NWidget(WWT_SHADEBOX, COLOUR_GREY),
66 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
67 NWidget(WWT_STICKYBOX, COLOUR_GREY),
71 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASCENDING_DESCENDING), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
72 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetToolTip(STR_TOOLTIP_SORT_CRITERIA),
76 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetToolTip(STR_TOOLTIP_FILTER_CRITERIA),
77 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_BV_CONFIGURE_BADGES), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetResize(0, 0), SetFill(0, 1), SetSpriteTip(SPR_EXTRA_MENU, STR_BADGE_CONFIG_MENU_TOOLTIP),
79 NWidget(WWT_PANEL, COLOUR_GREY),
80 NWidget(WWT_EDITBOX, COLOUR_GREY, WID_BV_FILTER), SetResize(1, 0), SetFill(1, 0), SetPadding(2), SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
85 /* Vehicle list. */
90 /* Panel with details. */
91 NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(),
92 /* Build/rename buttons, resize button. */
94 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL),
95 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0),
97 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE), SetResize(1, 0), SetFill(1, 0),
98 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0),
99 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
100 EndContainer(),
101};
102
103
105uint8_t _engine_sort_last_criteria[] = {0, 0, 0, 0};
106bool _engine_sort_last_order[] = {false, false, false, false};
107bool _engine_sort_show_hidden_engines[] = {false, false, false, false};
109
112{
113 int r = Engine::Get(a.engine_id)->list_position - Engine::Get(b.engine_id)->list_position;
114
115 return _engine_sort_direction ? r > 0 : r < 0;
116}
117
120{
121 const auto va = Engine::Get(a.engine_id)->intro_date;
122 const auto vb = Engine::Get(b.engine_id)->intro_date;
123 const auto r = va - vb;
124
125 /* Use EngineID to sort instead since we want consistent sorting */
126 if (r == 0) return EngineNumberSorter(a, b);
127 return _engine_sort_direction ? r > 0 : r < 0;
128}
129
130/* cached values for EngineNameSorter to spare many GetString() calls */
131static EngineID _last_engine[2] = { EngineID::Invalid(), EngineID::Invalid() };
132
135{
136 static std::string last_name[2] = { {}, {} };
137
138 if (a.engine_id != _last_engine[0]) {
139 _last_engine[0] = a.engine_id;
140 last_name[0] = GetString(STR_ENGINE_NAME, PackEngineNameDParam(a.engine_id, EngineNameContext::PurchaseList));
141 }
142
143 if (b.engine_id != _last_engine[1]) {
144 _last_engine[1] = b.engine_id;
145 last_name[1] = GetString(STR_ENGINE_NAME, PackEngineNameDParam(b.engine_id, EngineNameContext::PurchaseList));
146 }
147
148 int r = StrNaturalCompare(last_name[0], last_name[1]); // Sort by name (natural sorting).
149
150 /* Use EngineID to sort instead since we want consistent sorting */
151 if (r == 0) return EngineNumberSorter(a, b);
152 return _engine_sort_direction ? r > 0 : r < 0;
153}
154
157{
158 const int va = Engine::Get(a.engine_id)->reliability;
159 const int vb = Engine::Get(b.engine_id)->reliability;
160 const int r = va - vb;
161
162 /* Use EngineID to sort instead since we want consistent sorting */
163 if (r == 0) return EngineNumberSorter(a, b);
164 return _engine_sort_direction ? r > 0 : r < 0;
165}
166
169{
170 Money va = Engine::Get(a.engine_id)->GetCost();
171 Money vb = Engine::Get(b.engine_id)->GetCost();
172 int r = ClampTo<int32_t>(va - vb);
173
174 /* Use EngineID to sort instead since we want consistent sorting */
175 if (r == 0) return EngineNumberSorter(a, b);
176 return _engine_sort_direction ? r > 0 : r < 0;
177}
178
181{
182 int va = Engine::Get(a.engine_id)->GetDisplayMaxSpeed();
183 int vb = Engine::Get(b.engine_id)->GetDisplayMaxSpeed();
184 int r = va - vb;
185
186 /* Use EngineID to sort instead since we want consistent sorting */
187 if (r == 0) return EngineNumberSorter(a, b);
188 return _engine_sort_direction ? r > 0 : r < 0;
189}
190
193{
194 int va = Engine::Get(a.engine_id)->GetPower();
195 int vb = Engine::Get(b.engine_id)->GetPower();
196 int r = va - vb;
197
198 /* Use EngineID to sort instead since we want consistent sorting */
199 if (r == 0) return EngineNumberSorter(a, b);
200 return _engine_sort_direction ? r > 0 : r < 0;
201}
202
205{
206 int va = Engine::Get(a.engine_id)->GetDisplayMaxTractiveEffort();
207 int vb = Engine::Get(b.engine_id)->GetDisplayMaxTractiveEffort();
208 int r = va - vb;
209
210 /* Use EngineID to sort instead since we want consistent sorting */
211 if (r == 0) return EngineNumberSorter(a, b);
212 return _engine_sort_direction ? r > 0 : r < 0;
213}
214
217{
218 Money va = Engine::Get(a.engine_id)->GetRunningCost();
219 Money vb = Engine::Get(b.engine_id)->GetRunningCost();
220 int r = ClampTo<int32_t>(va - vb);
221
222 /* Use EngineID to sort instead since we want consistent sorting */
223 if (r == 0) return EngineNumberSorter(a, b);
224 return _engine_sort_direction ? r > 0 : r < 0;
225}
226
229{
230 const Engine *e_a = Engine::Get(a.engine_id);
231 const Engine *e_b = Engine::Get(b.engine_id);
232 uint p_a = e_a->GetPower();
233 uint p_b = e_b->GetPower();
234 Money r_a = e_a->GetRunningCost();
235 Money r_b = e_b->GetRunningCost();
236 /* Check if running cost is zero in one or both engines.
237 * If only one of them is zero then that one has higher value,
238 * else if both have zero cost then compare powers. */
239 if (r_a == 0) {
240 if (r_b == 0) {
241 /* If it is ambiguous which to return go with their ID */
242 if (p_a == p_b) return EngineNumberSorter(a, b);
243 return _engine_sort_direction != (p_a < p_b);
244 }
246 }
247 if (r_b == 0) return _engine_sort_direction;
248 /* Using double for more precision when comparing close values.
249 * This shouldn't have any major effects in performance nor in keeping
250 * the game in sync between players since it's used in GUI only in client side */
251 double v_a = (double)p_a / (double)r_a;
252 double v_b = (double)p_b / (double)r_b;
253 /* Use EngineID to sort if both have same power/running cost,
254 * since we want consistent sorting.
255 * Also if both have no power then sort with reverse of running cost to simulate
256 * previous sorting behaviour for wagons. */
257 if (v_a == 0 && v_b == 0) return EngineRunningCostSorter(b, a);
258 if (v_a == v_b) return EngineNumberSorter(a, b);
259 return _engine_sort_direction != (v_a < v_b);
260}
261
262/* Train sorting functions */
263
266{
267 const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
268 const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
269
270 int va = GetTotalCapacityOfArticulatedParts(a.engine_id) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
271 int vb = GetTotalCapacityOfArticulatedParts(b.engine_id) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
272 int r = va - vb;
273
274 /* Use EngineID to sort instead since we want consistent sorting */
275 if (r == 0) return EngineNumberSorter(a, b);
276 return _engine_sort_direction ? r > 0 : r < 0;
277}
278
281{
282 int val_a = (RailVehInfo(a.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
283 int val_b = (RailVehInfo(b.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
284 int r = val_a - val_b;
285
286 /* Use EngineID to sort instead since we want consistent sorting */
287 if (r == 0) return EngineNumberSorter(a, b);
288 return _engine_sort_direction ? r > 0 : r < 0;
289}
290
291/* Road vehicle sorting functions */
292
295{
298 int r = va - vb;
299
300 /* Use EngineID to sort instead since we want consistent sorting */
301 if (r == 0) return EngineNumberSorter(a, b);
302 return _engine_sort_direction ? r > 0 : r < 0;
303}
304
305/* Ship vehicle sorting functions */
306
309{
310 const Engine *e_a = Engine::Get(a.engine_id);
311 const Engine *e_b = Engine::Get(b.engine_id);
312
313 int va = e_a->GetDisplayDefaultCapacity();
314 int vb = e_b->GetDisplayDefaultCapacity();
315 int r = va - vb;
316
317 /* Use EngineID to sort instead since we want consistent sorting */
318 if (r == 0) return EngineNumberSorter(a, b);
319 return _engine_sort_direction ? r > 0 : r < 0;
320}
321
322/* Aircraft sorting functions */
323
326{
327 const Engine *e_a = Engine::Get(a.engine_id);
328 const Engine *e_b = Engine::Get(b.engine_id);
329
330 uint16_t mail_a, mail_b;
331 int va = e_a->GetDisplayDefaultCapacity(&mail_a);
332 int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
333 int r = va - vb;
334
335 if (r == 0) {
336 /* The planes have the same passenger capacity. Check mail capacity instead */
337 r = mail_a - mail_b;
338
339 if (r == 0) {
340 /* Use EngineID to sort instead since we want consistent sorting */
341 return EngineNumberSorter(a, b);
342 }
343 }
344 return _engine_sort_direction ? r > 0 : r < 0;
345}
346
349{
350 uint16_t r_a = Engine::Get(a.engine_id)->GetRange();
351 uint16_t r_b = Engine::Get(b.engine_id)->GetRange();
352
353 int r = r_a - r_b;
354
355 /* Use EngineID to sort instead since we want consistent sorting */
356 if (r == 0) return EngineNumberSorter(a, b);
357 return _engine_sort_direction ? r > 0 : r < 0;
358}
359
409
411const std::initializer_list<const StringID> _engine_sort_listing[] = {{
412 /* Trains */
413 STR_SORT_BY_ENGINE_ID,
414 STR_SORT_BY_COST,
415 STR_SORT_BY_MAX_SPEED,
416 STR_SORT_BY_POWER,
417 STR_SORT_BY_TRACTIVE_EFFORT,
418 STR_SORT_BY_INTRO_DATE,
419 STR_SORT_BY_NAME,
420 STR_SORT_BY_RUNNING_COST,
421 STR_SORT_BY_POWER_VS_RUNNING_COST,
422 STR_SORT_BY_RELIABILITY,
423 STR_SORT_BY_CARGO_CAPACITY,
424}, {
425 /* Road vehicles */
426 STR_SORT_BY_ENGINE_ID,
427 STR_SORT_BY_COST,
428 STR_SORT_BY_MAX_SPEED,
429 STR_SORT_BY_POWER,
430 STR_SORT_BY_TRACTIVE_EFFORT,
431 STR_SORT_BY_INTRO_DATE,
432 STR_SORT_BY_NAME,
433 STR_SORT_BY_RUNNING_COST,
434 STR_SORT_BY_POWER_VS_RUNNING_COST,
435 STR_SORT_BY_RELIABILITY,
436 STR_SORT_BY_CARGO_CAPACITY,
437}, {
438 /* Ships */
439 STR_SORT_BY_ENGINE_ID,
440 STR_SORT_BY_COST,
441 STR_SORT_BY_MAX_SPEED,
442 STR_SORT_BY_INTRO_DATE,
443 STR_SORT_BY_NAME,
444 STR_SORT_BY_RUNNING_COST,
445 STR_SORT_BY_RELIABILITY,
446 STR_SORT_BY_CARGO_CAPACITY,
447}, {
448 /* Aircraft */
449 STR_SORT_BY_ENGINE_ID,
450 STR_SORT_BY_COST,
451 STR_SORT_BY_MAX_SPEED,
452 STR_SORT_BY_INTRO_DATE,
453 STR_SORT_BY_NAME,
454 STR_SORT_BY_RUNNING_COST,
455 STR_SORT_BY_RELIABILITY,
456 STR_SORT_BY_CARGO_CAPACITY,
457 STR_SORT_BY_RANGE,
458}};
459
466static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoType cargo_type)
467{
468 if (cargo_type == CargoFilterCriteria::CF_ANY) {
469 return true;
470 } else if (cargo_type == CargoFilterCriteria::CF_ENGINES) {
471 return Engine::Get(item->engine_id)->GetPower() != 0;
472 } else {
473 CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(item->engine_id, true) & _standard_cargo_mask;
474 return (cargo_type == CargoFilterCriteria::CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cargo_type));
475 }
476}
477
478static GUIEngineList::FilterFunction * const _engine_filter_funcs[] = {
480};
481
482static uint GetCargoWeight(const CargoArray &cap, VehicleType vtype)
483{
484 uint weight = 0;
485 for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) {
486 if (cap[cargo] != 0) {
487 if (vtype == VEH_TRAIN) {
488 weight += CargoSpec::Get(cargo)->WeightOfNUnitsInTrain(cap[cargo]);
489 } else {
490 weight += CargoSpec::Get(cargo)->WeightOfNUnits(cap[cargo]);
491 }
492 }
493 }
494 return weight;
495}
496
497static int DrawCargoCapacityInfo(int left, int right, int y, TestedEngineDetails &te, bool refittable)
498{
499 for (const CargoSpec *cs : _sorted_cargo_specs) {
500 CargoType cargo_type = cs->Index();
501 if (te.all_capacities[cargo_type] == 0) continue;
502
503 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, cargo_type, te.all_capacities[cargo_type], refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
505 }
506
507 return y;
508}
509
510/* Draw rail wagon specific details */
511static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
512{
513 const Engine *e = Engine::Get(engine_number);
514
515 /* Purchase cost */
516 if (te.cost != 0) {
517 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
518 } else {
519 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
520 }
522
523 /* Wagon weight - (including cargo) */
524 uint weight = e->GetDisplayWeight();
525 DrawString(left, right, y,
526 GetString(STR_PURCHASE_INFO_WEIGHT_CWEIGHT, weight, GetCargoWeight(te.all_capacities, VEH_TRAIN) + weight));
528
529 /* Wagon speed limit, displayed if above zero */
530 if (_settings_game.vehicle.wagon_speed_limits) {
531 uint max_speed = e->GetDisplayMaxSpeed();
532 if (max_speed > 0) {
533 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED, PackVelocity(max_speed, e->type)));
535 }
536 }
537
538 /* Running cost */
539 if (rvi->running_cost_class != Price::Invalid) {
540 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
542 }
543
544 return y;
545}
546
547/* Draw locomotive specific details */
548static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
549{
550 const Engine *e = Engine::Get(engine_number);
551
552 /* Purchase Cost - Engine weight */
553 if (te.cost != 0) {
554 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_WEIGHT, e->GetCost() + te.cost, te.cost, e->GetDisplayWeight()));
555 } else {
556 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_WEIGHT, e->GetCost(), e->GetDisplayWeight()));
557 }
559
560 /* Supported rail types */
561 std::string railtypes{};
562 std::string_view list_separator = GetListSeparator();
563
564 for (const auto &rt : _sorted_railtypes) {
565 if (!rvi->railtypes.Test(rt)) continue;
566
567 if (!railtypes.empty()) railtypes += list_separator;
568 AppendStringInPlace(railtypes, GetRailTypeInfo(rt)->strings.name);
569 }
570 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_RAILTYPES, railtypes));
572
573 /* Max speed - Engine power */
574 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
576
577 /* Max tractive effort - not applicable if old acceleration or maglev */
578 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
579 bool is_maglev = true;
580 for (RailType rt : rvi->railtypes) {
582 }
583 if (!is_maglev) {
584 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
586 }
587 }
588
589 /* Running cost */
590 if (rvi->running_cost_class != Price::Invalid) {
591 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
593 }
594
595 /* Powered wagons power - Powered wagons extra weight */
596 if (rvi->pow_wag_power != 0) {
597 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, rvi->pow_wag_power, rvi->pow_wag_weight));
599 }
600
601 return y;
602}
603
604/* Draw road vehicle specific details */
605static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
606{
607 const Engine *e = Engine::Get(engine_number);
608
609 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) {
610 /* Purchase Cost */
611 if (te.cost != 0) {
612 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
613 } else {
614 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
615 }
617
618 /* Road vehicle weight - (including cargo) */
619 int16_t weight = e->GetDisplayWeight();
620 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_WEIGHT_CWEIGHT, weight, GetCargoWeight(te.all_capacities, VEH_ROAD) + weight));
622
623 /* Max speed - Engine power */
624 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
626
627 /* Max tractive effort */
628 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
630 } else {
631 /* Purchase cost - Max speed */
632 if (te.cost != 0) {
633 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
634 } else {
635 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
636 }
638 }
639
640 /* Running cost */
641 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
643
644 return y;
645}
646
647/* Draw ship specific details */
648static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
649{
650 const Engine *e = Engine::Get(engine_number);
651
652 /* Purchase cost - Max speed */
653 uint raw_speed = e->GetDisplayMaxSpeed();
654 uint ocean_speed = e->VehInfo<ShipVehicleInfo>().ApplyWaterClassSpeedFrac(raw_speed, true);
655 uint canal_speed = e->VehInfo<ShipVehicleInfo>().ApplyWaterClassSpeedFrac(raw_speed, false);
656
657 if (ocean_speed == canal_speed) {
658 if (te.cost != 0) {
659 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(ocean_speed, e->type)));
660 } else {
661 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(ocean_speed, e->type)));
662 }
664 } else {
665 if (te.cost != 0) {
666 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
667 } else {
668 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
669 }
671
672 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_OCEAN, PackVelocity(ocean_speed, e->type)));
674
675 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_CANAL, PackVelocity(canal_speed, e->type)));
677 }
678
679 /* Cargo type + capacity */
680 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, te.cargo, te.capacity, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
682
683 /* Running cost */
684 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
686
687 return y;
688}
689
700static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
701{
702 const Engine *e = Engine::Get(engine_number);
703
704 /* Purchase cost - Max speed */
705 if (te.cost != 0) {
706 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
707 } else {
708 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
709 }
711
712 /* Cargo capacity */
713 if (te.mail_capacity > 0) {
714 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, te.cargo, te.capacity, GetCargoTypeByLabel(CT_MAIL), te.mail_capacity));
715 } else {
716 /* Note, if the default capacity is selected by the refit capacity
717 * callback, then the capacity shown is likely to be incorrect. */
718 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, te.cargo, te.capacity, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
719 }
721
722 /* Running cost */
723 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
725
726 /* Aircraft type */
727 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_TYPE, e->GetAircraftTypeText()));
729
730 /* Aircraft range, if available. */
731 uint16_t range = e->GetRange();
732 if (range != 0) {
733 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_RANGE, range));
735 }
736
737 return y;
738}
739
740
746static std::optional<std::string> GetNewGRFAdditionalText(EngineID engine)
747{
748 std::array<int32_t, 16> regs100;
749 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr, regs100);
750 if (callback == CALLBACK_FAILED || callback == 0x400) return std::nullopt;
751 const GRFFile *grffile = Engine::Get(engine)->GetGRF();
752 assert(grffile != nullptr);
753 if (callback == 0x40F) {
754 return GetGRFStringWithTextStack(grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
755 }
756 if (callback > 0x400) {
758 return std::nullopt;
759 }
760
761 return GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, regs100);
762}
763
772static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
773{
774 auto text = GetNewGRFAdditionalText(engine);
775 if (!text) return y;
776 return DrawStringMultiLine(left, right, y, INT32_MAX, *text, TC_BLACK);
777}
778
779void TestedEngineDetails::FillDefaultCapacities(const Engine *e)
780{
781 this->cargo = e->GetDefaultCargoType();
782 if (e->type == VEH_TRAIN || e->type == VEH_ROAD) {
784 this->capacity = this->all_capacities[this->cargo];
785 this->mail_capacity = 0;
786 } else {
788 this->all_capacities[this->cargo] = this->capacity;
789 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
790 this->all_capacities[GetCargoTypeByLabel(CT_MAIL)] = this->mail_capacity;
791 } else {
792 this->mail_capacity = 0;
793 }
794 }
795 if (this->all_capacities.GetCount() == 0) this->cargo = INVALID_CARGO;
796}
797
805int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
806{
807 const Engine *e = Engine::Get(engine_number);
808 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
809 bool refittable = IsArticulatedVehicleRefittable(engine_number);
810 bool articulated_cargo = false;
811
812 switch (e->type) {
813 default: NOT_REACHED();
814 case VEH_TRAIN:
815 if (e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) {
816 y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->VehInfo<RailVehicleInfo>(), te);
817 } else {
818 y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->VehInfo<RailVehicleInfo>(), te);
819 }
820 articulated_cargo = true;
821 break;
822
823 case VEH_ROAD:
824 y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te);
825 articulated_cargo = true;
826 break;
827
828 case VEH_SHIP:
829 y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te);
830 break;
831
832 case VEH_AIRCRAFT:
833 y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
834 break;
835 }
836
837 if (articulated_cargo) {
838 /* Cargo type + capacity, or N/A */
839 int new_y = DrawCargoCapacityInfo(left, right, y, te, refittable);
840
841 if (new_y == y) {
842 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, INVALID_CARGO, 0, STR_EMPTY));
844 } else {
845 y = new_y;
846 }
847 }
848
849 /* Draw details that apply to all types except rail wagons. */
850 if (e->type != VEH_TRAIN || e->VehInfo<RailVehicleInfo>().railveh_type != RAILVEH_WAGON) {
851 /* Design date - Life length */
852 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_DESIGNED_LIFE, ymd.year, TimerGameCalendar::DateToYear(e->GetLifeLengthInDays())));
854
855 /* Reliability */
856 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_RELIABILITY, ToPercent16(e->reliability)));
858 }
859
860 if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
861
862 y = DrawBadgeNameList({left, y, right, INT16_MAX}, e->badges, static_cast<GrfSpecFeature>(GSF_TRAINS + e->type));
863
864 /* Additional text from NewGRF */
865 y = ShowAdditionalText(left, right, y, engine_number);
866
867 /* The NewGRF's name which the vehicle comes from */
868 const GRFConfig *config = GetGRFConfig(e->GetGRFID());
869 if (_settings_client.gui.show_newgrf_name && config != nullptr)
870 {
871 DrawString(left, right, y, config->GetName(), TC_BLACK);
873 }
874
875 return y;
876}
877
878static void DrawEngineBadgeColumn(const Rect &r, int column_group, const GUIBadgeClasses &badge_classes, const Engine *e, PaletteID remap)
879{
880 DrawBadgeColumn(r, column_group, badge_classes, e->badges, static_cast<GrfSpecFeature>(GSF_TRAINS + e->type), e->info.base_intro, remap);
881}
882
895void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group, const GUIBadgeClasses &badge_classes, uint8_t sort_criteria)
896{
897 static const std::array<int8_t, VehicleType::VEH_COMPANY_END> sprite_y_offsets = { 0, 0, -1, -1 };
898
899 auto [first, last] = sb.GetVisibleRangeIterators(eng_list);
900
901 bool rtl = _current_text_dir == TD_RTL;
902 int step_size = GetEngineListHeight(type);
903 int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
904 int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
905 int sprite_width = sprite_left + sprite_right;
906 int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
907 PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
908
909 auto badge_column_widths = badge_classes.GetColumnWidths();
910
911 Rect ir = r.WithHeight(step_size).Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
912 int sprite_y_offset = ScaleSpriteTrad(sprite_y_offsets[type]) + ir.Height() / 2;
913
914 Dimension replace_icon = {0, 0};
915 int count_width = 0;
916 if (show_count) {
917 replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
918
919 uint biggest_num_engines = 0;
920 for (auto it = first; it != last; ++it) {
921 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, it->engine_id);
922 biggest_num_engines = std::max(biggest_num_engines, num_engines);
923 }
924
925 count_width = GetStringBoundingBox(GetString(STR_JUST_COMMA, biggest_num_engines), FS_SMALL).width;
926 }
927
928 const int text_row_height = ir.Shrink(WidgetDimensions::scaled.matrix).Height();
929 const int normal_text_y_offset = (text_row_height - GetCharacterHeight(FS_NORMAL)) / 2;
930 const int small_text_y_offset = text_row_height - GetCharacterHeight(FS_SMALL);
931
932 const int offset = (rtl ? -circle_width : circle_width) / 2;
933 const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
934
935 for (auto it = first; it != last; ++it) {
936 const auto &item = *it;
937 const Engine *e = Engine::Get(item.engine_id);
938
939 uint indent = item.indent * WidgetDimensions::scaled.hsep_indent;
940 bool has_variants = item.flags.Test(EngineDisplayFlag::HasVariants);
941 bool is_folded = item.flags.Test(EngineDisplayFlag::IsFolded);
942 bool shaded = item.flags.Test(EngineDisplayFlag::Shaded);
943
944 Rect textr = ir.Shrink(WidgetDimensions::scaled.matrix);
945 Rect tr = ir.Indent(indent, rtl);
946
947 if (item.indent > 0) {
948 /* Draw tree continuation lines. */
949 int tx = (rtl ? ir.right : ir.left) + offset;
950 for (uint lvl = 1; lvl <= item.indent; ++lvl) {
951 if (HasBit(item.level_mask, lvl)) GfxDrawLine(tx, ir.top, tx, ir.bottom, linecolour, WidgetDimensions::scaled.fullbevel.top);
952 if (lvl < item.indent) tx += level_width;
953 }
954 /* Draw our node in the tree. */
955 int ycentre = CentreBounds(textr.top, textr.bottom, WidgetDimensions::scaled.fullbevel.top);
956 if (!HasBit(item.level_mask, item.indent)) GfxDrawLine(tx, ir.top, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
957 GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
958 }
959
960 if (has_variants) {
961 Rect fr = tr.WithWidth(circle_width, rtl);
962 DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, fr.WithY(textr), SA_CENTER);
963 }
964
965 tr = tr.Indent(circle_width + WidgetDimensions::scaled.hsep_normal, rtl);
966
967 /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
968 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
969 const PaletteID pal = (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(item.engine_id, _local_company);
970
971 if (badge_column_widths.size() >= 1 && badge_column_widths[0] > 0) {
972 Rect br = tr.WithWidth(badge_column_widths[0], rtl);
973 DrawEngineBadgeColumn(br, 0, badge_classes, e, pal);
974 tr = tr.Indent(badge_column_widths[0], rtl);
975 }
976
977 int sprite_x = tr.WithWidth(sprite_width, rtl).left + sprite_left;
978 DrawVehicleEngine(r.left, r.right, sprite_x, tr.top + sprite_y_offset, item.engine_id, pal, EIT_PURCHASE);
979
980 tr = tr.Indent(sprite_width + WidgetDimensions::scaled.hsep_wide, rtl);
981
982 if (badge_column_widths.size() >= 2 && badge_column_widths[1] > 0) {
983 Rect br = tr.WithWidth(badge_column_widths[1], rtl);
984 DrawEngineBadgeColumn(br, 1, badge_classes, e, pal);
985 tr = tr.Indent(badge_column_widths[1], rtl);
986 }
987
988 if (show_count) {
989 /* Rect for replace-protection icon. */
990 Rect rr = tr.WithWidth(replace_icon.width, !rtl);
991 tr = tr.Indent(replace_icon.width + WidgetDimensions::scaled.hsep_normal, !rtl);
992 /* Rect for engine type count text. */
993 Rect cr = tr.WithWidth(count_width, !rtl);
994 tr = tr.Indent(count_width + WidgetDimensions::scaled.hsep_normal, !rtl);
995
996 DrawString(cr.left, cr.right, textr.top + small_text_y_offset, GetString(STR_JUST_COMMA, num_engines), TC_BLACK, SA_RIGHT | SA_FORCE, false, FS_SMALL);
997
998 if (EngineHasReplacementForCompany(Company::Get(_local_company), item.engine_id, selected_group)) {
999 DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr, SA_CENTER);
1000 }
1001 }
1002
1003 if (badge_column_widths.size() >= 3 && badge_column_widths[2] > 0) {
1004 Rect br = tr.WithWidth(badge_column_widths[2], !rtl).Indent(WidgetDimensions::scaled.hsep_wide, rtl);
1005 DrawEngineBadgeColumn(br, 2, badge_classes, e, pal);
1006 tr = tr.Indent(badge_column_widths[2], !rtl);
1007 }
1008
1009 bool hidden = e->company_hidden.Test(_local_company);
1010 StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
1011 TextColour tc = (item.engine_id == selected_id) ? TC_WHITE : ((hidden | shaded) ? (TC_GREY | TC_FORCED | TC_NO_SHADE) : TC_BLACK);
1012
1013 /* Draw the value of the currently selected sort property to the right (or left in RTL), if applicable */
1014 std::string sort_prop_detail;
1015
1016 switch (std::data(_engine_sort_listing[type])[sort_criteria]) {
1017 case STR_SORT_BY_ENGINE_ID:
1018 /* No extra interesting info to show in this case */
1019 break;
1020 case STR_SORT_BY_COST:
1021 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_COST, e->GetCost());
1022 break;
1023 case STR_SORT_BY_MAX_SPEED:
1024 if (int max_speed = e->GetDisplayMaxSpeed(); max_speed != 0) {
1025 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_SPEED, PackVelocity(max_speed, Engine::Get(item.engine_id)->type));
1026 }
1027 break;
1028 case STR_SORT_BY_POWER:
1029 if (int power = e->GetPower(); power != 0) {
1030 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_POWER, power);
1031 }
1032 break;
1033 case STR_SORT_BY_TRACTIVE_EFFORT:
1034 /* Allow trucks, and allow trains that are not wagons */
1035 if (type == VEH_ROAD || (type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type != RAILVEH_WAGON)) {
1036 auto max_te = e->GetDisplayMaxTractiveEffort();
1037 if (max_te != 0) {
1038 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_MAX_TE, max_te);
1039 }
1040 }
1041 break;
1042 case STR_SORT_BY_INTRO_DATE: {
1043 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
1044 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_INTRO_DATE, ymd.year);
1045 }
1046 break;
1047 case STR_SORT_BY_NAME:
1048 /* No extra interesting info to show in this case */
1049 break;
1050 case STR_SORT_BY_RUNNING_COST:
1051 if (int running_cost = e->GetRunningCost(); running_cost != 0) {
1052 sort_prop_detail = GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_SORT_DETAILS_RUNNINGCOST_PERIOD : STR_PURCHASE_SORT_DETAILS_RUNNINGCOST_YEAR, running_cost);
1053 }
1054 break;
1055 case STR_SORT_BY_POWER_VS_RUNNING_COST:
1056 /* NOTE: No point showing the actual values of power/running cost, because they are affected by cost factors, which make the math off */
1057 if (Money rc = e->GetRunningCost(); rc != 0) {
1058 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_POWER_VS_RUNNING_COST, 100 * e->GetPower() / rc, /* digits for DECIMAL */ 2);
1059 }
1060 break;
1061 case STR_SORT_BY_RELIABILITY:
1062 if (auto isWagon = e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON; !isWagon) {
1063 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_RELIABILITY, ToPercent16(e->reliability));
1064 }
1065 break;
1066 case STR_SORT_BY_CARGO_CAPACITY: {
1067 uint total_capacity;
1068 switch (type) {
1069 case VEH_TRAIN:
1070 total_capacity = GetTotalCapacityOfArticulatedParts(item.engine_id) * (e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
1071 break;
1072 case VEH_ROAD:
1073 total_capacity = GetTotalCapacityOfArticulatedParts(item.engine_id);
1074 break;
1075 case VEH_SHIP:
1076 total_capacity = e->GetDisplayDefaultCapacity();
1077 break;
1078 case VEH_AIRCRAFT: {
1079 uint16_t mail_cap;
1080 int aircraft_cap = e->GetDisplayDefaultCapacity(&mail_cap);
1081 total_capacity = aircraft_cap + mail_cap;
1082 }
1083 break;
1084 default:
1085 NOT_REACHED();
1086 break;
1087 }
1088 if (total_capacity != 0) {
1089 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_CAPACITY, total_capacity);
1090 }
1091 }
1092 break;
1093 case STR_SORT_BY_RANGE:
1094 if (e->type == VEH_AIRCRAFT) {
1095 if (uint16_t range = e->GetRange(); range != 0) {
1096 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_AIRCRAFT_RANGE, range);
1097 }
1098 }
1099 break;
1100 default:
1101 break;
1102 }
1103
1104 int sort_detail_width = 0;
1105 if (!sort_prop_detail.empty()) {
1106 DrawString(tr.left, tr.right, textr.top + normal_text_y_offset, sort_prop_detail, tc, SA_RIGHT, false, FS_SMALL);
1107
1108 /* If we have sort detail to show, also measure its width so that we can adjust the
1109 * main name drawing rectangle to not overlap. */
1110 sort_detail_width = GetStringBoundingBox(sort_prop_detail, FS_SMALL).width;
1111 }
1112
1113 /* If the count is visible then this is part of in-use autoreplace list. */
1114 auto engine_name = PackEngineNameDParam(item.engine_id, show_count ? EngineNameContext::AutoreplaceVehicleInUse : EngineNameContext::PurchaseList, item.indent);
1115 std::string name = GetString(str, engine_name);
1116
1117 /* The left/right bounds are adjusted to not overlap with the sort detail that is on the left/right depending on the RTL setting. */
1118 DrawString(tr.left + (rtl ? sort_detail_width : 0), tr.right - (rtl ? 0 : sort_detail_width), textr.top + normal_text_y_offset, name, tc);
1119
1120 ir = ir.Translate(0, step_size);
1121 }
1122}
1123
1131void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button)
1132{
1133 uint32_t hidden_mask = 0;
1134 /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
1135 if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
1136 SetBit(hidden_mask, 3); // power
1137 SetBit(hidden_mask, 4); // tractive effort
1138 SetBit(hidden_mask, 8); // power by running costs
1139 }
1140 /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
1141 if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
1142 SetBit(hidden_mask, 4); // tractive effort
1143 }
1144 ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
1145}
1146
1154void GUIEngineListAddChildren(GUIEngineList &dst, const GUIEngineList &src, EngineID parent, uint8_t indent)
1155{
1156 for (const auto &item : src) {
1157 if (item.variant_id != parent || item.engine_id == parent) continue;
1158
1159 const Engine *e = Engine::Get(item.engine_id);
1160 EngineDisplayFlags flags = item.flags;
1161 if (e->display_last_variant != EngineID::Invalid()) flags.Reset(EngineDisplayFlag::Shaded);
1162 dst.emplace_back(e->display_last_variant == EngineID::Invalid() ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent);
1163
1164 /* Add variants if not folded */
1165 if (item.flags.Test(EngineDisplayFlag::HasVariants) && !item.flags.Test(EngineDisplayFlag::IsFolded)) {
1166 /* Add this engine again as a child */
1167 if (!item.flags.Test(EngineDisplayFlag::Shaded)) {
1168 dst.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags{}, indent + 1);
1169 }
1170 GUIEngineListAddChildren(dst, src, item.engine_id, indent + 1);
1171 }
1172 }
1173
1174 if (indent > 0 || dst.empty()) return;
1175
1176 /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
1177 uint16_t level_mask = 0;
1178 for (auto it = std::rbegin(dst); std::next(it) != std::rend(dst); ++it) {
1179 auto next_it = std::next(it);
1180 SB(level_mask, it->indent, 1, it->indent <= next_it->indent);
1181 next_it->level_mask = level_mask;
1182 }
1183}
1184
1186struct BuildVehicleWindow : Window {
1188 union {
1193 uint8_t sort_criteria = 0;
1194 bool show_hidden_engines = false;
1195 bool listview_mode = false;
1196 EngineID sel_engine = EngineID::Invalid();
1197 EngineID rename_engine = EngineID::Invalid();
1198 GUIEngineList eng_list{};
1201 Scrollbar *vscroll = nullptr;
1203 GUIBadgeClasses badge_classes{};
1204
1205 static constexpr int BADGE_COLUMNS = 3;
1206
1209
1210 std::pair<WidgetID, WidgetID> badge_filters{};
1211 BadgeFilterChoices badge_filter_choices{};
1212
1213 void SetBuyVehicleText()
1214 {
1215 NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
1216
1218 if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter_criteria;
1219
1220 if (refit) {
1221 widget->SetStringTip(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type, STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this->vehicle_type);
1222 } else {
1223 widget->SetStringTip(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type, STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this->vehicle_type);
1224 }
1225 }
1226
1228 {
1229 this->vehicle_type = type;
1230 this->listview_mode = tile == INVALID_TILE;
1231 this->window_number = this->listview_mode ? (int)type : tile.base();
1232
1236
1237 this->UpdateFilterByTile();
1238
1239 this->CreateNestedTree();
1240
1241 this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR);
1242
1243 /* If we are just viewing the list of vehicles, we do not need the Build button.
1244 * So we just hide it, and enlarge the Rename button by the now vacant place. */
1245 if (this->listview_mode) this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
1246
1247 NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_LIST);
1248 widget->SetToolTip(STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type);
1249
1251 widget->SetToolTip(STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type);
1252
1253 widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
1254 widget->SetStringTip(STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type, STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type);
1255
1257 widget->SetStringTip(STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + type, STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type);
1258 widget->SetLowered(this->show_hidden_engines);
1259
1260 this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9);
1261
1262 if (tile == INVALID_TILE) {
1263 this->FinishInitNested(type);
1264 } else {
1265 this->FinishInitNested(tile);
1266 }
1267
1269 this->vehicle_editbox.cancel_button = QueryString::ACTION_CLEAR;
1270
1271 this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
1272
1273 this->eng_list.ForceRebuild();
1274 this->GenerateBuildList(); // generate the list, since we need it in the next line
1275
1276 /* Select the first unshaded engine in the list as default when opening the window */
1277 EngineID engine = EngineID::Invalid();
1278 auto it = std::ranges::find_if(this->eng_list, [](const GUIEngineListItem &item) { return !item.flags.Test(EngineDisplayFlag::Shaded); });
1279 if (it != this->eng_list.end()) engine = it->engine_id;
1280 this->SelectEngine(engine);
1281 }
1282
1285 {
1286 switch (this->vehicle_type) {
1287 default: NOT_REACHED();
1288 case VEH_TRAIN:
1289 if (this->listview_mode) {
1290 this->filter.railtype = INVALID_RAILTYPE;
1291 } else {
1292 this->filter.railtype = GetRailType(this->window_number);
1293 }
1294 break;
1295
1296 case VEH_ROAD:
1297 if (this->listview_mode) {
1298 this->filter.roadtype = INVALID_ROADTYPE;
1299 } else {
1300 this->filter.roadtype = GetRoadTypeRoad(this->window_number);
1301 if (this->filter.roadtype == INVALID_ROADTYPE) {
1302 this->filter.roadtype = GetRoadTypeTram(this->window_number);
1303 }
1304 }
1305 break;
1306
1307 case VEH_SHIP:
1308 case VEH_AIRCRAFT:
1309 break;
1310 }
1311 }
1312
1313 StringID GetCargoFilterLabel(CargoType cargo_type) const
1314 {
1315 switch (cargo_type) {
1316 case CargoFilterCriteria::CF_ANY: return STR_PURCHASE_INFO_ALL_TYPES;
1317 case CargoFilterCriteria::CF_ENGINES: return STR_PURCHASE_INFO_ENGINES_ONLY;
1318 case CargoFilterCriteria::CF_NONE: return STR_PURCHASE_INFO_NONE;
1319 default: return CargoSpec::Get(cargo_type)->name;
1320 }
1321 }
1322
1325 {
1326 /* Set the last cargo filter criteria. */
1327 this->cargo_filter_criteria = _engine_sort_last_cargo_criteria[this->vehicle_type];
1328 if (this->cargo_filter_criteria < NUM_CARGO && !HasBit(_standard_cargo_mask, this->cargo_filter_criteria)) this->cargo_filter_criteria = CargoFilterCriteria::CF_ANY;
1329
1330 this->eng_list.SetFilterFuncs(_engine_filter_funcs);
1331 this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
1332 }
1333
1334 void SelectEngine(EngineID engine)
1335 {
1336 CargoType cargo = this->cargo_filter_criteria;
1337 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1338
1339 this->sel_engine = engine;
1340 this->SetBuyVehicleText();
1341
1342 if (this->sel_engine == EngineID::Invalid()) return;
1343
1344 const Engine *e = Engine::Get(this->sel_engine);
1345
1346 if (!this->listview_mode) {
1347 /* Query for cost and refitted capacity */
1348 auto [ret, veh_id, refit_capacity, refit_mail, cargo_capacities] = Command<Commands::BuildVehicle>::Do(DoCommandFlag::QueryCost, TileIndex(this->window_number), this->sel_engine, true, cargo, INVALID_CLIENT_ID);
1349 if (ret.Succeeded()) {
1350 this->te.cost = ret.GetCost() - e->GetCost();
1351 this->te.capacity = refit_capacity;
1352 this->te.mail_capacity = refit_mail;
1353 this->te.cargo = !IsValidCargoType(cargo) ? e->GetDefaultCargoType() : cargo;
1354 this->te.all_capacities = cargo_capacities;
1355 return;
1356 }
1357 }
1358
1359 /* Purchase test was not possible or failed, fill in the defaults instead. */
1360 this->te.cost = 0;
1361 this->te.FillDefaultCapacities(e);
1362 }
1363
1364 void OnInit() override
1365 {
1366 this->badge_classes = GUIBadgeClasses(static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
1367 this->SetCargoFilterArray();
1368
1369 this->badge_filters = AddBadgeDropdownFilters(this, WID_BV_BADGE_FILTER, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
1370
1371 this->widget_lookup.clear();
1372 this->nested_root->FillWidgetLookup(this->widget_lookup);
1373 }
1374
1377 {
1378 this->eng_list.Filter(this->cargo_filter_criteria);
1379 if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
1380 this->SelectEngine(EngineID::Invalid());
1381 } else if (std::ranges::find(this->eng_list, this->sel_engine, &GUIEngineListItem::engine_id) == this->eng_list.end()) { // previously selected engine didn't pass the filter, select the first engine of the list
1382 this->SelectEngine(this->eng_list[0].engine_id);
1383 }
1384 }
1385
1392 {
1393 GUIEngineListItem item = {eid, eid, EngineDisplayFlags{}, 0};
1394 return CargoAndEngineFilter(&item, this->cargo_filter_criteria);
1395 }
1396
1402 bool FilterByText(const Engine *e)
1403 {
1404 /* Do not filter if the filter text box is empty */
1405 if (this->string_filter.IsEmpty()) return true;
1406
1407 /* Filter engine name */
1408 this->string_filter.ResetState();
1409 this->string_filter.AddLine(GetString(STR_ENGINE_NAME, PackEngineNameDParam(e->index, EngineNameContext::PurchaseList)));
1410
1411 /* Filter NewGRF extra text */
1412 auto text = GetNewGRFAdditionalText(e->index);
1413 if (text) this->string_filter.AddLine(*text);
1414
1415 return this->string_filter.GetState();
1416 }
1417
1418 /* Figure out what train EngineIDs to put in the list */
1419 void GenerateBuildTrainList(GUIEngineList &list)
1420 {
1421 FlatSet<EngineID> variants;
1422 EngineID sel_id = EngineID::Invalid();
1423 size_t num_engines = 0;
1424
1425 list.clear();
1426
1427 BadgeTextFilter btf(this->string_filter, GSF_TRAINS);
1428 BadgeDropdownFilter bdf(this->badge_filter_choices);
1429
1430 /* Make list of all available train engines and wagons.
1431 * Also check to see if the previously selected engine is still available,
1432 * and if not, reset selection to EngineID::Invalid(). This could be the case
1433 * when engines become obsolete and are removed */
1434 for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
1435 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1436 EngineID eid = e->index;
1437 const RailVehicleInfo *rvi = &e->VehInfo<RailVehicleInfo>();
1438
1439 if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtypes, this->filter.railtype)) continue;
1440 if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
1441
1442 /* Filter now! So num_engines and num_wagons is valid */
1443 if (!FilterSingleEngine(eid)) continue;
1444
1445 if (!bdf.Filter(e->badges)) continue;
1446
1447 /* Filter by name or NewGRF extra text */
1448 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1449
1450 list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1451
1452 if (rvi->railveh_type != RAILVEH_WAGON) num_engines++;
1453
1454 /* Add all parent variants of this engine to the variant list */
1455 EngineID parent = e->info.variant_id;
1456 while (parent != EngineID::Invalid() && variants.insert(parent).second) {
1457 parent = Engine::Get(parent)->info.variant_id;
1458 }
1459
1460 if (eid == this->sel_engine) sel_id = eid;
1461 }
1462
1463 /* ensure primary engine of variant group is in list */
1464 for (const auto &variant : variants) {
1465 if (std::ranges::find(list, variant, &GUIEngineListItem::engine_id) == list.end()) {
1466 const Engine *e = Engine::Get(variant);
1467 list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1468 if (e->VehInfo<RailVehicleInfo>().railveh_type != RAILVEH_WAGON) num_engines++;
1469 }
1470 }
1471
1472 this->SelectEngine(sel_id);
1473
1474 /* invalidate cached values for name sorter - engine names could change */
1475 _last_engine[0] = _last_engine[1] = EngineID::Invalid();
1476
1477 /* make engines first, and then wagons, sorted by selected sort_criteria */
1478 _engine_sort_direction = false;
1480
1481 /* and then sort engines */
1483 EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
1484
1485 /* and finally sort wagons */
1486 EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], num_engines, list.size() - num_engines);
1487 }
1488
1489 /* Figure out what road vehicle EngineIDs to put in the list */
1490 void GenerateBuildRoadVehList()
1491 {
1492 EngineID sel_id = EngineID::Invalid();
1493
1494 this->eng_list.clear();
1495
1496 BadgeTextFilter btf(this->string_filter, GSF_ROADVEHICLES);
1497 BadgeDropdownFilter bdf(this->badge_filter_choices);
1498
1499 for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
1500 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1501 EngineID eid = e->index;
1502 if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
1503 if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->VehInfo<RoadVehicleInfo>().roadtype, this->filter.roadtype)) continue;
1504 if (!bdf.Filter(e->badges)) continue;
1505
1506 /* Filter by name or NewGRF extra text */
1507 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1508
1509 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1510
1511 if (eid == this->sel_engine) sel_id = eid;
1512 }
1513 this->SelectEngine(sel_id);
1514 }
1515
1516 /* Figure out what ship EngineIDs to put in the list */
1517 void GenerateBuildShipList()
1518 {
1519 EngineID sel_id = EngineID::Invalid();
1520 this->eng_list.clear();
1521
1522 BadgeTextFilter btf(this->string_filter, GSF_SHIPS);
1523 BadgeDropdownFilter bdf(this->badge_filter_choices);
1524
1525 for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
1526 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1527 EngineID eid = e->index;
1528 if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
1529 if (!bdf.Filter(e->badges)) continue;
1530
1531 /* Filter by name or NewGRF extra text */
1532 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1533
1534 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1535
1536 if (eid == this->sel_engine) sel_id = eid;
1537 }
1538 this->SelectEngine(sel_id);
1539 }
1540
1541 /* Figure out what aircraft EngineIDs to put in the list */
1542 void GenerateBuildAircraftList()
1543 {
1544 EngineID sel_id = EngineID::Invalid();
1545
1546 this->eng_list.clear();
1547
1548 const Station *st = this->listview_mode ? nullptr : Station::GetByTile(TileIndex(this->window_number));
1549
1550 BadgeTextFilter btf(this->string_filter, GSF_AIRCRAFT);
1551 BadgeDropdownFilter bdf(this->badge_filter_choices);
1552
1553 /* Make list of all available planes.
1554 * Also check to see if the previously selected plane is still available,
1555 * and if not, reset selection to EngineID::Invalid(). This could be the case
1556 * when planes become obsolete and are removed */
1557 for (const Engine *e : Engine::IterateType(VEH_AIRCRAFT)) {
1558 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1559 EngineID eid = e->index;
1560 if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
1561 /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
1562 if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
1563 if (!bdf.Filter(e->badges)) continue;
1564
1565 /* Filter by name or NewGRF extra text */
1566 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1567
1568 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1569
1570 if (eid == this->sel_engine) sel_id = eid;
1571 }
1572
1573 this->SelectEngine(sel_id);
1574 }
1575
1576 /* Generate the list of vehicles */
1577 void GenerateBuildList()
1578 {
1579 if (!this->eng_list.NeedRebuild()) return;
1580
1581 /* Update filter type in case the road/railtype of the depot got converted */
1582 this->UpdateFilterByTile();
1583
1584 this->eng_list.clear();
1585
1586 GUIEngineList list;
1587
1588 switch (this->vehicle_type) {
1589 default: NOT_REACHED();
1590 case VEH_TRAIN:
1591 this->GenerateBuildTrainList(list);
1592 GUIEngineListAddChildren(this->eng_list, list);
1593 this->eng_list.RebuildDone();
1594 return;
1595 case VEH_ROAD:
1596 this->GenerateBuildRoadVehList();
1597 break;
1598 case VEH_SHIP:
1599 this->GenerateBuildShipList();
1600 break;
1601 case VEH_AIRCRAFT:
1602 this->GenerateBuildAircraftList();
1603 break;
1604 }
1605
1606 this->FilterEngineList();
1607
1608 /* ensure primary engine of variant group is in list after filtering */
1609 FlatSet<EngineID> variants;
1610 for (const auto &item : this->eng_list) {
1611 EngineID parent = item.variant_id;
1612 while (parent != EngineID::Invalid() && variants.insert(parent).second) {
1614 }
1615 }
1616
1617 for (const auto &variant : variants) {
1618 if (std::ranges::find(this->eng_list, variant, &GUIEngineListItem::engine_id) == this->eng_list.end()) {
1619 const Engine *e = Engine::Get(variant);
1620 this->eng_list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1621 }
1622 }
1623
1625 EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
1626
1627 this->eng_list.swap(list);
1628 GUIEngineListAddChildren(this->eng_list, list, EngineID::Invalid(), 0);
1629 this->eng_list.RebuildDone();
1630 }
1631
1632 DropDownList BuildCargoDropDownList() const
1633 {
1634 DropDownList list;
1635
1636 /* Add item for disabling filtering. */
1637 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY));
1638 /* Specific filters for trains. */
1639 if (this->vehicle_type == VEH_TRAIN) {
1640 /* Add item for locomotives only in case of trains. */
1641 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ENGINES), CargoFilterCriteria::CF_ENGINES));
1642 /* Add item for vehicles not carrying anything, e.g. train engines.
1643 * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
1644 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE));
1645 }
1646
1647 /* Add cargos */
1648 Dimension d = GetLargestCargoIconSize();
1649 for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
1650 list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index()));
1651 }
1652
1653 return list;
1654 }
1655
1656 DropDownList BuildBadgeConfigurationList() const
1657 {
1658 static const auto separators = {STR_BADGE_CONFIG_PREVIEW, STR_BADGE_CONFIG_NAME};
1659 return BuildBadgeClassConfigurationList(this->badge_classes, BADGE_COLUMNS, separators, COLOUR_GREY);
1660 }
1661
1662 void BuildVehicle()
1663 {
1664 EngineID sel_eng = this->sel_engine;
1665 if (sel_eng == EngineID::Invalid()) return;
1666
1667 CargoType cargo = this->cargo_filter_criteria;
1668 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1669 if (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) {
1670 Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1671 } else {
1672 Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1673 }
1674
1675 /* Update last used variant in hierarchy and refresh if necessary. */
1676 bool refresh = false;
1677 EngineID parent = sel_eng;
1678 while (parent != EngineID::Invalid()) {
1679 Engine *e = Engine::Get(parent);
1680 refresh |= (e->display_last_variant != sel_eng);
1681 e->display_last_variant = sel_eng;
1682 parent = e->info.variant_id;
1683 }
1684
1685 if (refresh) {
1686 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1687 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1688 }
1689 }
1690
1691 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1692 {
1693 switch (widget) {
1695 this->descending_sort_order ^= true;
1696 _engine_sort_last_order[this->vehicle_type] = this->descending_sort_order;
1697 this->eng_list.ForceRebuild();
1698 this->SetDirty();
1699 break;
1700
1702 this->show_hidden_engines ^= true;
1703 _engine_sort_show_hidden_engines[this->vehicle_type] = this->show_hidden_engines;
1704 this->eng_list.ForceRebuild();
1705 this->SetWidgetLoweredState(widget, this->show_hidden_engines);
1706 this->SetDirty();
1707 break;
1708
1709 case WID_BV_LIST: {
1710 EngineID e = EngineID::Invalid();
1711 const auto it = this->vscroll->GetScrolledItemFromWidget(this->eng_list, pt.y, this, WID_BV_LIST);
1712 if (it != this->eng_list.end()) {
1713 const auto &item = *it;
1714 const Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL);
1715 if (item.flags.Test(EngineDisplayFlag::HasVariants) && IsInsideMM(r.left, r.right, pt.x)) {
1716 /* toggle folded flag on engine */
1717 assert(item.variant_id != EngineID::Invalid());
1718 Engine *engine = Engine::Get(item.variant_id);
1720
1721 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1722 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1723 return;
1724 }
1725 if (!item.flags.Test(EngineDisplayFlag::Shaded)) e = item.engine_id;
1726 }
1727 this->SelectEngine(e);
1728 this->SetDirty();
1729 if (_ctrl_pressed) {
1730 this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
1731 } else if (click_count > 1 && !this->listview_mode) {
1732 this->OnClick(pt, WID_BV_BUILD, 1);
1733 }
1734 break;
1735 }
1736
1737 case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
1738 DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
1739 break;
1740
1741 case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
1742 ShowDropDownList(this, this->BuildCargoDropDownList(), this->cargo_filter_criteria, widget);
1743 break;
1744
1746 if (this->badge_classes.GetClasses().empty()) break;
1747 ShowDropDownList(this, this->BuildBadgeConfigurationList(), -1, widget, 0, DropDownOption::Persist);
1748 break;
1749
1750 case WID_BV_SHOW_HIDE: {
1751 const Engine *e = (this->sel_engine == EngineID::Invalid()) ? nullptr : Engine::Get(this->sel_engine);
1752 if (e != nullptr) {
1753 Command<Commands::SetVehicleVisibility>::Post(this->sel_engine, !e->IsHidden(_current_company));
1754 }
1755 break;
1756 }
1757
1758 case WID_BV_BUILD:
1759 this->BuildVehicle();
1760 break;
1761
1762 case WID_BV_RENAME: {
1763 EngineID sel_eng = this->sel_engine;
1764 if (sel_eng != EngineID::Invalid()) {
1765 this->rename_engine = sel_eng;
1767 }
1768 break;
1769 }
1770
1771 default:
1772 if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
1773 PaletteID palette = SPR_2CCMAP_BASE + Company::Get(_local_company)->GetCompanyRecolourOffset(LS_DEFAULT);
1774 ShowDropDownList(this, this->GetWidget<NWidgetBadgeFilter>(widget)->GetDropDownList(palette), -1, widget, 0);
1775 }
1776 break;
1777 }
1778 }
1779
1785 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1786 {
1787 if (!gui_scope) return;
1788 /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
1789 if (this->vehicle_type == VEH_ROAD &&
1790 _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL &&
1791 this->sort_criteria > 7) {
1792 this->sort_criteria = 0;
1794 }
1795 this->eng_list.ForceRebuild();
1796 }
1797
1798 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1799 {
1800 switch (widget) {
1801 case WID_BV_CAPTION:
1802 if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) {
1803 const RailTypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
1804 return GetString(rti->strings.build_caption);
1805 }
1806 if (this->vehicle_type == VEH_ROAD && !this->listview_mode) {
1807 const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype);
1808 return GetString(rti->strings.build_caption);
1809 }
1810 return GetString((this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type);
1811
1813 return GetString(std::data(_engine_sort_listing[this->vehicle_type])[this->sort_criteria]);
1814
1816 return GetString(this->GetCargoFilterLabel(this->cargo_filter_criteria));
1817
1818 case WID_BV_SHOW_HIDE: {
1819 const Engine *e = (this->sel_engine == EngineID::Invalid()) ? nullptr : Engine::Get(this->sel_engine);
1820 if (e != nullptr && e->IsHidden(_local_company)) {
1821 return GetString(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type);
1822 }
1823 return GetString(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1824 }
1825
1826 default:
1827 if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
1828 return this->GetWidget<NWidgetBadgeFilter>(widget)->GetStringParameter(this->badge_filter_choices);
1829 }
1830
1831 return this->Window::GetWidgetString(widget, stringid);
1832 }
1833 }
1834
1835 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1836 {
1837 switch (widget) {
1838 case WID_BV_LIST:
1839 fill.height = resize.height = GetEngineListHeight(this->vehicle_type);
1840 size.height = 3 * resize.height;
1841 size.width = std::max(size.width, this->badge_classes.GetTotalColumnsWidth() + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165) + padding.width;
1842 break;
1843
1844 case WID_BV_PANEL:
1845 size.height = GetCharacterHeight(FS_NORMAL) * this->details_height + padding.height;
1846 break;
1847
1850 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
1851 d.height += padding.height;
1852 size = maxdim(size, d);
1853 break;
1854 }
1855
1857 size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList()).width + padding.width);
1858 break;
1859
1861 /* Hide the configuration button if no configurable badges are present. */
1862 if (this->badge_classes.GetClasses().empty()) size = {0, 0};
1863 break;
1864
1865 case WID_BV_BUILD:
1866 size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
1867 size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
1868 size.width += padding.width;
1869 size.height += padding.height;
1870 break;
1871
1872 case WID_BV_SHOW_HIDE:
1873 size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1874 size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
1875 size.width += padding.width;
1876 size.height += padding.height;
1877 break;
1878 }
1879 }
1880
1881 void DrawWidget(const Rect &r, WidgetID widget) const override
1882 {
1883 switch (widget) {
1884 case WID_BV_LIST:
1886 this->vehicle_type,
1887 r,
1888 this->eng_list,
1889 *this->vscroll,
1890 this->sel_engine,
1891 false,
1893 this->badge_classes,
1894 this->sort_criteria
1895 );
1896 break;
1897
1899 this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
1900 break;
1901 }
1902 }
1903
1904 void OnPaint() override
1905 {
1906 this->GenerateBuildList();
1907 this->vscroll->SetCount(this->eng_list.size());
1908
1909 this->SetWidgetsDisabledState(this->sel_engine == EngineID::Invalid(), WID_BV_SHOW_HIDE, WID_BV_BUILD);
1910
1911 /* Disable renaming engines in network games if you are not the server. */
1912 this->SetWidgetDisabledState(WID_BV_RENAME, this->sel_engine == EngineID::Invalid() || (_networking && !_network_server));
1913
1914 this->DrawWidgets();
1915
1916 if (!this->IsShaded()) {
1917 int needed_height = this->details_height;
1918 /* Draw details panels. */
1919 if (this->sel_engine != EngineID::Invalid()) {
1920 const Rect r = this->GetWidget<NWidgetBase>(WID_BV_PANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1921 int text_end = DrawVehiclePurchaseInfo(r.left, r.right, r.top, this->sel_engine, this->te);
1922 needed_height = std::max(needed_height, (text_end - r.top) / GetCharacterHeight(FS_NORMAL));
1923 }
1924 if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
1925 int resize = needed_height - this->details_height;
1926 this->details_height = needed_height;
1927 this->ReInit(0, resize * GetCharacterHeight(FS_NORMAL));
1928 return;
1929 }
1930 }
1931 }
1932
1933 void OnQueryTextFinished(std::optional<std::string> str) override
1934 {
1935 if (!str.has_value()) return;
1936
1937 Command<Commands::RenameEngine>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, this->rename_engine, *str);
1938 }
1939
1940 void OnDropdownSelect(WidgetID widget, int index, int click_result) override
1941 {
1942 switch (widget) {
1944 if (this->sort_criteria != index) {
1945 this->sort_criteria = index;
1946 _engine_sort_last_criteria[this->vehicle_type] = this->sort_criteria;
1947 this->eng_list.ForceRebuild();
1948 }
1949 break;
1950
1951 case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
1952 if (this->cargo_filter_criteria != index) {
1953 this->cargo_filter_criteria = index;
1954 _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter_criteria;
1955 /* deactivate filter if criteria is 'Show All', activate it otherwise */
1956 this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
1957 this->eng_list.ForceRebuild();
1958 this->SelectEngine(this->sel_engine);
1959 }
1960 break;
1961
1963 bool reopen = HandleBadgeConfigurationDropDownClick(static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type), BADGE_COLUMNS, index, click_result, this->badge_filter_choices);
1964
1965 this->ReInit();
1966
1967 if (reopen) {
1968 ReplaceDropDownList(this, this->BuildBadgeConfigurationList(), -1);
1969 } else {
1971 }
1972
1973 /* We need to refresh if a filter is removed. */
1974 this->eng_list.ForceRebuild();
1975 break;
1976 }
1977
1978 default:
1979 if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
1980 if (index < 0) {
1981 ResetBadgeFilter(this->badge_filter_choices, this->GetWidget<NWidgetBadgeFilter>(widget)->GetBadgeClassID());
1982 } else {
1983 SetBadgeFilter(this->badge_filter_choices, BadgeID(index));
1984 }
1985 this->eng_list.ForceRebuild();
1986 }
1987 break;
1988 }
1989 this->SetDirty();
1990 }
1991
1992 void OnResize() override
1993 {
1994 this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
1995 }
1996
1997 void OnEditboxChanged(WidgetID wid) override
1998 {
1999 if (wid == WID_BV_FILTER) {
2000 this->string_filter.SetFilterTerm(this->vehicle_editbox.text.GetText());
2001 this->InvalidateData();
2002 }
2003 }
2004
2005 static inline HotkeyList hotkeys{"buildvehicle", {
2006 Hotkey('F', "focus_filter_box", WID_BV_FILTER),
2007 }};
2008};
2009
2010static WindowDesc _build_vehicle_desc(
2011 WDP_AUTO, "build_vehicle", 240, 268,
2014 _nested_build_vehicle_widgets,
2015 &BuildVehicleWindow::hotkeys
2016);
2017
2018void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
2019{
2020 /* We want to be able to open both Available Train as Available Ships,
2021 * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number.
2022 * As it always is a low value, it won't collide with any real tile
2023 * number. */
2024 uint num = (tile == INVALID_TILE) ? (int)type : tile.base();
2025
2026 assert(IsCompanyBuildableVehicleType(type));
2027
2029
2030 new BuildVehicleWindow(_build_vehicle_desc, tile, type);
2031}
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
Ors the refit_masks of all articulated parts.
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
Get the capacity of the parts of a given engine.
bool IsArticulatedVehicleRefittable(EngineID engine)
Checks whether any of the articulated parts is refittable.
Functions related to articulated vehicles.
Functions related to autoreplacing.
bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group)
Check if a company has a replacement set up for the given engine.
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Compare the (NewGRF) list position.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static bool EngineIntroDateSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by introduction date.
static bool EngineCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by purchase cost.
static CargoType _engine_sort_last_cargo_criteria[]
Last set filter criteria, for each vehicle type.
void GUIEngineListAddChildren(GUIEngineList &dst, const GUIEngineList &src, EngineID parent, uint8_t indent)
Add children to GUI engine list to build a hierarchical tree.
static bool TrainEnginesThenWagonsSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of train engines by engine / wagon.
static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoType cargo_type)
Filters vehicles by cargo and engine (in case of rail vehicle).
static std::optional< std::string > GetNewGRFAdditionalText(EngineID engine)
Try to get the NewGRF engine additional text callback as an optional std::string.
static bool AircraftEngineCargoSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of aircraft by cargo.
bool _engine_sort_last_order[]
Last set direction of the sort order, for each vehicle type.
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group, const GUIBadgeClasses &badge_classes, uint8_t sort_criteria)
Engine drawing loop.
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by engineID.
uint GetEngineListHeight(VehicleType type)
Get the height of a single 'entry' in the engine lists.
static bool TrainEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of train engines by capacity.
static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
Draw aircraft specific details in the buy window.
static bool EnginePowerVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by running costs.
static bool EngineReliabilitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by reliability.
const std::initializer_list< const StringID > _engine_sort_listing[]
Dropdown menu strings for the vehicle sort criteria.
uint8_t _engine_sort_last_criteria[]
Last set sort criteria, for each vehicle type.
static bool ShipEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of ships by capacity.
int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
Draw the purchase info details of a vehicle at a given location.
static bool EngineTractiveEffortSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by tractive effort.
EngList_SortTypeFunction *const _engine_sort_functions[][11]
Sort functions for the vehicle sort criteria, for each vehicle type.
void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button)
Display the dropdown for the vehicle sort criteria.
static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
Display additional text from NewGRF in the purchase information window.
static bool EngineSpeedSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by speed.
bool _engine_sort_direction
false = descending, true = ascending.
static bool EngineNameSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by name.
static bool EnginePowerSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by power.
static bool EngineRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of engines by running costs.
static bool AircraftRangeSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of aircraft by range.
static bool RoadVehEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of road vehicles by capacity.
bool _engine_sort_show_hidden_engines[]
Last set 'show hidden engines' setting for each vehicle type.
Types related to the build_vehicle widgets.
@ WID_BV_BUILD
Build panel.
@ WID_BV_SHOW_HIDE
Button to hide or show the selected engine.
@ WID_BV_SORT_ASCENDING_DESCENDING
Sort direction.
@ WID_BV_CAPTION
Caption of window.
@ WID_BV_SHOW_HIDDEN_ENGINES
Toggle whether to display the hidden vehicles.
@ WID_BV_CONFIGURE_BADGES
Button to configure badges.
@ WID_BV_BADGE_FILTER
Container for dropdown badge filters.
@ WID_BV_LIST
List of vehicles.
@ WID_BV_SORT_DROPDOWN
Criteria of sorting dropdown.
@ WID_BV_RENAME
Rename button.
@ WID_BV_SCROLLBAR
Scrollbar of list.
@ WID_BV_BUILD_SEL
Build button.
@ WID_BV_PANEL
Button panel.
@ WID_BV_FILTER
Filter by name.
@ WID_BV_CARGO_FILTER_DROPDOWN
Cargo filter dropdown.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:108
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
std::span< const CargoSpec * > _sorted_standard_cargo_specs
Standard cargo specifications sorted alphabetically by name.
CargoTypes _standard_cargo_mask
Bitmask of real cargo types available.
Definition cargotype.cpp:36
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Types/functions related to cargoes.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Flip(Tvalue_type value)
Flip the value-th bit.
StringID GetAircraftTypeText() const
Get the name of the aircraft type for display purposes.
Definition engine.cpp:470
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition engine.cpp:393
uint16_t GetRange() const
Get the range of an aircraft type.
Definition engine.cpp:456
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:160
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:321
TimerGameCalendar::Date intro_date
Date of introduction of the engine.
Definition engine_base.h:46
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
uint GetDisplayMaxSpeed() const
Returns max speed of the engine for display purposes.
Definition engine.cpp:361
EngineDisplayFlags display_flags
NOSAVE client-side-only display flags for build engine list.
Definition engine_base.h:64
uint GetDisplayWeight() const
Returns the weight of the engine for display purposes.
Definition engine.cpp:411
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:62
bool IsVariantHidden(CompanyID c) const
Check whether the engine variant chain is hidden in the GUI for the given company.
Definition engine.cpp:490
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:446
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity=nullptr) const
Determines the default cargo capacity of an engine for display purposes.
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
CompanyMask company_hidden
Bit for each company whether the engine is normally hidden in the build gui for that company.
Definition engine_base.h:41
Money GetRunningCost() const
Return how much the running costs of this engine are.
Definition engine.cpp:284
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:49
uint GetDisplayMaxTractiveEffort() const
Returns the tractive effort of the engine for display purposes.
Definition engine.cpp:429
bool IsHidden(CompanyID c) const
Check whether the engine is hidden in the GUI for the given company.
EngineID display_last_variant
NOSAVE client-side-only last variant selected.
Definition engine_base.h:65
Flat set implementation that uses a sorted vector for storage.
std::pair< const_iterator, bool > insert(const Tkey &key)
Insert a key into the set, if it does not already exist.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void SetFilterState(bool state)
Enable or disable the filter.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
bool(const GUIEngineListItem *a, CargoType filter) FilterFunction
void SetToolTip(StringID tool_tip)
Set the tool tip of the nested widget.
Definition widget.cpp:1225
void SetLowered(bool lowered)
Lower or raise the widget.
void SetStringTip(StringID string, StringID tool_tip)
Set string and tool tip of the nested widget.
Definition widget.cpp:1165
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:115
struct RailTypeInfo::@157247141350136173143103254227157213063052244122 strings
Strings associated with the rail type.
VehicleAccelerationModel acceleration_type
Acceleration type of this rail type.
Definition rail.h:215
StringID name
Name of this rail type.
Definition rail.h:165
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition rail.h:168
struct RoadTypeInfo::@070000167274302256150317022075324310363002361255 strings
Strings associated with the rail type.
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition road.h:80
Scrollbar data structure.
void SetCount(size_t num)
Sets the number of elements in the list.
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.
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:2500
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static constexpr Year DateToYear(Date date)
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
Functions related to commands.
@ QueryCost
query cost only, don't build.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
VehicleCellSize GetVehicleImageCellSize(VehicleType type, EngineImageType image_type)
Get the GUI cell size for a vehicle image.
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:459
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
Definition dropdown.cpp:381
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options)
Show a drop down list.
Definition dropdown.cpp:419
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.
@ Persist
Set if this dropdown should stay open after an option is selected.
@ Invalid
Invalid base price.
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1251
Base class for engines.
@ HasVariants
Set if engine has variants.
Definition engine_base.h:28
@ IsFolded
Set if display of variants should be folded (hidden).
Definition engine_base.h:29
@ Shaded
Set if engine should be masked.
Definition engine_base.h:30
Command definitions related to engines.
Functions related to engines.
uint GetTotalCapacityOfArticulatedParts(EngineID engine)
Get the capacity of an engine with articulated parts.
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare)
Sort all items using quick sort and given 'CompareItems' function.
void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items)
Sort selected range of items (on indices @ <begin, begin+num_items-1>).
void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
Draw an engine.
Engine GUI functions, used by build_vehicle_gui and autoreplace_gui.
bool EngList_SortTypeFunction(const GUIEngineListItem &, const GUIEngineListItem &)
argument type for EngList_Sort.
Definition engine_gui.h:33
static const uint MAX_LENGTH_ENGINE_NAME_CHARS
The maximum length of an engine name in characters including '\0'.
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
uint64_t PackEngineNameDParam(EngineID engine_id, EngineNameContext context, uint32_t extra_data=0)
Combine an engine ID and a name context to an engine name StringParameter.
@ PurchaseList
Name is shown in the purchase list (including autoreplace window 'Available vehicles' panel).
@ Generic
No specific context available.
@ AutoreplaceVehicleInUse
Name is show in the autoreplace window 'Vehicles in use' panel.
@ Maglev
Maglev acceleration model.
Definition engine_type.h:50
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:34
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:33
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:972
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:900
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:669
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
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:788
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:68
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:250
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:390
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:400
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
@ TC_FORCED
Ignore colour changes from strings.
Definition gfx_type.h:332
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:331
Base class for groups and group functions.
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
Get the number of engines with EngineID id_e in the group with GroupID id_g and its sub-groups.
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
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.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart SetTextStyle(TextColour colour, FontSize size=FS_NORMAL)
Widget part function for setting the text style.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
void SetDirty() const
Mark entire window as dirty (in need of re-paint).
Definition window.cpp:967
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
Hotkey related functions.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
static constexpr CargoType CF_NONE
Show only items which do not carry cargo (e.g. train engines).
Definition cargo_type.h:94
static constexpr CargoType CF_ENGINES
Show only engines (for rail vehicles only).
Definition cargo_type.h:95
static constexpr CargoType CF_ANY
Show all items independent of carried cargo (i.e. no filtering).
Definition cargo_type.h:93
bool _networking
are we in networking mode?
Definition network.cpp:66
bool _network_server
network-server is active
Definition network.cpp:67
Basic functions/variables used all over the place.
@ INVALID_CLIENT_ID
Client is not part of anything.
GrfSpecFeature
Definition newgrf.h:71
Functions related to NewGRF badges.
Functions related to NewGRF badge configuration.
int DrawBadgeNameList(Rect r, std::span< const BadgeID > badges, GrfSpecFeature)
Draw names for a list of badge labels.
void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span< const BadgeID > badges, GrfSpecFeature feature, std::optional< TimerGameCalendar::Date > introduction_date, PaletteID remap)
Draw a badge column group.
std::pair< WidgetID, WidgetID > AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature)
Add badge drop down filter widgets.
bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result, BadgeFilterChoices &choices)
Handle the badge configuration drop down selection.
void SetBadgeFilter(BadgeFilterChoices &choices, BadgeID badge_index)
Set badge filter choice for a class.
void ResetBadgeFilter(BadgeFilterChoices &choices, BadgeClassID badge_class_index)
Reset badge filter choice for a class.
GUI functions related to NewGRF badges.
@ CBID_VEHICLE_ADDITIONAL_TEXT
This callback is called from vehicle purchase lists.
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.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles.
Functions for NewGRF engines.
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span< const int32_t > textstack)
Format a GRF string using the text ref stack for parameters.
Header of Action 04 "universal holder" structure and functions.
StrongType::Typedef< uint32_t, struct GRFStringIDTag, StrongType::Compare, StrongType::Integer > GRFStringID
Type for GRF-internal string IDs.
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:388
Base for the GUIs that have an edit box in them.
std::vector< RailType > _sorted_railtypes
Sorted list of rail types.
Definition rail_cmd.cpp:47
bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition rail.h:376
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:300
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition rail_map.h:115
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:25
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:32
bool HasPowerOnRoad(RoadType enginetype, RoadType tiletype)
Checks if an engine of the given RoadType got power on a tile with a given RoadType.
Definition road.h:230
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
RoadType GetRoadTypeRoad(Tile t)
Get the road type for RoadTramType being RTT_ROAD.
Definition road_map.h:152
RoadType GetRoadTypeTram(Tile t)
Get the road type for RoadTramType being RTT_TRAM.
Definition road_map.h:163
RoadType
The different roadtypes we support.
Definition road_type.h:23
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
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:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1619
Base classes/functions for stations.
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:427
Functions related to low-level strings.
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
Searching and filtering using a stringterm.
std::string_view GetListSeparator()
Get the list separator string for the current language.
Definition strings.cpp:299
void AppendStringInPlace(std::string &result, StringID string)
Resolve the given StringID and append in place into an existing std::string with formatting but no pa...
Definition strings.cpp:434
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
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.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
GUI for building vehicles.
VehicleType vehicle_type
Type of vehicles shown in the window.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
static constexpr int BADGE_COLUMNS
Number of columns available for badges (0 = left of image, 1 = between image and name,...
bool FilterByText(const Engine *e)
Filter by name and NewGRF extra text.
void UpdateFilterByTile()
Set the filter type according to the depot type.
bool descending_sort_order
Sort direction,.
bool listview_mode
If set, only display the available vehicles and do not show a 'build' button.
void OnDropdownSelect(WidgetID widget, int index, int click_result) override
A dropdown option associated to this window has been selected.
CargoType cargo_filter_criteria
Selected cargo filter.
void SetCargoFilterArray()
Populate the filter list and set the cargo filter criteria.
RailType railtype
Rail type to show, or INVALID_RAILTYPE.
union BuildVehicleWindow::@015063063316140361220303015310112114302264111156 filter
Filter to apply.
void OnPaint() override
The window must be repainted.
int details_height
Minimal needed height of the details panels, in text lines (found so far).
QueryString vehicle_editbox
Filter editbox.
void OnResize() override
Called after the window got resized.
bool show_hidden_engines
State of the 'show hidden engines' button.
void FilterEngineList()
Filter the engine list against the currently selected cargo filter.
EngineID rename_engine
Engine being renamed.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
TestedEngineDetails te
Tested cost and capacity after refit.
std::pair< WidgetID, WidgetID > badge_filters
First and last widgets IDs of badge filters.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
StringFilter string_filter
Filter for vehicle name.
uint8_t sort_criteria
Current sort criterium.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
bool FilterSingleEngine(EngineID eid)
Filter a single engine.
EngineID sel_engine
Currently selected engine, or EngineID::Invalid().
RoadType roadtype
Road type to show, or INVALID_ROADTYPE.
void OnInit() override
Notification that the nested widget tree gets initialized.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
Class for storing amounts of cargo.
Definition cargo_type.h:115
Specification of a cargo type.
Definition cargotype.h:74
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:138
StringID name
Name of this type of cargo.
Definition cargotype.h:91
Dimensions (a width and height) of a rectangle in 2D.
EngineID variant_id
Engine variant ID. If set, will be treated specially in purchase lists.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
Information about GRF, used in the game and (part of it) in savegames.
std::string GetName() const
Get the name of this grf.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:117
EngineDisplayFlags flags
Flags for toggling/drawing (un)folded status and controlling indentation.
Definition engine_gui.h:24
EngineID variant_id
Variant group of the engine.
Definition engine_gui.h:23
EngineID engine_id
Engine to display in build purchase list.
Definition engine_gui.h:22
uint8_t indent
Display indentation level.
Definition engine_gui.h:25
List of hotkeys for a window.
Definition hotkeys.h:37
All data for a single hotkey.
Definition hotkeys.h:21
Colour for pixel/line drawing.
Definition gfx_type.h:405
static Engine * Get(auto index)
Data stored about a string that can be modified in the GUI.
static const int ACTION_CLEAR
Clear editbox.
Information about a rail vehicle.
Definition engine_type.h:74
RailTypes railtypes
Railtypes, mangled if elrail is disabled.
Definition engine_type.h:78
uint16_t pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition engine_type.h:88
uint8_t pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition engine_type.h:89
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
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.
int Height() const
Get height of Rect.
Rect WithY(int new_top, int new_bottom) const
Create a new Rect, replacing the top and bottom coordiates.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
Information about a ship vehicle.
Definition engine_type.h:99
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(std::string_view str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
bool GetState() const
Get the matching state of the current item.
Extra information about refitted cargo and capacity.
Definition vehicle_gui.h:42
CargoType cargo
Cargo type.
Definition vehicle_gui.h:44
Money cost
Refit cost.
Definition vehicle_gui.h:43
CargoArray all_capacities
Capacities for all cargoes.
Definition vehicle_gui.h:47
uint16_t mail_capacity
Mail capacity if available.
Definition vehicle_gui.h:46
uint capacity
Cargo capacity.
Definition vehicle_gui.h:45
std::string_view GetText() const
Get the current text.
Definition textbuf.cpp:284
uint extend_left
Extend of the cell to the left.
Definition vehicle_gui.h:85
uint extend_right
Extend of the cell to the right.
Definition vehicle_gui.h:86
High level window description.
Definition window_gui.h:168
Data structure for an opened window.
Definition window_gui.h:274
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:979
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:815
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1809
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:321
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:766
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3247
Window * parent
Parent window.
Definition window_gui.h:329
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:505
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:798
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1076
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:516
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1799
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:560
WidgetLookup widget_lookup
Indexed access to the nested widget tree. Do not access directly, use Window::GetWidget() instead.
Definition window_gui.h:323
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1832
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:986
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
std::unique_ptr< NWidgetBase > nested_root
Root of the nested tree.
Definition window_gui.h:322
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
Stuff related to the text buffer GUI.
@ EnableDefault
enable the 'Default' button ("\0" is returned)
Definition textbuf_gui.h:20
@ LengthIsInChars
the length of the string is counted in characters
Definition textbuf_gui.h:21
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
Definition of the game-calendar-timer.
Command definitions related to trains.
void CcBuildWagon(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray, TileIndex tile, EngineID, bool, CargoType, ClientID)
Callback for building wagons.
Definition train_gui.cpp:29
PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition vehicle.cpp:2136
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3060
Command definitions for vehicles.
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.
Functions related to vehicles.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
uint ShowRefitOptionsList(int left, int right, int y, EngineID engine)
Display list of cargo types of the engine, for the purchase information window.
Functions related to the vehicle's GUIs.
@ EIT_PURCHASE
Vehicle drawn in purchase list, autoreplace gui, ...
VehicleType
Available vehicle types.
@ VEH_INVALID
Non-existing type of vehicle.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
static const uint MAX_LENGTH_VEHICLE_NAME_CHARS
The maximum length of a vehicle name in characters including '\0'.
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:41
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:62
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX).
Definition widget_type.h:57
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX).
Definition widget_type.h:55
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window).
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX).
Definition widget_type.h:56
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
NWidContainerFlag
Nested widget container flags,.
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:1196
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3307
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition window.cpp:3325
Window functions not directly related to making/drawing windows.
@ Construction
This window is used for construction; close it whenever changing company.
Definition window_gui.h:153
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:219
@ SBS_UP
Sort descending.
Definition window_gui.h:220
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_REPLACE_VEHICLE
Replace vehicle window; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers:
@ Station
station encountered (could be a target next time)
Definition yapf_type.hpp:26
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition zoom_func.h:107