OpenTTD Source 20250311-master-g40ddc03423
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 <http://www.gnu.org/licenses/>.
6 */
7
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_engine.h"
22#include "newgrf_text.h"
23#include "group.h"
24#include "string_func.h"
25#include "strings_func.h"
26#include "window_func.h"
28#include "vehicle_func.h"
29#include "dropdown_type.h"
30#include "dropdown_func.h"
31#include "engine_gui.h"
32#include "cargotype.h"
34#include "autoreplace_func.h"
35#include "engine_cmd.h"
36#include "train_cmd.h"
37#include "vehicle_cmd.h"
38#include "zoom_func.h"
39#include "querystring_gui.h"
40#include "stringfilter_type.h"
41#include "hotkeys.h"
42
44
45#include "table/strings.h"
46
47#include "safeguards.h"
48
55{
56 return std::max<uint>(GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.matrix.Vertical(), GetVehicleImageCellSize(type, EIT_PURCHASE).height);
57}
58
59static constexpr NWidgetPart _nested_build_vehicle_widgets[] = {
61 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
62 NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetTextStyle(TC_WHITE),
63 NWidget(WWT_SHADEBOX, COLOUR_GREY),
64 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
65 NWidget(WWT_STICKYBOX, COLOUR_GREY),
69 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASCENDING_DESCENDING), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
70 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetToolTip(STR_TOOLTIP_SORT_CRITERIA),
74 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetToolTip(STR_TOOLTIP_FILTER_CRITERIA),
76 NWidget(WWT_PANEL, COLOUR_GREY),
77 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),
80 /* Vehicle list. */
85 /* Panel with details. */
86 NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(),
87 /* Build/rename buttons, resize button. */
89 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL),
90 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0),
92 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE), SetResize(1, 0), SetFill(1, 0),
93 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0),
94 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
96};
97
98
100uint8_t _engine_sort_last_criteria[] = {0, 0, 0, 0};
101bool _engine_sort_last_order[] = {false, false, false, false};
102bool _engine_sort_show_hidden_engines[] = {false, false, false, false};
104
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
125{
126 const auto va = Engine::Get(a.engine_id)->intro_date;
127 const auto vb = Engine::Get(b.engine_id)->intro_date;
128 const auto r = va - vb;
129
130 /* Use EngineID to sort instead since we want consistent sorting */
131 if (r == 0) return EngineNumberSorter(a, b);
132 return _engine_sort_direction ? r > 0 : r < 0;
133}
134
135/* cached values for EngineNameSorter to spare many GetString() calls */
136static EngineID _last_engine[2] = { EngineID::Invalid(), EngineID::Invalid() };
137
145{
146 static std::string last_name[2] = { {}, {} };
147
148 if (a.engine_id != _last_engine[0]) {
149 _last_engine[0] = a.engine_id;
150 last_name[0] = GetString(STR_ENGINE_NAME, PackEngineNameDParam(a.engine_id, EngineNameContext::PurchaseList));
151 }
152
153 if (b.engine_id != _last_engine[1]) {
154 _last_engine[1] = b.engine_id;
155 last_name[1] = GetString(STR_ENGINE_NAME, PackEngineNameDParam(b.engine_id, EngineNameContext::PurchaseList));
156 }
157
158 int r = StrNaturalCompare(last_name[0], last_name[1]); // Sort by name (natural sorting).
159
160 /* Use EngineID to sort instead since we want consistent sorting */
161 if (r == 0) return EngineNumberSorter(a, b);
162 return _engine_sort_direction ? r > 0 : r < 0;
163}
164
172{
173 const int va = Engine::Get(a.engine_id)->reliability;
174 const int vb = Engine::Get(b.engine_id)->reliability;
175 const int r = va - vb;
176
177 /* Use EngineID to sort instead since we want consistent sorting */
178 if (r == 0) return EngineNumberSorter(a, b);
179 return _engine_sort_direction ? r > 0 : r < 0;
180}
181
189{
190 Money va = Engine::Get(a.engine_id)->GetCost();
191 Money vb = Engine::Get(b.engine_id)->GetCost();
192 int r = ClampTo<int32_t>(va - vb);
193
194 /* Use EngineID to sort instead since we want consistent sorting */
195 if (r == 0) return EngineNumberSorter(a, b);
196 return _engine_sort_direction ? r > 0 : r < 0;
197}
198
206{
207 int va = Engine::Get(a.engine_id)->GetDisplayMaxSpeed();
208 int vb = Engine::Get(b.engine_id)->GetDisplayMaxSpeed();
209 int r = va - vb;
210
211 /* Use EngineID to sort instead since we want consistent sorting */
212 if (r == 0) return EngineNumberSorter(a, b);
213 return _engine_sort_direction ? r > 0 : r < 0;
214}
215
223{
224 int va = Engine::Get(a.engine_id)->GetPower();
225 int vb = Engine::Get(b.engine_id)->GetPower();
226 int r = va - vb;
227
228 /* Use EngineID to sort instead since we want consistent sorting */
229 if (r == 0) return EngineNumberSorter(a, b);
230 return _engine_sort_direction ? r > 0 : r < 0;
231}
232
240{
241 int va = Engine::Get(a.engine_id)->GetDisplayMaxTractiveEffort();
242 int vb = Engine::Get(b.engine_id)->GetDisplayMaxTractiveEffort();
243 int r = va - vb;
244
245 /* Use EngineID to sort instead since we want consistent sorting */
246 if (r == 0) return EngineNumberSorter(a, b);
247 return _engine_sort_direction ? r > 0 : r < 0;
248}
249
257{
258 Money va = Engine::Get(a.engine_id)->GetRunningCost();
259 Money vb = Engine::Get(b.engine_id)->GetRunningCost();
260 int r = ClampTo<int32_t>(va - vb);
261
262 /* Use EngineID to sort instead since we want consistent sorting */
263 if (r == 0) return EngineNumberSorter(a, b);
264 return _engine_sort_direction ? r > 0 : r < 0;
265}
266
274{
275 const Engine *e_a = Engine::Get(a.engine_id);
276 const Engine *e_b = Engine::Get(b.engine_id);
277 uint p_a = e_a->GetPower();
278 uint p_b = e_b->GetPower();
279 Money r_a = e_a->GetRunningCost();
280 Money r_b = e_b->GetRunningCost();
281 /* Check if running cost is zero in one or both engines.
282 * If only one of them is zero then that one has higher value,
283 * else if both have zero cost then compare powers. */
284 if (r_a == 0) {
285 if (r_b == 0) {
286 /* If it is ambiguous which to return go with their ID */
287 if (p_a == p_b) return EngineNumberSorter(a, b);
288 return _engine_sort_direction != (p_a < p_b);
289 }
291 }
292 if (r_b == 0) return _engine_sort_direction;
293 /* Using double for more precision when comparing close values.
294 * This shouldn't have any major effects in performance nor in keeping
295 * the game in sync between players since it's used in GUI only in client side */
296 double v_a = (double)p_a / (double)r_a;
297 double v_b = (double)p_b / (double)r_b;
298 /* Use EngineID to sort if both have same power/running cost,
299 * since we want consistent sorting.
300 * Also if both have no power then sort with reverse of running cost to simulate
301 * previous sorting behaviour for wagons. */
302 if (v_a == 0 && v_b == 0) return EngineRunningCostSorter(b, a);
303 if (v_a == v_b) return EngineNumberSorter(a, b);
304 return _engine_sort_direction != (v_a < v_b);
305}
306
307/* Train sorting functions */
308
316{
317 const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
318 const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
319
320 int va = GetTotalCapacityOfArticulatedParts(a.engine_id) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
321 int vb = GetTotalCapacityOfArticulatedParts(b.engine_id) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
322 int r = va - vb;
323
324 /* Use EngineID to sort instead since we want consistent sorting */
325 if (r == 0) return EngineNumberSorter(a, b);
326 return _engine_sort_direction ? r > 0 : r < 0;
327}
328
336{
337 int val_a = (RailVehInfo(a.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
338 int val_b = (RailVehInfo(b.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
339 int r = val_a - val_b;
340
341 /* Use EngineID to sort instead since we want consistent sorting */
342 if (r == 0) return EngineNumberSorter(a, b);
343 return _engine_sort_direction ? r > 0 : r < 0;
344}
345
346/* Road vehicle sorting functions */
347
355{
358 int r = va - vb;
359
360 /* Use EngineID to sort instead since we want consistent sorting */
361 if (r == 0) return EngineNumberSorter(a, b);
362 return _engine_sort_direction ? r > 0 : r < 0;
363}
364
365/* Ship vehicle sorting functions */
366
374{
375 const Engine *e_a = Engine::Get(a.engine_id);
376 const Engine *e_b = Engine::Get(b.engine_id);
377
378 int va = e_a->GetDisplayDefaultCapacity();
379 int vb = e_b->GetDisplayDefaultCapacity();
380 int r = va - vb;
381
382 /* Use EngineID to sort instead since we want consistent sorting */
383 if (r == 0) return EngineNumberSorter(a, b);
384 return _engine_sort_direction ? r > 0 : r < 0;
385}
386
387/* Aircraft sorting functions */
388
396{
397 const Engine *e_a = Engine::Get(a.engine_id);
398 const Engine *e_b = Engine::Get(b.engine_id);
399
400 uint16_t mail_a, mail_b;
401 int va = e_a->GetDisplayDefaultCapacity(&mail_a);
402 int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
403 int r = va - vb;
404
405 if (r == 0) {
406 /* The planes have the same passenger capacity. Check mail capacity instead */
407 r = mail_a - mail_b;
408
409 if (r == 0) {
410 /* Use EngineID to sort instead since we want consistent sorting */
411 return EngineNumberSorter(a, b);
412 }
413 }
414 return _engine_sort_direction ? r > 0 : r < 0;
415}
416
424{
425 uint16_t r_a = Engine::Get(a.engine_id)->GetRange();
426 uint16_t r_b = Engine::Get(b.engine_id)->GetRange();
427
428 int r = r_a - r_b;
429
430 /* Use EngineID to sort instead since we want consistent sorting */
431 if (r == 0) return EngineNumberSorter(a, b);
432 return _engine_sort_direction ? r > 0 : r < 0;
433}
434
484
486const std::initializer_list<const StringID> _engine_sort_listing[] = {{
487 /* Trains */
488 STR_SORT_BY_ENGINE_ID,
489 STR_SORT_BY_COST,
490 STR_SORT_BY_MAX_SPEED,
491 STR_SORT_BY_POWER,
492 STR_SORT_BY_TRACTIVE_EFFORT,
493 STR_SORT_BY_INTRO_DATE,
494 STR_SORT_BY_NAME,
495 STR_SORT_BY_RUNNING_COST,
496 STR_SORT_BY_POWER_VS_RUNNING_COST,
497 STR_SORT_BY_RELIABILITY,
498 STR_SORT_BY_CARGO_CAPACITY,
499}, {
500 /* Road vehicles */
501 STR_SORT_BY_ENGINE_ID,
502 STR_SORT_BY_COST,
503 STR_SORT_BY_MAX_SPEED,
504 STR_SORT_BY_POWER,
505 STR_SORT_BY_TRACTIVE_EFFORT,
506 STR_SORT_BY_INTRO_DATE,
507 STR_SORT_BY_NAME,
508 STR_SORT_BY_RUNNING_COST,
509 STR_SORT_BY_POWER_VS_RUNNING_COST,
510 STR_SORT_BY_RELIABILITY,
511 STR_SORT_BY_CARGO_CAPACITY,
512}, {
513 /* Ships */
514 STR_SORT_BY_ENGINE_ID,
515 STR_SORT_BY_COST,
516 STR_SORT_BY_MAX_SPEED,
517 STR_SORT_BY_INTRO_DATE,
518 STR_SORT_BY_NAME,
519 STR_SORT_BY_RUNNING_COST,
520 STR_SORT_BY_RELIABILITY,
521 STR_SORT_BY_CARGO_CAPACITY,
522}, {
523 /* Aircraft */
524 STR_SORT_BY_ENGINE_ID,
525 STR_SORT_BY_COST,
526 STR_SORT_BY_MAX_SPEED,
527 STR_SORT_BY_INTRO_DATE,
528 STR_SORT_BY_NAME,
529 STR_SORT_BY_RUNNING_COST,
530 STR_SORT_BY_RELIABILITY,
531 STR_SORT_BY_CARGO_CAPACITY,
532 STR_SORT_BY_RANGE,
533}};
534
536static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoType cargo_type)
537{
538 if (cargo_type == CargoFilterCriteria::CF_ANY) {
539 return true;
540 } else if (cargo_type == CargoFilterCriteria::CF_ENGINES) {
541 return Engine::Get(item->engine_id)->GetPower() != 0;
542 } else {
543 CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(item->engine_id, true) & _standard_cargo_mask;
544 return (cargo_type == CargoFilterCriteria::CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cargo_type));
545 }
546}
547
548static GUIEngineList::FilterFunction * const _engine_filter_funcs[] = {
550};
551
552static uint GetCargoWeight(const CargoArray &cap, VehicleType vtype)
553{
554 uint weight = 0;
555 for (CargoType c = 0; c < NUM_CARGO; c++) {
556 if (cap[c] != 0) {
557 if (vtype == VEH_TRAIN) {
558 weight += CargoSpec::Get(c)->WeightOfNUnitsInTrain(cap[c]);
559 } else {
560 weight += CargoSpec::Get(c)->WeightOfNUnits(cap[c]);
561 }
562 }
563 }
564 return weight;
565}
566
567static int DrawCargoCapacityInfo(int left, int right, int y, TestedEngineDetails &te, bool refittable)
568{
569 for (const CargoSpec *cs : _sorted_cargo_specs) {
570 CargoType cargo_type = cs->Index();
571 if (te.all_capacities[cargo_type] == 0) continue;
572
573 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, cargo_type, te.all_capacities[cargo_type], refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
575 }
576
577 return y;
578}
579
580/* Draw rail wagon specific details */
581static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
582{
583 const Engine *e = Engine::Get(engine_number);
584
585 /* Purchase cost */
586 if (te.cost != 0) {
587 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
588 } else {
589 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
590 }
592
593 /* Wagon weight - (including cargo) */
594 uint weight = e->GetDisplayWeight();
595 DrawString(left, right, y,
596 GetString(STR_PURCHASE_INFO_WEIGHT_CWEIGHT, weight, GetCargoWeight(te.all_capacities, VEH_TRAIN) + weight));
598
599 /* Wagon speed limit, displayed if above zero */
601 uint max_speed = e->GetDisplayMaxSpeed();
602 if (max_speed > 0) {
603 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED, PackVelocity(max_speed, e->type)));
605 }
606 }
607
608 /* Running cost */
609 if (rvi->running_cost_class != INVALID_PRICE) {
610 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
612 }
613
614 return y;
615}
616
617/* Draw locomotive specific details */
618static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
619{
620 const Engine *e = Engine::Get(engine_number);
621
622 /* Purchase Cost - Engine weight */
623 if (te.cost != 0) {
624 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_WEIGHT, e->GetCost() + te.cost, te.cost, e->GetDisplayWeight()));
625 } else {
626 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_WEIGHT, e->GetCost(), e->GetDisplayWeight()));
627 }
629
630 /* Max speed - Engine power */
631 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
633
634 /* Max tractive effort - not applicable if old acceleration or maglev */
636 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
638 }
639
640 /* Running cost */
641 if (rvi->running_cost_class != INVALID_PRICE) {
642 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
644 }
645
646 /* Powered wagons power - Powered wagons extra weight */
647 if (rvi->pow_wag_power != 0) {
648 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, rvi->pow_wag_power, rvi->pow_wag_weight));
650 }
651
652 return y;
653}
654
655/* Draw road vehicle specific details */
656static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
657{
658 const Engine *e = Engine::Get(engine_number);
659
661 /* Purchase Cost */
662 if (te.cost != 0) {
663 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
664 } else {
665 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
666 }
668
669 /* Road vehicle weight - (including cargo) */
670 int16_t weight = e->GetDisplayWeight();
671 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_WEIGHT_CWEIGHT, weight, GetCargoWeight(te.all_capacities, VEH_ROAD) + weight));
673
674 /* Max speed - Engine power */
675 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
677
678 /* Max tractive effort */
679 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
681 } else {
682 /* Purchase cost - Max speed */
683 if (te.cost != 0) {
684 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
685 } else {
686 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
687 }
689 }
690
691 /* Running cost */
692 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
694
695 return y;
696}
697
698/* Draw ship specific details */
699static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
700{
701 const Engine *e = Engine::Get(engine_number);
702
703 /* Purchase cost - Max speed */
704 uint raw_speed = e->GetDisplayMaxSpeed();
705 uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
706 uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
707
708 if (ocean_speed == canal_speed) {
709 if (te.cost != 0) {
710 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(ocean_speed, e->type)));
711 } else {
712 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(ocean_speed, e->type)));
713 }
715 } else {
716 if (te.cost != 0) {
717 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
718 } else {
719 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
720 }
722
723 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_OCEAN, PackVelocity(ocean_speed, e->type)));
725
726 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_CANAL, PackVelocity(canal_speed, e->type)));
728 }
729
730 /* Cargo type + capacity */
731 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, te.cargo, te.capacity, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
733
734 /* Running cost */
735 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
737
738 return y;
739}
740
750static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
751{
752 const Engine *e = Engine::Get(engine_number);
753
754 /* Purchase cost - Max speed */
755 if (te.cost != 0) {
756 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
757 } else {
758 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
759 }
761
762 /* Cargo capacity */
763 if (te.mail_capacity > 0) {
764 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, te.cargo, te.capacity, GetCargoTypeByLabel(CT_MAIL), te.mail_capacity));
765 } else {
766 /* Note, if the default capacity is selected by the refit capacity
767 * callback, then the capacity shown is likely to be incorrect. */
768 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, te.cargo, te.capacity, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
769 }
771
772 /* Running cost */
773 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
775
776 /* Aircraft type */
777 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_TYPE, e->GetAircraftTypeText()));
779
780 /* Aircraft range, if available. */
781 uint16_t range = e->GetRange();
782 if (range != 0) {
783 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_RANGE, range));
785 }
786
787 return y;
788}
789
790
796static std::optional<std::string> GetNewGRFAdditionalText(EngineID engine)
797{
798 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr);
799 if (callback == CALLBACK_FAILED || callback == 0x400) return std::nullopt;
800 const GRFFile *grffile = Engine::Get(engine)->GetGRF();
801 assert(grffile != nullptr);
802 if (callback > 0x400) {
804 return std::nullopt;
805 }
806
807 return GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
808}
809
818static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
819{
820 auto text = GetNewGRFAdditionalText(engine);
821 if (!text) return y;
822 return DrawStringMultiLine(left, right, y, INT32_MAX, *text, TC_BLACK);
823}
824
825void TestedEngineDetails::FillDefaultCapacities(const Engine *e)
826{
827 this->cargo = e->GetDefaultCargoType();
828 if (e->type == VEH_TRAIN || e->type == VEH_ROAD) {
830 this->capacity = this->all_capacities[this->cargo];
831 this->mail_capacity = 0;
832 } else {
834 this->all_capacities[this->cargo] = this->capacity;
835 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
836 this->all_capacities[GetCargoTypeByLabel(CT_MAIL)] = this->mail_capacity;
837 } else {
838 this->mail_capacity = 0;
839 }
840 }
841 if (this->all_capacities.GetCount() == 0) this->cargo = INVALID_CARGO;
842}
843
850int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
851{
852 const Engine *e = Engine::Get(engine_number);
853 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
854 bool refittable = IsArticulatedVehicleRefittable(engine_number);
855 bool articulated_cargo = false;
856
857 switch (e->type) {
858 default: NOT_REACHED();
859 case VEH_TRAIN:
860 if (e->u.rail.railveh_type == RAILVEH_WAGON) {
861 y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
862 } else {
863 y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
864 }
865 articulated_cargo = true;
866 break;
867
868 case VEH_ROAD:
869 y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te);
870 articulated_cargo = true;
871 break;
872
873 case VEH_SHIP:
874 y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te);
875 break;
876
877 case VEH_AIRCRAFT:
878 y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
879 break;
880 }
881
882 if (articulated_cargo) {
883 /* Cargo type + capacity, or N/A */
884 int new_y = DrawCargoCapacityInfo(left, right, y, te, refittable);
885
886 if (new_y == y) {
887 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, INVALID_CARGO, 0, STR_EMPTY));
889 } else {
890 y = new_y;
891 }
892 }
893
894 /* Draw details that apply to all types except rail wagons. */
895 if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
896 /* Design date - Life length */
897 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_DESIGNED_LIFE, ymd.year, TimerGameCalendar::DateToYear(e->GetLifeLengthInDays())));
899
900 /* Reliability */
901 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_RELIABILITY, ToPercent16(e->reliability)));
903 }
904
905 if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
906
907 y = DrawBadgeNameList({left, y, right, INT16_MAX}, e->badges, static_cast<GrfSpecFeature>(GSF_TRAINS + e->type));
908
909 /* Additional text from NewGRF */
910 y = ShowAdditionalText(left, right, y, engine_number);
911
912 /* The NewGRF's name which the vehicle comes from */
913 const GRFConfig *config = GetGRFConfig(e->GetGRFID());
914 if (_settings_client.gui.show_newgrf_name && config != nullptr)
915 {
916 DrawString(left, right, y, config->GetName(), TC_BLACK);
918 }
919
920 return y;
921}
922
923static void DrawEngineBadgeColumn(const Rect &r, int column_group, const GUIBadgeClasses &badge_classes, const Engine *e, PaletteID remap)
924{
925 DrawBadgeColumn(r, column_group, badge_classes, e->badges, static_cast<GrfSpecFeature>(GSF_TRAINS + e->type), e->info.base_intro, remap);
926}
927
938void 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)
939{
940 static const std::array<int8_t, VehicleType::VEH_COMPANY_END> sprite_y_offsets = { 0, 0, -1, -1 };
941
942 auto [first, last] = sb.GetVisibleRangeIterators(eng_list);
943
944 bool rtl = _current_text_dir == TD_RTL;
945 int step_size = GetEngineListHeight(type);
946 int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
947 int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
948 int sprite_width = sprite_left + sprite_right;
949 int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
950 int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
951
952 auto badge_column_widths = badge_classes.GetColumnWidths();
953
954 Rect ir = r.WithHeight(step_size).Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
955 int sprite_y_offset = ScaleSpriteTrad(sprite_y_offsets[type]) + ir.Height() / 2;
956
957 Dimension replace_icon = {0, 0};
958 int count_width = 0;
959 if (show_count) {
960 replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
961
962 uint biggest_num_engines = 0;
963 for (auto it = first; it != last; ++it) {
964 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, it->engine_id);
965 biggest_num_engines = std::max(biggest_num_engines, num_engines);
966 }
967
968 count_width = GetStringBoundingBox(GetString(STR_JUST_COMMA, biggest_num_engines), FS_SMALL).width;
969 }
970
971 const int text_row_height = ir.Shrink(WidgetDimensions::scaled.matrix).Height();
972 const int normal_text_y_offset = (text_row_height - GetCharacterHeight(FS_NORMAL)) / 2;
973 const int small_text_y_offset = text_row_height - GetCharacterHeight(FS_SMALL);
974
975 const int offset = (rtl ? -circle_width : circle_width) / 2;
977
978 for (auto it = first; it != last; ++it) {
979 const auto &item = *it;
980 const Engine *e = Engine::Get(item.engine_id);
981
982 uint indent = item.indent * WidgetDimensions::scaled.hsep_indent;
983 bool has_variants = item.flags.Test(EngineDisplayFlag::HasVariants);
984 bool is_folded = item.flags.Test(EngineDisplayFlag::IsFolded);
985 bool shaded = item.flags.Test(EngineDisplayFlag::Shaded);
986
987 Rect textr = ir.Shrink(WidgetDimensions::scaled.matrix);
988 Rect tr = ir.Indent(indent, rtl);
989
990 if (item.indent > 0) {
991 /* Draw tree continuation lines. */
992 int tx = (rtl ? ir.right : ir.left) + offset;
993 for (uint lvl = 1; lvl <= item.indent; ++lvl) {
994 if (HasBit(item.level_mask, lvl)) GfxDrawLine(tx, ir.top, tx, ir.bottom, linecolour, WidgetDimensions::scaled.fullbevel.top);
995 if (lvl < item.indent) tx += level_width;
996 }
997 /* Draw our node in the tree. */
998 int ycentre = CenterBounds(textr.top, textr.bottom, WidgetDimensions::scaled.fullbevel.top);
999 if (!HasBit(item.level_mask, item.indent)) GfxDrawLine(tx, ir.top, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
1000 GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
1001 }
1002
1003 if (has_variants) {
1004 Rect fr = tr.WithWidth(circle_width, rtl);
1005 DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, {fr.left, textr.top, fr.right, textr.bottom}, SA_CENTER);
1006 }
1007
1008 tr = tr.Indent(circle_width + WidgetDimensions::scaled.hsep_normal, rtl);
1009
1010 /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
1011 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
1012 const PaletteID pal = (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(item.engine_id, _local_company);
1013
1014 if (badge_column_widths.size() >= 1 && badge_column_widths[0] > 0) {
1015 Rect br = tr.WithWidth(badge_column_widths[0], rtl);
1016 DrawEngineBadgeColumn(br, 0, badge_classes, e, pal);
1017 tr = tr.Indent(badge_column_widths[0], rtl);
1018 }
1019
1020 int sprite_x = tr.WithWidth(sprite_width, rtl).left + sprite_left;
1021 DrawVehicleEngine(r.left, r.right, sprite_x, tr.top + sprite_y_offset, item.engine_id, pal, EIT_PURCHASE);
1022
1023 tr = tr.Indent(sprite_width + WidgetDimensions::scaled.hsep_wide, rtl);
1024
1025 if (badge_column_widths.size() >= 2 && badge_column_widths[1] > 0) {
1026 Rect br = tr.WithWidth(badge_column_widths[1], rtl);
1027 DrawEngineBadgeColumn(br, 1, badge_classes, e, pal);
1028 tr = tr.Indent(badge_column_widths[1], rtl);
1029 }
1030
1031 if (show_count) {
1032 /* Rect for replace-protection icon. */
1033 Rect rr = tr.WithWidth(replace_icon.width, !rtl);
1034 tr = tr.Indent(replace_icon.width + WidgetDimensions::scaled.hsep_normal, !rtl);
1035 /* Rect for engine type count text. */
1036 Rect cr = tr.WithWidth(count_width, !rtl);
1037 tr = tr.Indent(count_width + WidgetDimensions::scaled.hsep_normal, !rtl);
1038
1039 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);
1040
1041 if (EngineHasReplacementForCompany(Company::Get(_local_company), item.engine_id, selected_group)) {
1042 DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr, SA_CENTER);
1043 }
1044 }
1045
1046 if (badge_column_widths.size() >= 3 && badge_column_widths[2] > 0) {
1047 Rect br = tr.WithWidth(badge_column_widths[2], !rtl).Indent(WidgetDimensions::scaled.hsep_wide, rtl);
1048 DrawEngineBadgeColumn(br, 2, badge_classes, e, pal);
1049 tr = tr.Indent(badge_column_widths[2], !rtl);
1050 }
1051
1052 bool hidden = e->company_hidden.Test(_local_company);
1053 StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
1054 TextColour tc = (item.engine_id == selected_id) ? TC_WHITE : ((hidden | shaded) ? (TC_GREY | TC_FORCED | TC_NO_SHADE) : TC_BLACK);
1055
1056 /* If the count is visible then this is part of in-use autoreplace list. */
1057 auto engine_name = PackEngineNameDParam(item.engine_id, show_count ? EngineNameContext::AutoreplaceVehicleInUse : EngineNameContext::PurchaseList, item.indent);
1058 DrawString(tr.left, tr.right, textr.top + normal_text_y_offset,GetString(str, engine_name), tc);
1059
1060 ir = ir.Translate(0, step_size);
1061 }
1062}
1063
1071void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button)
1072{
1073 uint32_t hidden_mask = 0;
1074 /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
1075 if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
1076 SetBit(hidden_mask, 3); // power
1077 SetBit(hidden_mask, 4); // tractive effort
1078 SetBit(hidden_mask, 8); // power by running costs
1079 }
1080 /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
1081 if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
1082 SetBit(hidden_mask, 4); // tractive effort
1083 }
1084 ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
1085}
1086
1094void GUIEngineListAddChildren(GUIEngineList &dst, const GUIEngineList &src, EngineID parent, uint8_t indent)
1095{
1096 for (const auto &item : src) {
1097 if (item.variant_id != parent || item.engine_id == parent) continue;
1098
1099 const Engine *e = Engine::Get(item.engine_id);
1100 EngineDisplayFlags flags = item.flags;
1101 if (e->display_last_variant != EngineID::Invalid()) flags.Reset(EngineDisplayFlag::Shaded);
1102 dst.emplace_back(e->display_last_variant == EngineID::Invalid() ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent);
1103
1104 /* Add variants if not folded */
1105 if (item.flags.Test(EngineDisplayFlag::HasVariants) && !item.flags.Test(EngineDisplayFlag::IsFolded)) {
1106 /* Add this engine again as a child */
1107 if (!item.flags.Test(EngineDisplayFlag::Shaded)) {
1108 dst.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags{}, indent + 1);
1109 }
1110 GUIEngineListAddChildren(dst, src, item.engine_id, indent + 1);
1111 }
1112 }
1113
1114 if (indent > 0 || dst.empty()) return;
1115
1116 /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
1117 uint16_t level_mask = 0;
1118 for (auto it = std::rbegin(dst); std::next(it) != std::rend(dst); ++it) {
1119 auto next_it = std::next(it);
1120 SB(level_mask, it->indent, 1, it->indent <= next_it->indent);
1121 next_it->level_mask = level_mask;
1122 }
1123}
1124
1129
1133 union {
1139 bool show_hidden_engines = false;
1140 bool listview_mode = false;
1141 EngineID sel_engine = EngineID::Invalid();
1142 EngineID rename_engine = EngineID::Invalid();
1143 GUIEngineList eng_list{};
1146 Scrollbar *vscroll = nullptr;
1148 GUIBadgeClasses badge_classes{};
1149
1152
1153 void SetBuyVehicleText()
1154 {
1156
1158 if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter_criteria;
1159
1160 if (refit) {
1162 } else {
1164 }
1165 }
1166
1168 {
1169 this->vehicle_type = type;
1170 this->listview_mode = tile == INVALID_TILE;
1171 this->window_number = this->listview_mode ? (int)type : tile.base();
1172
1173 this->sort_criteria = _engine_sort_last_criteria[type];
1174 this->descending_sort_order = _engine_sort_last_order[type];
1175 this->show_hidden_engines = _engine_sort_show_hidden_engines[type];
1176
1177 this->UpdateFilterByTile();
1178
1179 this->CreateNestedTree();
1180
1181 this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR);
1182
1183 /* If we are just viewing the list of vehicles, we do not need the Build button.
1184 * So we just hide it, and enlarge the Rename button by the now vacant place. */
1185 if (this->listview_mode) this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
1186
1189
1192
1193 widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
1195
1198 widget->SetLowered(this->show_hidden_engines);
1199
1200 this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9);
1201
1202 if (tile == INVALID_TILE) {
1203 this->FinishInitNested(type);
1204 } else {
1205 this->FinishInitNested(tile);
1206 }
1207
1209 this->vehicle_editbox.cancel_button = QueryString::ACTION_CLEAR;
1210
1211 this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
1212
1213 this->eng_list.ForceRebuild();
1214 this->GenerateBuildList(); // generate the list, since we need it in the next line
1215
1216 /* Select the first unshaded engine in the list as default when opening the window */
1217 EngineID engine = EngineID::Invalid();
1218 auto it = std::ranges::find_if(this->eng_list, [](const GUIEngineListItem &item) { return !item.flags.Test(EngineDisplayFlag::Shaded); });
1219 if (it != this->eng_list.end()) engine = it->engine_id;
1220 this->SelectEngine(engine);
1221 }
1222
1225 {
1226 switch (this->vehicle_type) {
1227 default: NOT_REACHED();
1228 case VEH_TRAIN:
1229 if (this->listview_mode) {
1230 this->filter.railtype = INVALID_RAILTYPE;
1231 } else {
1232 this->filter.railtype = GetRailType(this->window_number);
1233 }
1234 break;
1235
1236 case VEH_ROAD:
1237 if (this->listview_mode) {
1238 this->filter.roadtype = INVALID_ROADTYPE;
1239 } else {
1240 this->filter.roadtype = GetRoadTypeRoad(this->window_number);
1241 if (this->filter.roadtype == INVALID_ROADTYPE) {
1242 this->filter.roadtype = GetRoadTypeTram(this->window_number);
1243 }
1244 }
1245 break;
1246
1247 case VEH_SHIP:
1248 case VEH_AIRCRAFT:
1249 break;
1250 }
1251 }
1252
1253 StringID GetCargoFilterLabel(CargoType cargo_type) const
1254 {
1255 switch (cargo_type) {
1259 default: return CargoSpec::Get(cargo_type)->name;
1260 }
1261 }
1262
1265 {
1266 /* Set the last cargo filter criteria. */
1269
1270 this->eng_list.SetFilterFuncs(_engine_filter_funcs);
1272 }
1273
1274 void SelectEngine(EngineID engine)
1275 {
1276 CargoType cargo = this->cargo_filter_criteria;
1277 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1278
1279 this->sel_engine = engine;
1280 this->SetBuyVehicleText();
1281
1282 if (this->sel_engine == EngineID::Invalid()) return;
1283
1284 const Engine *e = Engine::Get(this->sel_engine);
1285
1286 if (!this->listview_mode) {
1287 /* Query for cost and refitted capacity */
1289 if (ret.Succeeded()) {
1290 this->te.cost = ret.GetCost() - e->GetCost();
1291 this->te.capacity = refit_capacity;
1292 this->te.mail_capacity = refit_mail;
1293 this->te.cargo = !IsValidCargoType(cargo) ? e->GetDefaultCargoType() : cargo;
1295 return;
1296 }
1297 }
1298
1299 /* Purchase test was not possible or failed, fill in the defaults instead. */
1300 this->te.cost = 0;
1301 this->te.FillDefaultCapacities(e);
1302 }
1303
1304 void OnInit() override
1305 {
1306 this->badge_classes = GUIBadgeClasses(static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
1307 this->SetCargoFilterArray();
1308 }
1309
1312 {
1313 this->eng_list.Filter(this->cargo_filter_criteria);
1314 if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
1315 this->SelectEngine(EngineID::Invalid());
1316 } 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
1317 this->SelectEngine(this->eng_list[0].engine_id);
1318 }
1319 }
1320
1323 {
1325 return CargoAndEngineFilter(&item, this->cargo_filter_criteria);
1326 }
1327
1329 bool FilterByText(const Engine *e)
1330 {
1331 /* Do not filter if the filter text box is empty */
1332 if (this->string_filter.IsEmpty()) return true;
1333
1334 /* Filter engine name */
1335 this->string_filter.ResetState();
1337
1338 /* Filter NewGRF extra text */
1339 auto text = GetNewGRFAdditionalText(e->index);
1340 if (text) this->string_filter.AddLine(*text);
1341
1342 return this->string_filter.GetState();
1343 }
1344
1345 /* Figure out what train EngineIDs to put in the list */
1346 void GenerateBuildTrainList(GUIEngineList &list)
1347 {
1348 std::vector<EngineID> variants;
1349 EngineID sel_id = EngineID::Invalid();
1350 size_t num_engines = 0;
1351
1352 list.clear();
1353
1354 BadgeTextFilter btf(this->string_filter, GSF_TRAINS);
1355
1356 /* Make list of all available train engines and wagons.
1357 * Also check to see if the previously selected engine is still available,
1358 * and if not, reset selection to EngineID::Invalid(). This could be the case
1359 * when engines become obsolete and are removed */
1360 for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
1361 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1362 EngineID eid = e->index;
1363 const RailVehicleInfo *rvi = &e->u.rail;
1364
1365 if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
1367
1368 /* Filter now! So num_engines and num_wagons is valid */
1369 if (!FilterSingleEngine(eid)) continue;
1370
1371 /* Filter by name or NewGRF extra text */
1372 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1373
1374 list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1375
1376 if (rvi->railveh_type != RAILVEH_WAGON) num_engines++;
1377
1378 /* Add all parent variants of this engine to the variant list */
1379 EngineID parent = e->info.variant_id;
1380 while (parent != EngineID::Invalid()) {
1381 variants.push_back(parent);
1382 parent = Engine::Get(parent)->info.variant_id;
1383 }
1384
1385 if (eid == this->sel_engine) sel_id = eid;
1386 }
1387
1388 /* ensure primary engine of variant group is in list */
1389 for (const auto &variant : variants) {
1390 if (std::ranges::find(list, variant, &GUIEngineListItem::engine_id) == list.end()) {
1391 const Engine *e = Engine::Get(variant);
1392 list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1393 if (e->u.rail.railveh_type != RAILVEH_WAGON) num_engines++;
1394 }
1395 }
1396
1397 this->SelectEngine(sel_id);
1398
1399 /* invalidate cached values for name sorter - engine names could change */
1400 _last_engine[0] = _last_engine[1] = EngineID::Invalid();
1401
1402 /* make engines first, and then wagons, sorted by selected sort_criteria */
1403 _engine_sort_direction = false;
1405
1406 /* and then sort engines */
1408 EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
1409
1410 /* and finally sort wagons */
1411 EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], num_engines, list.size() - num_engines);
1412 }
1413
1414 /* Figure out what road vehicle EngineIDs to put in the list */
1415 void GenerateBuildRoadVehList()
1416 {
1417 EngineID sel_id = EngineID::Invalid();
1418
1419 this->eng_list.clear();
1420
1421 BadgeTextFilter btf(this->string_filter, GSF_ROADVEHICLES);
1422
1423 for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
1424 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1425 EngineID eid = e->index;
1426 if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
1427 if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
1428
1429 /* Filter by name or NewGRF extra text */
1430 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1431
1432 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1433
1434 if (eid == this->sel_engine) sel_id = eid;
1435 }
1436 this->SelectEngine(sel_id);
1437 }
1438
1439 /* Figure out what ship EngineIDs to put in the list */
1440 void GenerateBuildShipList()
1441 {
1442 EngineID sel_id = EngineID::Invalid();
1443 this->eng_list.clear();
1444
1445 BadgeTextFilter btf(this->string_filter, GSF_SHIPS);
1446
1447 for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
1448 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1449 EngineID eid = e->index;
1450 if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
1451
1452 /* Filter by name or NewGRF extra text */
1453 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1454
1455 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1456
1457 if (eid == this->sel_engine) sel_id = eid;
1458 }
1459 this->SelectEngine(sel_id);
1460 }
1461
1462 /* Figure out what aircraft EngineIDs to put in the list */
1463 void GenerateBuildAircraftList()
1464 {
1465 EngineID sel_id = EngineID::Invalid();
1466
1467 this->eng_list.clear();
1468
1469 const Station *st = this->listview_mode ? nullptr : Station::GetByTile(TileIndex(this->window_number));
1470
1471 BadgeTextFilter btf(this->string_filter, GSF_AIRCRAFT);
1472
1473 /* Make list of all available planes.
1474 * Also check to see if the previously selected plane is still available,
1475 * and if not, reset selection to EngineID::Invalid(). This could be the case
1476 * when planes become obsolete and are removed */
1477 for (const Engine *e : Engine::IterateType(VEH_AIRCRAFT)) {
1478 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1479 EngineID eid = e->index;
1481 /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
1482 if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
1483
1484 /* Filter by name or NewGRF extra text */
1485 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1486
1487 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1488
1489 if (eid == this->sel_engine) sel_id = eid;
1490 }
1491
1492 this->SelectEngine(sel_id);
1493 }
1494
1495 /* Generate the list of vehicles */
1496 void GenerateBuildList()
1497 {
1498 if (!this->eng_list.NeedRebuild()) return;
1499
1500 /* Update filter type in case the road/railtype of the depot got converted */
1501 this->UpdateFilterByTile();
1502
1503 this->eng_list.clear();
1504
1505 GUIEngineList list;
1506
1507 switch (this->vehicle_type) {
1508 default: NOT_REACHED();
1509 case VEH_TRAIN:
1510 this->GenerateBuildTrainList(list);
1511 GUIEngineListAddChildren(this->eng_list, list);
1512 this->eng_list.RebuildDone();
1513 return;
1514 case VEH_ROAD:
1515 this->GenerateBuildRoadVehList();
1516 break;
1517 case VEH_SHIP:
1518 this->GenerateBuildShipList();
1519 break;
1520 case VEH_AIRCRAFT:
1521 this->GenerateBuildAircraftList();
1522 break;
1523 }
1524
1525 this->FilterEngineList();
1526
1527 /* ensure primary engine of variant group is in list after filtering */
1528 std::vector<EngineID> variants;
1529 for (const auto &item : this->eng_list) {
1530 EngineID parent = item.variant_id;
1531 while (parent != EngineID::Invalid()) {
1532 variants.push_back(parent);
1533 parent = Engine::Get(parent)->info.variant_id;
1534 }
1535 }
1536
1537 for (const auto &variant : variants) {
1538 if (std::ranges::find(this->eng_list, variant, &GUIEngineListItem::engine_id) == this->eng_list.end()) {
1539 const Engine *e = Engine::Get(variant);
1540 this->eng_list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1541 }
1542 }
1543
1545 EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
1546
1547 this->eng_list.swap(list);
1548 GUIEngineListAddChildren(this->eng_list, list, EngineID::Invalid(), 0);
1549 this->eng_list.RebuildDone();
1550 }
1551
1552 DropDownList BuildCargoDropDownList() const
1553 {
1554 DropDownList list;
1555
1556 /* Add item for disabling filtering. */
1557 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY));
1558 /* Specific filters for trains. */
1559 if (this->vehicle_type == VEH_TRAIN) {
1560 /* Add item for locomotives only in case of trains. */
1561 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ENGINES), CargoFilterCriteria::CF_ENGINES));
1562 /* Add item for vehicles not carrying anything, e.g. train engines.
1563 * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
1564 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE));
1565 }
1566
1567 /* Add cargos */
1569 for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
1570 list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index()));
1571 }
1572
1573 return list;
1574 }
1575
1576 void BuildVehicle()
1577 {
1578 EngineID sel_eng = this->sel_engine;
1579 if (sel_eng == EngineID::Invalid()) return;
1580
1581 CargoType cargo = this->cargo_filter_criteria;
1582 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1583 if (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) {
1584 Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1585 } else {
1586 Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1587 }
1588
1589 /* Update last used variant in hierarchy and refresh if necessary. */
1590 bool refresh = false;
1592 while (parent != EngineID::Invalid()) {
1594 refresh |= (e->display_last_variant != sel_eng);
1595 e->display_last_variant = sel_eng;
1596 parent = e->info.variant_id;
1597 }
1598
1599 if (refresh) {
1600 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1601 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1602 }
1603 }
1604
1605 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1606 {
1607 switch (widget) {
1609 this->descending_sort_order ^= true;
1611 this->eng_list.ForceRebuild();
1612 this->SetDirty();
1613 break;
1614
1616 this->show_hidden_engines ^= true;
1618 this->eng_list.ForceRebuild();
1619 this->SetWidgetLoweredState(widget, this->show_hidden_engines);
1620 this->SetDirty();
1621 break;
1622
1623 case WID_BV_LIST: {
1624 EngineID e = EngineID::Invalid();
1625 const auto it = this->vscroll->GetScrolledItemFromWidget(this->eng_list, pt.y, this, WID_BV_LIST);
1626 if (it != this->eng_list.end()) {
1627 const auto &item = *it;
1628 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);
1629 if (item.flags.Test(EngineDisplayFlag::HasVariants) && IsInsideMM(r.left, r.right, pt.x)) {
1630 /* toggle folded flag on engine */
1631 assert(item.variant_id != EngineID::Invalid());
1632 Engine *engine = Engine::Get(item.variant_id);
1634
1635 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1636 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1637 return;
1638 }
1639 if (!item.flags.Test(EngineDisplayFlag::Shaded)) e = item.engine_id;
1640 }
1641 this->SelectEngine(e);
1642 this->SetDirty();
1643 if (_ctrl_pressed) {
1644 this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
1645 } else if (click_count > 1 && !this->listview_mode) {
1646 this->OnClick(pt, WID_BV_BUILD, 1);
1647 }
1648 break;
1649 }
1650
1651 case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
1652 DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
1653 break;
1654
1655 case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
1656 ShowDropDownList(this, this->BuildCargoDropDownList(), this->cargo_filter_criteria, widget);
1657 break;
1658
1659 case WID_BV_SHOW_HIDE: {
1660 const Engine *e = (this->sel_engine == EngineID::Invalid()) ? nullptr : Engine::Get(this->sel_engine);
1661 if (e != nullptr) {
1662 Command<CMD_SET_VEHICLE_VISIBILITY>::Post(this->sel_engine, !e->IsHidden(_current_company));
1663 }
1664 break;
1665 }
1666
1667 case WID_BV_BUILD:
1668 this->BuildVehicle();
1669 break;
1670
1671 case WID_BV_RENAME: {
1672 EngineID sel_eng = this->sel_engine;
1673 if (sel_eng != EngineID::Invalid()) {
1674 this->rename_engine = sel_eng;
1676 }
1677 break;
1678 }
1679 }
1680 }
1681
1687 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1688 {
1689 if (!gui_scope) return;
1690 /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
1691 if (this->vehicle_type == VEH_ROAD &&
1693 this->sort_criteria > 7) {
1694 this->sort_criteria = 0;
1696 }
1697 this->eng_list.ForceRebuild();
1698 }
1699
1700 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1701 {
1702 switch (widget) {
1703 case WID_BV_CAPTION:
1704 if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) {
1705 const RailTypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
1706 return GetString(rti->strings.build_caption);
1707 }
1708 if (this->vehicle_type == VEH_ROAD && !this->listview_mode) {
1709 const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype);
1710 return GetString(rti->strings.build_caption);
1711 }
1712 return GetString((this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type);
1713
1715 return GetString(std::data(_engine_sort_listing[this->vehicle_type])[this->sort_criteria]);
1716
1718 return GetString(this->GetCargoFilterLabel(this->cargo_filter_criteria));
1719
1720 case WID_BV_SHOW_HIDE: {
1721 const Engine *e = (this->sel_engine == EngineID::Invalid()) ? nullptr : Engine::Get(this->sel_engine);
1722 if (e != nullptr && e->IsHidden(_local_company)) {
1723 return GetString(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type);
1724 }
1725 return GetString(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1726 }
1727
1728 default:
1729 return this->Window::GetWidgetString(widget, stringid);
1730 }
1731 }
1732
1734 {
1735 switch (widget) {
1736 case WID_BV_LIST:
1737 resize.height = GetEngineListHeight(this->vehicle_type);
1738 size.height = 3 * resize.height;
1739 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;
1740 break;
1741
1742 case WID_BV_PANEL:
1743 size.height = GetCharacterHeight(FS_NORMAL) * this->details_height + padding.height;
1744 break;
1745
1748 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
1749 d.height += padding.height;
1750 size = maxdim(size, d);
1751 break;
1752 }
1753
1755 size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList()).width + padding.width);
1756 break;
1757
1758 case WID_BV_BUILD:
1761 size.width += padding.width;
1762 size.height += padding.height;
1763 break;
1764
1765 case WID_BV_SHOW_HIDE:
1767 size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
1768 size.width += padding.width;
1769 size.height += padding.height;
1770 break;
1771 }
1772 }
1773
1774 void DrawWidget(const Rect &r, WidgetID widget) const override
1775 {
1776 switch (widget) {
1777 case WID_BV_LIST:
1779 this->vehicle_type,
1780 r,
1781 this->eng_list,
1782 *this->vscroll,
1783 this->sel_engine,
1784 false,
1786 this->badge_classes
1787 );
1788 break;
1789
1791 this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
1792 break;
1793 }
1794 }
1795
1796 void OnPaint() override
1797 {
1798 this->GenerateBuildList();
1799 this->vscroll->SetCount(this->eng_list.size());
1800
1801 this->SetWidgetsDisabledState(this->sel_engine == EngineID::Invalid(), WID_BV_SHOW_HIDE, WID_BV_BUILD);
1802
1803 /* Disable renaming engines in network games if you are not the server. */
1804 this->SetWidgetDisabledState(WID_BV_RENAME, this->sel_engine == EngineID::Invalid() || (_networking && !_network_server));
1805
1806 this->DrawWidgets();
1807
1808 if (!this->IsShaded()) {
1809 int needed_height = this->details_height;
1810 /* Draw details panels. */
1811 if (this->sel_engine != EngineID::Invalid()) {
1812 const Rect r = this->GetWidget<NWidgetBase>(WID_BV_PANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1813 int text_end = DrawVehiclePurchaseInfo(r.left, r.right, r.top, this->sel_engine, this->te);
1815 }
1816 if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
1817 int resize = needed_height - this->details_height;
1818 this->details_height = needed_height;
1819 this->ReInit(0, resize * GetCharacterHeight(FS_NORMAL));
1820 return;
1821 }
1822 }
1823 }
1824
1825 void OnQueryTextFinished(std::optional<std::string> str) override
1826 {
1827 if (!str.has_value()) return;
1828
1829 Command<CMD_RENAME_ENGINE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, this->rename_engine, *str);
1830 }
1831
1832 void OnDropdownSelect(WidgetID widget, int index) override
1833 {
1834 switch (widget) {
1836 if (this->sort_criteria != index) {
1837 this->sort_criteria = index;
1839 this->eng_list.ForceRebuild();
1840 }
1841 break;
1842
1843 case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
1844 if (this->cargo_filter_criteria != index) {
1845 this->cargo_filter_criteria = index;
1847 /* deactivate filter if criteria is 'Show All', activate it otherwise */
1849 this->eng_list.ForceRebuild();
1850 this->SelectEngine(this->sel_engine);
1851 }
1852 break;
1853 }
1854 this->SetDirty();
1855 }
1856
1857 void OnResize() override
1858 {
1859 this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
1860 }
1861
1863 {
1864 if (wid == WID_BV_FILTER) {
1865 this->string_filter.SetFilterTerm(this->vehicle_editbox.text.GetText());
1866 this->InvalidateData();
1867 }
1868 }
1869
1871 {
1872 switch (hotkey) {
1875 SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
1876 return ES_HANDLED;
1877
1878 default:
1879 return ES_NOT_HANDLED;
1880 }
1881
1882 return ES_HANDLED;
1883 }
1884
1885 static inline HotkeyList hotkeys{"buildvehicle", {
1886 Hotkey('F', "focus_filter_box", BVHK_FOCUS_FILTER_BOX),
1887 }};
1888};
1889
1890static WindowDesc _build_vehicle_desc(
1891 WDP_AUTO, "build_vehicle", 240, 268,
1894 _nested_build_vehicle_widgets,
1895 &BuildVehicleWindow::hotkeys
1896);
1897
1898void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
1899{
1900 /* We want to be able to open both Available Train as Available Ships,
1901 * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number.
1902 * As it always is a low value, it won't collide with any real tile
1903 * number. */
1904 uint num = (tile == INVALID_TILE) ? (int)type : tile.base();
1905
1906 assert(IsCompanyBuildableVehicleType(type));
1907
1909
1910 new BuildVehicleWindow(_build_vehicle_desc, tile, type);
1911}
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.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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.
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.
BuildVehicleHotkeys
Enum referring to the Hotkeys in the build vehicle window.
@ BVHK_FOCUS_FILTER_BOX
Focus the edit box for editing the filter string.
static bool TrainEnginesThenWagonsSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
Determines order of train engines by engine / wagon.
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)
Engine drawing loop.
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.
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_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:23
bool IsValidCargoType(CargoType t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
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:38
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 & Flip(Tvalue_type value)
Flip the value-th bit.
constexpr Timpl & Reset(Tvalue_type value)
Reset the value-th bit.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetFilterState(bool state)
Enable or disable the filter.
bool(const GUIEngineListItem *, CargoType) FilterFunction
Signature of filter function.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
Base class for a 'real' widget.
void SetToolTip(StringID tool_tip)
Set the tool tip of the nested widget.
Definition widget.cpp:1198
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:1138
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:118
struct RailTypeInfo::@24 strings
Strings associated with the rail type.
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition rail.h:170
uint8_t acceleration_type
Acceleration type of this rail type.
Definition rail.h:217
struct RoadTypeInfo::@27 strings
Strings associated with the rail type.
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition road.h:97
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:2521
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)
Calculate the year of a given date.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:29
RectPadding fullbevel
Always-scaled bevel thickness.
Definition window_gui.h:39
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
int hsep_indent
Width of indentation for tree layouts.
Definition window_gui.h:63
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:441
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition dropdown.cpp:404
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
Definition dropdown.cpp:363
Functions related to the drop down widget.
Types related to the drop down widget.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1255
Base class for engines.
@ HasVariants
Set if engine has variants.
@ IsFolded
Set if display of variants should be folded (hidden).
@ Shaded
Set if engine should be masked.
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'.
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 dparam.
@ 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.
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:33
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:32
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:923
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:852
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:658
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
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:775
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:67
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition gfx_func.h:166
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:244
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:377
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:387
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:385
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:294
@ TC_FORCED
Ignore colour changes from strings.
Definition gfx_type.h:319
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:318
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 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 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 NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
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 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:943
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
Hotkey related functions.
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.
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:96
static constexpr CargoType CF_ENGINES
Show only engines (for rail vehicles only)
Definition cargo_type.h:97
static constexpr CargoType CF_ANY
Show all items independent of carried cargo (i.e. no filtering)
Definition cargo_type.h:95
bool _networking
are we in networking mode?
Definition network.cpp:65
bool _network_server
network-server is active
Definition network.cpp:66
Basic functions/variables used all over the place.
@ INVALID_CLIENT_ID
Client is not part of anything.
GrfSpecFeature
Definition newgrf.h:68
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 &badge_classes, std::span< const BadgeID > badges, GrfSpecFeature feature, std::optional< TimerGameCalendar::Date > introduction_date, PaletteID remap)
Draw a badge column group.
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)
Evaluate a newgrf callback for vehicles.
Functions for NewGRF engines.
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, uint8_t num_entries)
Format a GRF string using the text ref stack for parameters.
Header of Action 04 "universal holder" structure and functions.
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:387
Base for the GUIs that have an edit box in them.
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:328
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:27
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:34
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:235
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:220
RoadType
The different roadtypes we support.
Definition road_type.h:25
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:30
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:58
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1609
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:607
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 GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:426
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.
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
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.
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.
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.
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.
EventState OnHotkey(int hotkey) override
A hotkey has been pressed.
union BuildVehicleWindow::@0 filter
Filter to apply.
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::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:113
uint GetCount() const
Get the amount of cargos that have an amount.
Definition cargo_type.h:128
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:137
StringID name
Name of this type of cargo.
Definition cargotype.h:91
GUISettings gui
settings related to the GUI
Dimensions (a width and height) of a rectangle in 2D.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
StringID GetAircraftTypeText() const
Get the name of the aircraft type for display purposes.
Definition engine.cpp:467
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition engine.cpp:390
uint16_t GetRange() const
Get the range of an aircraft type.
Definition engine.cpp:453
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:157
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:318
TimerGameCalendar::Date intro_date
Date of introduction of the engine.
Definition engine_base.h:45
uint GetDisplayMaxSpeed() const
Returns max speed of the engine for display purposes.
Definition engine.cpp:358
EngineDisplayFlags display_flags
NOSAVE client-side-only display flags for build engine list.
Definition engine_base.h:63
uint GetDisplayWeight() const
Returns the weight of the engine for display purposes.
Definition engine.cpp:408
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:61
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:443
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.
CompanyMask company_hidden
Bit for each company whether the engine is normally hidden in the build gui for that company.
Definition engine_base.h:40
Money GetRunningCost() const
Return how much the running costs of this engine are.
Definition engine.cpp:281
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:48
uint GetDisplayMaxTractiveEffort() const
Returns the tractive effort of the engine for display purposes.
Definition engine.cpp:426
EngineID display_last_variant
NOSAVE client-side-only last variant selected.
Definition engine_base.h:64
Information about GRF, used in the game and (part of it) in savegames.
const char * GetName() const
Get the name of this grf.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:111
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
bool show_newgrf_name
Show the name of the NewGRF in the build vehicle window.
VehicleSettings vehicle
options for vehicles
List of hotkeys for a window.
Definition hotkeys.h:37
All data for a single hotkey.
Definition hotkeys.h:21
Partial widget specification to allow NWidgets to be written nested.
Coordinates of a point in 2D.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
Data stored about a string that can be modified in the GUI.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
Information about a rail vehicle.
Definition engine_type.h:46
uint16_t pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition engine_type.h:60
RailType railtype
Railtype, mangled if elrail is disabled.
Definition engine_type.h:50
uint8_t pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition engine_type.h:61
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 Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
RoadType roadtype
Road type.
uint ApplyWaterClassSpeedFrac(uint raw_speed, bool is_ocean) const
Apply ocean/canal speed fraction to a velocity.
Definition engine_type.h:85
Station data structure.
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.
void AddLine(const char *str)
Pass another text line from the current item to the filter.
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
const char * GetText() const
Get the current text.
Definition textbuf.cpp:286
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
uint8_t roadveh_acceleration_model
realistic acceleration for road vehicles
uint8_t train_acceleration_model
realistic acceleration for trains
bool wagon_speed_limits
enable wagon speed limits
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:955
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:793
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1736
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:744
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3164
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:502
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:776
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:1726
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:483
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:558
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:973
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:311
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
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)
@ LengthIsInChars
the length of the string is counted in characters
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
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:87
Definition of the game-calendar-timer.
Command definitions related to trains.
void CcBuildWagon(Commands cmd, 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:2133
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3047
Command definitions for vehicles.
void CcBuildPrimaryVehicle(Commands cmd, 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_EDITBOX
a textbox for typing
Definition widget_type.h:61
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:65
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:45
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:49
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:54
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:51
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:75
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:67
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:59
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:58
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:55
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:60
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:70
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
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:1143
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition window.cpp:419
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:3224
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:3241
Window functions not directly related to making/drawing windows.
@ Construction
This window is used for construction; close it whenever changing company.
@ 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:145
int WidgetID
Widget ID.
Definition window_type.h:20
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ WC_REPLACE_VEHICLE
Replace vehicle window; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers:
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition zoom_func.h:107