OpenTTD Source 20250205-master-gfd85ab1e2c
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_engine.h"
21#include "newgrf_text.h"
22#include "group.h"
23#include "string_func.h"
24#include "strings_func.h"
25#include "window_func.h"
27#include "vehicle_func.h"
28#include "dropdown_type.h"
29#include "dropdown_func.h"
30#include "engine_gui.h"
31#include "cargotype.h"
33#include "autoreplace_func.h"
34#include "engine_cmd.h"
35#include "train_cmd.h"
36#include "vehicle_cmd.h"
37#include "zoom_func.h"
38#include "querystring_gui.h"
39#include "stringfilter_type.h"
40#include "hotkeys.h"
41
43
44#include "table/strings.h"
45
46#include "safeguards.h"
47
54{
55 return std::max<uint>(GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.matrix.Vertical(), GetVehicleImageCellSize(type, EIT_PURCHASE).height);
56}
57
58static constexpr NWidgetPart _nested_build_vehicle_widgets[] = {
60 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
61 NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetStringTip(STR_JUST_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), SetTextStyle(TC_WHITE),
62 NWidget(WWT_SHADEBOX, COLOUR_GREY),
63 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
64 NWidget(WWT_STICKYBOX, COLOUR_GREY),
68 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASCENDING_DESCENDING), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
69 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA),
73 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
75 NWidget(WWT_PANEL, COLOUR_GREY),
76 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),
79 /* Vehicle list. */
84 /* Panel with details. */
85 NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(),
86 /* Build/rename buttons, resize button. */
88 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL),
89 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0),
91 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_JUST_STRING),
92 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0),
93 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
95};
96
97
99uint8_t _engine_sort_last_criteria[] = {0, 0, 0, 0};
100bool _engine_sort_last_order[] = {false, false, false, false};
101bool _engine_sort_show_hidden_engines[] = {false, false, false, false};
103
111{
112 int r = Engine::Get(a.engine_id)->list_position - Engine::Get(b.engine_id)->list_position;
113
114 return _engine_sort_direction ? r > 0 : r < 0;
115}
116
124{
125 const auto va = Engine::Get(a.engine_id)->intro_date;
126 const auto vb = Engine::Get(b.engine_id)->intro_date;
127 const auto r = va - vb;
128
129 /* Use EngineID to sort instead since we want consistent sorting */
130 if (r == 0) return EngineNumberSorter(a, b);
131 return _engine_sort_direction ? r > 0 : r < 0;
132}
133
134/* cached values for EngineNameSorter to spare many GetString() calls */
135static EngineID _last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
136
144{
145 static std::string last_name[2] = { {}, {} };
146
147 if (a.engine_id != _last_engine[0]) {
148 _last_engine[0] = a.engine_id;
150 last_name[0] = GetString(STR_ENGINE_NAME);
151 }
152
153 if (b.engine_id != _last_engine[1]) {
154 _last_engine[1] = b.engine_id;
156 last_name[1] = GetString(STR_ENGINE_NAME);
157 }
158
159 int r = StrNaturalCompare(last_name[0], last_name[1]); // Sort by name (natural sorting).
160
161 /* Use EngineID to sort instead since we want consistent sorting */
162 if (r == 0) return EngineNumberSorter(a, b);
163 return _engine_sort_direction ? r > 0 : r < 0;
164}
165
173{
174 const int va = Engine::Get(a.engine_id)->reliability;
175 const int vb = Engine::Get(b.engine_id)->reliability;
176 const int r = va - vb;
177
178 /* Use EngineID to sort instead since we want consistent sorting */
179 if (r == 0) return EngineNumberSorter(a, b);
180 return _engine_sort_direction ? r > 0 : r < 0;
181}
182
190{
191 Money va = Engine::Get(a.engine_id)->GetCost();
192 Money vb = Engine::Get(b.engine_id)->GetCost();
193 int r = ClampTo<int32_t>(va - vb);
194
195 /* Use EngineID to sort instead since we want consistent sorting */
196 if (r == 0) return EngineNumberSorter(a, b);
197 return _engine_sort_direction ? r > 0 : r < 0;
198}
199
207{
208 int va = Engine::Get(a.engine_id)->GetDisplayMaxSpeed();
209 int vb = Engine::Get(b.engine_id)->GetDisplayMaxSpeed();
210 int r = va - vb;
211
212 /* Use EngineID to sort instead since we want consistent sorting */
213 if (r == 0) return EngineNumberSorter(a, b);
214 return _engine_sort_direction ? r > 0 : r < 0;
215}
216
224{
225 int va = Engine::Get(a.engine_id)->GetPower();
226 int vb = Engine::Get(b.engine_id)->GetPower();
227 int r = va - vb;
228
229 /* Use EngineID to sort instead since we want consistent sorting */
230 if (r == 0) return EngineNumberSorter(a, b);
231 return _engine_sort_direction ? r > 0 : r < 0;
232}
233
241{
242 int va = Engine::Get(a.engine_id)->GetDisplayMaxTractiveEffort();
243 int vb = Engine::Get(b.engine_id)->GetDisplayMaxTractiveEffort();
244 int r = va - vb;
245
246 /* Use EngineID to sort instead since we want consistent sorting */
247 if (r == 0) return EngineNumberSorter(a, b);
248 return _engine_sort_direction ? r > 0 : r < 0;
249}
250
258{
259 Money va = Engine::Get(a.engine_id)->GetRunningCost();
260 Money vb = Engine::Get(b.engine_id)->GetRunningCost();
261 int r = ClampTo<int32_t>(va - vb);
262
263 /* Use EngineID to sort instead since we want consistent sorting */
264 if (r == 0) return EngineNumberSorter(a, b);
265 return _engine_sort_direction ? r > 0 : r < 0;
266}
267
275{
276 const Engine *e_a = Engine::Get(a.engine_id);
277 const Engine *e_b = Engine::Get(b.engine_id);
278 uint p_a = e_a->GetPower();
279 uint p_b = e_b->GetPower();
280 Money r_a = e_a->GetRunningCost();
281 Money r_b = e_b->GetRunningCost();
282 /* Check if running cost is zero in one or both engines.
283 * If only one of them is zero then that one has higher value,
284 * else if both have zero cost then compare powers. */
285 if (r_a == 0) {
286 if (r_b == 0) {
287 /* If it is ambiguous which to return go with their ID */
288 if (p_a == p_b) return EngineNumberSorter(a, b);
289 return _engine_sort_direction != (p_a < p_b);
290 }
292 }
293 if (r_b == 0) return _engine_sort_direction;
294 /* Using double for more precision when comparing close values.
295 * This shouldn't have any major effects in performance nor in keeping
296 * the game in sync between players since it's used in GUI only in client side */
297 double v_a = (double)p_a / (double)r_a;
298 double v_b = (double)p_b / (double)r_b;
299 /* Use EngineID to sort if both have same power/running cost,
300 * since we want consistent sorting.
301 * Also if both have no power then sort with reverse of running cost to simulate
302 * previous sorting behaviour for wagons. */
303 if (v_a == 0 && v_b == 0) return EngineRunningCostSorter(b, a);
304 if (v_a == v_b) return EngineNumberSorter(a, b);
305 return _engine_sort_direction != (v_a < v_b);
306}
307
308/* Train sorting functions */
309
317{
318 const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
319 const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
320
321 int va = GetTotalCapacityOfArticulatedParts(a.engine_id) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
322 int vb = GetTotalCapacityOfArticulatedParts(b.engine_id) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
323 int r = va - vb;
324
325 /* Use EngineID to sort instead since we want consistent sorting */
326 if (r == 0) return EngineNumberSorter(a, b);
327 return _engine_sort_direction ? r > 0 : r < 0;
328}
329
337{
338 int val_a = (RailVehInfo(a.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
339 int val_b = (RailVehInfo(b.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
340 int r = val_a - val_b;
341
342 /* Use EngineID to sort instead since we want consistent sorting */
343 if (r == 0) return EngineNumberSorter(a, b);
344 return _engine_sort_direction ? r > 0 : r < 0;
345}
346
347/* Road vehicle sorting functions */
348
356{
359 int r = va - vb;
360
361 /* Use EngineID to sort instead since we want consistent sorting */
362 if (r == 0) return EngineNumberSorter(a, b);
363 return _engine_sort_direction ? r > 0 : r < 0;
364}
365
366/* Ship vehicle sorting functions */
367
375{
376 const Engine *e_a = Engine::Get(a.engine_id);
377 const Engine *e_b = Engine::Get(b.engine_id);
378
379 int va = e_a->GetDisplayDefaultCapacity();
380 int vb = e_b->GetDisplayDefaultCapacity();
381 int r = va - vb;
382
383 /* Use EngineID to sort instead since we want consistent sorting */
384 if (r == 0) return EngineNumberSorter(a, b);
385 return _engine_sort_direction ? r > 0 : r < 0;
386}
387
388/* Aircraft sorting functions */
389
397{
398 const Engine *e_a = Engine::Get(a.engine_id);
399 const Engine *e_b = Engine::Get(b.engine_id);
400
401 uint16_t mail_a, mail_b;
402 int va = e_a->GetDisplayDefaultCapacity(&mail_a);
403 int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
404 int r = va - vb;
405
406 if (r == 0) {
407 /* The planes have the same passenger capacity. Check mail capacity instead */
408 r = mail_a - mail_b;
409
410 if (r == 0) {
411 /* Use EngineID to sort instead since we want consistent sorting */
412 return EngineNumberSorter(a, b);
413 }
414 }
415 return _engine_sort_direction ? r > 0 : r < 0;
416}
417
425{
426 uint16_t r_a = Engine::Get(a.engine_id)->GetRange();
427 uint16_t r_b = Engine::Get(b.engine_id)->GetRange();
428
429 int r = r_a - r_b;
430
431 /* Use EngineID to sort instead since we want consistent sorting */
432 if (r == 0) return EngineNumberSorter(a, b);
433 return _engine_sort_direction ? r > 0 : r < 0;
434}
435
485
487const std::initializer_list<const StringID> _engine_sort_listing[] = {{
488 /* Trains */
489 STR_SORT_BY_ENGINE_ID,
490 STR_SORT_BY_COST,
491 STR_SORT_BY_MAX_SPEED,
492 STR_SORT_BY_POWER,
493 STR_SORT_BY_TRACTIVE_EFFORT,
494 STR_SORT_BY_INTRO_DATE,
495 STR_SORT_BY_NAME,
496 STR_SORT_BY_RUNNING_COST,
497 STR_SORT_BY_POWER_VS_RUNNING_COST,
498 STR_SORT_BY_RELIABILITY,
499 STR_SORT_BY_CARGO_CAPACITY,
500}, {
501 /* Road vehicles */
502 STR_SORT_BY_ENGINE_ID,
503 STR_SORT_BY_COST,
504 STR_SORT_BY_MAX_SPEED,
505 STR_SORT_BY_POWER,
506 STR_SORT_BY_TRACTIVE_EFFORT,
507 STR_SORT_BY_INTRO_DATE,
508 STR_SORT_BY_NAME,
509 STR_SORT_BY_RUNNING_COST,
510 STR_SORT_BY_POWER_VS_RUNNING_COST,
511 STR_SORT_BY_RELIABILITY,
512 STR_SORT_BY_CARGO_CAPACITY,
513}, {
514 /* Ships */
515 STR_SORT_BY_ENGINE_ID,
516 STR_SORT_BY_COST,
517 STR_SORT_BY_MAX_SPEED,
518 STR_SORT_BY_INTRO_DATE,
519 STR_SORT_BY_NAME,
520 STR_SORT_BY_RUNNING_COST,
521 STR_SORT_BY_RELIABILITY,
522 STR_SORT_BY_CARGO_CAPACITY,
523}, {
524 /* Aircraft */
525 STR_SORT_BY_ENGINE_ID,
526 STR_SORT_BY_COST,
527 STR_SORT_BY_MAX_SPEED,
528 STR_SORT_BY_INTRO_DATE,
529 STR_SORT_BY_NAME,
530 STR_SORT_BY_RUNNING_COST,
531 STR_SORT_BY_RELIABILITY,
532 STR_SORT_BY_CARGO_CAPACITY,
533 STR_SORT_BY_RANGE,
534}};
535
537static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoType cargo_type)
538{
539 if (cargo_type == CargoFilterCriteria::CF_ANY) {
540 return true;
541 } else if (cargo_type == CargoFilterCriteria::CF_ENGINES) {
542 return Engine::Get(item->engine_id)->GetPower() != 0;
543 } else {
544 CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(item->engine_id, true) & _standard_cargo_mask;
545 return (cargo_type == CargoFilterCriteria::CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cargo_type));
546 }
547}
548
549static GUIEngineList::FilterFunction * const _engine_filter_funcs[] = {
551};
552
553static uint GetCargoWeight(const CargoArray &cap, VehicleType vtype)
554{
555 uint weight = 0;
556 for (CargoType c = 0; c < NUM_CARGO; c++) {
557 if (cap[c] != 0) {
558 if (vtype == VEH_TRAIN) {
559 weight += CargoSpec::Get(c)->WeightOfNUnitsInTrain(cap[c]);
560 } else {
561 weight += CargoSpec::Get(c)->WeightOfNUnits(cap[c]);
562 }
563 }
564 }
565 return weight;
566}
567
568static int DrawCargoCapacityInfo(int left, int right, int y, TestedEngineDetails &te, bool refittable)
569{
570 for (const CargoSpec *cs : _sorted_cargo_specs) {
571 CargoType cargo_type = cs->Index();
572 if (te.all_capacities[cargo_type] == 0) continue;
573
574 SetDParam(0, cargo_type);
575 SetDParam(1, te.all_capacities[cargo_type]);
576 SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
577 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
579 }
580
581 return y;
582}
583
584/* Draw rail wagon specific details */
585static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
586{
587 const Engine *e = Engine::Get(engine_number);
588
589 /* Purchase cost */
590 if (te.cost != 0) {
591 SetDParam(0, e->GetCost() + te.cost);
592 SetDParam(1, te.cost);
593 DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
594 } else {
595 SetDParam(0, e->GetCost());
596 DrawString(left, right, y, STR_PURCHASE_INFO_COST);
597 }
599
600 /* Wagon weight - (including cargo) */
601 uint weight = e->GetDisplayWeight();
602 SetDParam(0, weight);
603 SetDParam(1, GetCargoWeight(te.all_capacities, VEH_TRAIN) + weight);
604 DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
606
607 /* Wagon speed limit, displayed if above zero */
609 uint max_speed = e->GetDisplayMaxSpeed();
610 if (max_speed > 0) {
611 SetDParam(0, PackVelocity(max_speed, e->type));
612 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED);
614 }
615 }
616
617 /* Running cost */
618 if (rvi->running_cost_class != INVALID_PRICE) {
619 SetDParam(0, e->GetRunningCost());
620 DrawString(left, right, y, TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR);
622 }
623
624 return y;
625}
626
627/* Draw locomotive specific details */
628static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
629{
630 const Engine *e = Engine::Get(engine_number);
631
632 /* Purchase Cost - Engine weight */
633 if (te.cost != 0) {
634 SetDParam(0, e->GetCost() + te.cost);
635 SetDParam(1, te.cost);
637 DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_WEIGHT);
638 } else {
639 SetDParam(0, e->GetCost());
641 DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
642 }
644
645 /* Max speed - Engine power */
647 SetDParam(1, e->GetPower());
648 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
650
651 /* Max tractive effort - not applicable if old acceleration or maglev */
654 DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
656 }
657
658 /* Running cost */
659 if (rvi->running_cost_class != INVALID_PRICE) {
660 SetDParam(0, e->GetRunningCost());
661 DrawString(left, right, y, TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR);
663 }
664
665 /* Powered wagons power - Powered wagons extra weight */
666 if (rvi->pow_wag_power != 0) {
667 SetDParam(0, rvi->pow_wag_power);
668 SetDParam(1, rvi->pow_wag_weight);
669 DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT);
671 }
672
673 return y;
674}
675
676/* Draw road vehicle specific details */
677static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
678{
679 const Engine *e = Engine::Get(engine_number);
680
682 /* Purchase Cost */
683 if (te.cost != 0) {
684 SetDParam(0, e->GetCost() + te.cost);
685 SetDParam(1, te.cost);
686 DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
687 } else {
688 SetDParam(0, e->GetCost());
689 DrawString(left, right, y, STR_PURCHASE_INFO_COST);
690 }
692
693 /* Road vehicle weight - (including cargo) */
694 int16_t weight = e->GetDisplayWeight();
695 SetDParam(0, weight);
696 SetDParam(1, GetCargoWeight(te.all_capacities, VEH_ROAD) + weight);
697 DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
699
700 /* Max speed - Engine power */
702 SetDParam(1, e->GetPower());
703 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
705
706 /* Max tractive effort */
708 DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
710 } else {
711 /* Purchase cost - Max speed */
712 if (te.cost != 0) {
713 SetDParam(0, e->GetCost() + te.cost);
714 SetDParam(1, te.cost);
716 DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
717 } else {
718 SetDParam(0, e->GetCost());
720 DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
721 }
723 }
724
725 /* Running cost */
726 SetDParam(0, e->GetRunningCost());
727 DrawString(left, right, y, TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR);
729
730 return y;
731}
732
733/* Draw ship specific details */
734static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
735{
736 const Engine *e = Engine::Get(engine_number);
737
738 /* Purchase cost - Max speed */
739 uint raw_speed = e->GetDisplayMaxSpeed();
740 uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
741 uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
742
743 if (ocean_speed == canal_speed) {
744 if (te.cost != 0) {
745 SetDParam(0, e->GetCost() + te.cost);
746 SetDParam(1, te.cost);
747 SetDParam(2, PackVelocity(ocean_speed, e->type));
748 DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
749 } else {
750 SetDParam(0, e->GetCost());
751 SetDParam(1, PackVelocity(ocean_speed, e->type));
752 DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
753 }
755 } else {
756 if (te.cost != 0) {
757 SetDParam(0, e->GetCost() + te.cost);
758 SetDParam(1, te.cost);
759 DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
760 } else {
761 SetDParam(0, e->GetCost());
762 DrawString(left, right, y, STR_PURCHASE_INFO_COST);
763 }
765
766 SetDParam(0, PackVelocity(ocean_speed, e->type));
767 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN);
769
770 SetDParam(0, PackVelocity(canal_speed, e->type));
771 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL);
773 }
774
775 /* Cargo type + capacity */
776 SetDParam(0, te.cargo);
777 SetDParam(1, te.capacity);
778 SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
779 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
781
782 /* Running cost */
783 SetDParam(0, e->GetRunningCost());
784 DrawString(left, right, y, TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR);
786
787 return y;
788}
789
799static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
800{
801 const Engine *e = Engine::Get(engine_number);
802
803 /* Purchase cost - Max speed */
804 if (te.cost != 0) {
805 SetDParam(0, e->GetCost() + te.cost);
806 SetDParam(1, te.cost);
808 DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
809 } else {
810 SetDParam(0, e->GetCost());
812 DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
813 }
815
816 /* Cargo capacity */
817 if (te.mail_capacity > 0) {
818 SetDParam(0, te.cargo);
819 SetDParam(1, te.capacity);
820 SetDParam(2, GetCargoTypeByLabel(CT_MAIL));
822 DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY);
823 } else {
824 /* Note, if the default capacity is selected by the refit capacity
825 * callback, then the capacity shown is likely to be incorrect. */
826 SetDParam(0, te.cargo);
827 SetDParam(1, te.capacity);
828 SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
829 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
830 }
832
833 /* Running cost */
834 SetDParam(0, e->GetRunningCost());
835 DrawString(left, right, y, TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR);
837
838 /* Aircraft type */
840 DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_TYPE);
842
843 /* Aircraft range, if available. */
844 uint16_t range = e->GetRange();
845 if (range != 0) {
846 SetDParam(0, range);
847 DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE);
849 }
850
851 return y;
852}
853
854
860static std::optional<std::string> GetNewGRFAdditionalText(EngineID engine)
861{
862 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr);
863 if (callback == CALLBACK_FAILED || callback == 0x400) return std::nullopt;
864 const GRFFile *grffile = Engine::Get(engine)->GetGRF();
865 assert(grffile != nullptr);
866 if (callback > 0x400) {
868 return std::nullopt;
869 }
870
871 StartTextRefStackUsage(grffile, 6);
872 std::string result = GetString(GetGRFStringID(grffile->grfid, GRFSTR_MISC_GRF_TEXT + callback));
874 return result;
875}
876
885static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
886{
887 auto text = GetNewGRFAdditionalText(engine);
888 if (!text) return y;
889 return DrawStringMultiLine(left, right, y, INT32_MAX, *text, TC_BLACK);
890}
891
892void TestedEngineDetails::FillDefaultCapacities(const Engine *e)
893{
894 this->cargo = e->GetDefaultCargoType();
895 if (e->type == VEH_TRAIN || e->type == VEH_ROAD) {
897 this->capacity = this->all_capacities[this->cargo];
898 this->mail_capacity = 0;
899 } else {
901 this->all_capacities[this->cargo] = this->capacity;
902 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
903 this->all_capacities[GetCargoTypeByLabel(CT_MAIL)] = this->mail_capacity;
904 } else {
905 this->mail_capacity = 0;
906 }
907 }
908 if (this->all_capacities.GetCount() == 0) this->cargo = INVALID_CARGO;
909}
910
917int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
918{
919 const Engine *e = Engine::Get(engine_number);
920 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
921 bool refittable = IsArticulatedVehicleRefittable(engine_number);
922 bool articulated_cargo = false;
923
924 switch (e->type) {
925 default: NOT_REACHED();
926 case VEH_TRAIN:
927 if (e->u.rail.railveh_type == RAILVEH_WAGON) {
928 y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
929 } else {
930 y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
931 }
932 articulated_cargo = true;
933 break;
934
935 case VEH_ROAD:
936 y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te);
937 articulated_cargo = true;
938 break;
939
940 case VEH_SHIP:
941 y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te);
942 break;
943
944 case VEH_AIRCRAFT:
945 y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
946 break;
947 }
948
949 if (articulated_cargo) {
950 /* Cargo type + capacity, or N/A */
951 int new_y = DrawCargoCapacityInfo(left, right, y, te, refittable);
952
953 if (new_y == y) {
954 SetDParam(0, INVALID_CARGO);
955 SetDParam(2, STR_EMPTY);
956 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
958 } else {
959 y = new_y;
960 }
961 }
962
963 /* Draw details that apply to all types except rail wagons. */
964 if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
965 /* Design date - Life length */
966 SetDParam(0, ymd.year);
968 DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE);
970
971 /* Reliability */
973 DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY);
975 }
976
977 if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
978
979 /* Additional text from NewGRF */
980 y = ShowAdditionalText(left, right, y, engine_number);
981
982 /* The NewGRF's name which the vehicle comes from */
983 const GRFConfig *config = GetGRFConfig(e->GetGRFID());
984 if (_settings_client.gui.show_newgrf_name && config != nullptr)
985 {
986 DrawString(left, right, y, config->GetName(), TC_BLACK);
988 }
989
990 return y;
991}
992
1003void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group)
1004{
1005 static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
1006
1007 auto [first, last] = sb.GetVisibleRangeIterators(eng_list);
1008
1009 bool rtl = _current_text_dir == TD_RTL;
1010 int step_size = GetEngineListHeight(type);
1011 int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
1012 int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
1013 int sprite_width = sprite_left + sprite_right;
1014 int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
1015 int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
1016
1017 Rect ir = r.WithHeight(step_size).Shrink(WidgetDimensions::scaled.matrix);
1018 int sprite_y_offset = ScaleSpriteTrad(sprite_y_offsets[type]) + ir.Height() / 2;
1019
1020 Dimension replace_icon = {0, 0};
1021 int count_width = 0;
1022 if (show_count) {
1023 replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
1024
1025 uint biggest_num_engines = 0;
1026 for (auto it = first; it != last; ++it) {
1027 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, it->engine_id);
1028 biggest_num_engines = std::max(biggest_num_engines, num_engines);
1029 }
1030
1031 SetDParam(0, biggest_num_engines);
1032 count_width = GetStringBoundingBox(STR_JUST_COMMA, FS_SMALL).width;
1033 }
1034
1035 Rect tr = ir.Indent(circle_width + WidgetDimensions::scaled.hsep_normal + sprite_width + WidgetDimensions::scaled.hsep_wide, rtl); // Name position
1036 Rect cr = tr.Indent(replace_icon.width + WidgetDimensions::scaled.hsep_wide, !rtl).WithWidth(count_width, !rtl); // Count position
1037 Rect rr = tr.WithWidth(replace_icon.width, !rtl); // Replace icon position
1038 if (show_count) tr = tr.Indent(count_width + WidgetDimensions::scaled.hsep_normal + replace_icon.width + WidgetDimensions::scaled.hsep_wide, !rtl);
1039
1040 int normal_text_y_offset = (ir.Height() - GetCharacterHeight(FS_NORMAL)) / 2;
1041 int small_text_y_offset = ir.Height() - GetCharacterHeight(FS_SMALL);
1042 int replace_icon_y_offset = (ir.Height() - replace_icon.height) / 2;
1043
1044 const int offset = (rtl ? -circle_width : circle_width) / 2;
1046
1047 int y = ir.top;
1048 for (auto it = first; it != last; ++it) {
1049 const auto &item = *it;
1050 uint indent = item.indent * WidgetDimensions::scaled.hsep_indent;
1051 bool has_variants = item.flags.Test(EngineDisplayFlag::HasVariants);
1052 bool is_folded = item.flags.Test(EngineDisplayFlag::IsFolded);
1053 bool shaded = item.flags.Test(EngineDisplayFlag::Shaded);
1054
1055 if (item.indent > 0) {
1056 /* Draw tree continuation lines. */
1057 int tx = (rtl ? ir.right : ir.left) + offset;
1058 int ty = y - WidgetDimensions::scaled.matrix.top;
1059 for (uint lvl = 1; lvl <= item.indent; ++lvl) {
1060 if (HasBit(item.level_mask, lvl)) GfxDrawLine(tx, ty, tx, ty + step_size - 1, linecolour, WidgetDimensions::scaled.fullbevel.top);
1061 if (lvl < item.indent) tx += level_width;
1062 }
1063 /* Draw our node in the tree. */
1064 int ycentre = y + normal_text_y_offset + GetCharacterHeight(FS_NORMAL) / 2 - 1;
1065 if (!HasBit(item.level_mask, item.indent)) GfxDrawLine(tx, ty, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
1066 GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
1067 }
1068
1069 /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
1070 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
1071
1072 const Engine *e = Engine::Get(item.engine_id);
1073 bool hidden = HasBit(e->company_hidden, _local_company);
1074 StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
1075 TextColour tc = (item.engine_id == selected_id) ? TC_WHITE : ((hidden | shaded) ? (TC_GREY | TC_FORCED | TC_NO_SHADE) : TC_BLACK);
1076
1077 if (show_count) {
1078 /* relies on show_count to find 'Vehicle in use' panel of autoreplace window */
1080 } else {
1081 SetDParam(0, PackEngineNameDParam(item.engine_id, EngineNameContext::PurchaseList, item.indent));
1082 }
1083 Rect itr = tr.Indent(indent, rtl);
1084 DrawString(itr.left, itr.right, y + normal_text_y_offset, str, tc);
1085 int sprite_x = ir.Indent(indent + circle_width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(sprite_width, rtl).left + sprite_left;
1086 DrawVehicleEngine(r.left, r.right, sprite_x, y + sprite_y_offset, item.engine_id, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(item.engine_id, _local_company), EIT_PURCHASE);
1087 if (show_count) {
1088 SetDParam(0, num_engines);
1089 DrawString(cr.left, cr.right, y + small_text_y_offset, STR_JUST_COMMA, TC_BLACK, SA_RIGHT | SA_FORCE, false, FS_SMALL);
1090 if (EngineHasReplacementForCompany(Company::Get(_local_company), item.engine_id, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr.left, y + replace_icon_y_offset);
1091 }
1092 if (has_variants) {
1093 Rect fr = ir.Indent(indent, rtl).WithWidth(circle_width, rtl);
1094 DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, {fr.left, y, fr.right, y + ir.Height() - 1}, SA_CENTER);
1095 }
1096 y += step_size;
1097 }
1098}
1099
1107void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button)
1108{
1109 uint32_t hidden_mask = 0;
1110 /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
1111 if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
1112 SetBit(hidden_mask, 3); // power
1113 SetBit(hidden_mask, 4); // tractive effort
1114 SetBit(hidden_mask, 8); // power by running costs
1115 }
1116 /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
1117 if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
1118 SetBit(hidden_mask, 4); // tractive effort
1119 }
1120 ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
1121}
1122
1130void GUIEngineListAddChildren(GUIEngineList &dst, const GUIEngineList &src, EngineID parent, uint8_t indent)
1131{
1132 for (const auto &item : src) {
1133 if (item.variant_id != parent || item.engine_id == parent) continue;
1134
1135 const Engine *e = Engine::Get(item.engine_id);
1136 EngineDisplayFlags flags = item.flags;
1138 dst.emplace_back(e->display_last_variant == INVALID_ENGINE ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent);
1139
1140 /* Add variants if not folded */
1141 if (item.flags.Test(EngineDisplayFlag::HasVariants) && !item.flags.Test(EngineDisplayFlag::IsFolded)) {
1142 /* Add this engine again as a child */
1143 if (!item.flags.Test(EngineDisplayFlag::Shaded)) {
1144 dst.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags{}, indent + 1);
1145 }
1146 GUIEngineListAddChildren(dst, src, item.engine_id, indent + 1);
1147 }
1148 }
1149
1150 if (indent > 0 || dst.empty()) return;
1151
1152 /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
1153 uint16_t level_mask = 0;
1154 for (auto it = std::rbegin(dst); std::next(it) != std::rend(dst); ++it) {
1155 auto next_it = std::next(it);
1156 SB(level_mask, it->indent, 1, it->indent <= next_it->indent);
1157 next_it->level_mask = level_mask;
1158 }
1159}
1160
1165
1169 union {
1179 GUIEngineList eng_list;
1182 Scrollbar *vscroll;
1184
1187
1188 void SetBuyVehicleText()
1189 {
1191
1192 bool refit = this->sel_engine != INVALID_ENGINE && this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY && this->cargo_filter_criteria != CargoFilterCriteria::CF_NONE && this->cargo_filter_criteria != CargoFilterCriteria::CF_ENGINES;
1193 if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter_criteria;
1194
1195 if (refit) {
1197 } else {
1199 }
1200 }
1201
1203 {
1204 this->vehicle_type = type;
1205 this->listview_mode = tile == INVALID_TILE;
1206 this->window_number = this->listview_mode ? (int)type : tile.base();
1207
1208 this->sel_engine = INVALID_ENGINE;
1209
1210 this->sort_criteria = _engine_sort_last_criteria[type];
1211 this->descending_sort_order = _engine_sort_last_order[type];
1212 this->show_hidden_engines = _engine_sort_show_hidden_engines[type];
1213
1214 this->UpdateFilterByTile();
1215
1216 this->CreateNestedTree();
1217
1218 this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR);
1219
1220 /* If we are just viewing the list of vehicles, we do not need the Build button.
1221 * So we just hide it, and enlarge the Rename button by the now vacant place. */
1222 if (this->listview_mode) this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
1223
1226
1229
1230 widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
1232
1235 widget->SetLowered(this->show_hidden_engines);
1236
1237 this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9);
1238
1239 if (tile == INVALID_TILE) {
1240 this->FinishInitNested(type);
1241 } else {
1242 this->FinishInitNested(tile);
1243 }
1244
1246 this->vehicle_editbox.cancel_button = QueryString::ACTION_CLEAR;
1247
1248 this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
1249
1250 this->eng_list.ForceRebuild();
1251 this->GenerateBuildList(); // generate the list, since we need it in the next line
1252
1253 /* Select the first unshaded engine in the list as default when opening the window */
1254 EngineID engine = INVALID_ENGINE;
1255 auto it = std::ranges::find_if(this->eng_list, [](const GUIEngineListItem &item) { return !item.flags.Test(EngineDisplayFlag::Shaded); });
1256 if (it != this->eng_list.end()) engine = it->engine_id;
1257 this->SelectEngine(engine);
1258 }
1259
1262 {
1263 switch (this->vehicle_type) {
1264 default: NOT_REACHED();
1265 case VEH_TRAIN:
1266 if (this->listview_mode) {
1267 this->filter.railtype = INVALID_RAILTYPE;
1268 } else {
1269 this->filter.railtype = GetRailType(this->window_number);
1270 }
1271 break;
1272
1273 case VEH_ROAD:
1274 if (this->listview_mode) {
1275 this->filter.roadtype = INVALID_ROADTYPE;
1276 } else {
1277 this->filter.roadtype = GetRoadTypeRoad(this->window_number);
1278 if (this->filter.roadtype == INVALID_ROADTYPE) {
1279 this->filter.roadtype = GetRoadTypeTram(this->window_number);
1280 }
1281 }
1282 break;
1283
1284 case VEH_SHIP:
1285 case VEH_AIRCRAFT:
1286 break;
1287 }
1288 }
1289
1290 StringID GetCargoFilterLabel(CargoType cargo_type) const
1291 {
1292 switch (cargo_type) {
1296 default: return CargoSpec::Get(cargo_type)->name;
1297 }
1298 }
1299
1302 {
1303 /* Set the last cargo filter criteria. */
1304 this->cargo_filter_criteria = _engine_sort_last_cargo_criteria[this->vehicle_type];
1305 if (this->cargo_filter_criteria < NUM_CARGO && !HasBit(_standard_cargo_mask, this->cargo_filter_criteria)) this->cargo_filter_criteria = CargoFilterCriteria::CF_ANY;
1306
1307 this->eng_list.SetFilterFuncs(_engine_filter_funcs);
1308 this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
1309 }
1310
1311 void SelectEngine(EngineID engine)
1312 {
1313 CargoType cargo = this->cargo_filter_criteria;
1314 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1315
1316 this->sel_engine = engine;
1317 this->SetBuyVehicleText();
1318
1319 if (this->sel_engine == INVALID_ENGINE) return;
1320
1321 const Engine *e = Engine::Get(this->sel_engine);
1322
1323 if (!this->listview_mode) {
1324 /* Query for cost and refitted capacity */
1326 if (ret.Succeeded()) {
1327 this->te.cost = ret.GetCost() - e->GetCost();
1328 this->te.capacity = refit_capacity;
1329 this->te.mail_capacity = refit_mail;
1330 this->te.cargo = !IsValidCargoType(cargo) ? e->GetDefaultCargoType() : cargo;
1332 return;
1333 }
1334 }
1335
1336 /* Purchase test was not possible or failed, fill in the defaults instead. */
1337 this->te.cost = 0;
1338 this->te.FillDefaultCapacities(e);
1339 }
1340
1341 void OnInit() override
1342 {
1343 this->SetCargoFilterArray();
1344 }
1345
1348 {
1349 this->eng_list.Filter(this->cargo_filter_criteria);
1350 if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
1351 this->SelectEngine(INVALID_ENGINE);
1352 } 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
1353 this->SelectEngine(this->eng_list[0].engine_id);
1354 }
1355 }
1356
1359 {
1361 return CargoAndEngineFilter(&item, this->cargo_filter_criteria);
1362 }
1363
1365 bool FilterByText(const Engine *e)
1366 {
1367 /* Do not filter if the filter text box is empty */
1368 if (this->string_filter.IsEmpty()) return true;
1369
1370 /* Filter engine name */
1371 this->string_filter.ResetState();
1373 this->string_filter.AddLine(GetString(STR_ENGINE_NAME));
1374
1375 /* Filter NewGRF extra text */
1376 auto text = GetNewGRFAdditionalText(e->index);
1377 if (text) this->string_filter.AddLine(*text);
1378
1379 return this->string_filter.GetState();
1380 }
1381
1382 /* Figure out what train EngineIDs to put in the list */
1383 void GenerateBuildTrainList(GUIEngineList &list)
1384 {
1385 std::vector<EngineID> variants;
1387 size_t num_engines = 0;
1388
1389 list.clear();
1390
1391 /* Make list of all available train engines and wagons.
1392 * Also check to see if the previously selected engine is still available,
1393 * and if not, reset selection to INVALID_ENGINE. This could be the case
1394 * when engines become obsolete and are removed */
1395 for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
1396 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1397 EngineID eid = e->index;
1398 const RailVehicleInfo *rvi = &e->u.rail;
1399
1400 if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
1402
1403 /* Filter now! So num_engines and num_wagons is valid */
1404 if (!FilterSingleEngine(eid)) continue;
1405
1406 /* Filter by name or NewGRF extra text */
1407 if (!FilterByText(e)) continue;
1408
1409 list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1410
1411 if (rvi->railveh_type != RAILVEH_WAGON) num_engines++;
1412
1413 /* Add all parent variants of this engine to the variant list */
1414 EngineID parent = e->info.variant_id;
1415 while (parent != INVALID_ENGINE) {
1416 variants.push_back(parent);
1417 parent = Engine::Get(parent)->info.variant_id;
1418 }
1419
1420 if (eid == this->sel_engine) sel_id = eid;
1421 }
1422
1423 /* ensure primary engine of variant group is in list */
1424 for (const auto &variant : variants) {
1425 if (std::ranges::find(list, variant, &GUIEngineListItem::engine_id) == list.end()) {
1426 const Engine *e = Engine::Get(variant);
1427 list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1428 if (e->u.rail.railveh_type != RAILVEH_WAGON) num_engines++;
1429 }
1430 }
1431
1432 this->SelectEngine(sel_id);
1433
1434 /* invalidate cached values for name sorter - engine names could change */
1435 _last_engine[0] = _last_engine[1] = INVALID_ENGINE;
1436
1437 /* make engines first, and then wagons, sorted by selected sort_criteria */
1438 _engine_sort_direction = false;
1440
1441 /* and then sort engines */
1443 EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
1444
1445 /* and finally sort wagons */
1446 EngList_SortPartial(list, _engine_sort_functions[0][this->sort_criteria], num_engines, list.size() - num_engines);
1447 }
1448
1449 /* Figure out what road vehicle EngineIDs to put in the list */
1450 void GenerateBuildRoadVehList()
1451 {
1453
1454 this->eng_list.clear();
1455
1456 for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
1457 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1458 EngineID eid = e->index;
1459 if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
1460 if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
1461
1462 /* Filter by name or NewGRF extra text */
1463 if (!FilterByText(e)) continue;
1464
1465 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1466
1467 if (eid == this->sel_engine) sel_id = eid;
1468 }
1469 this->SelectEngine(sel_id);
1470 }
1471
1472 /* Figure out what ship EngineIDs to put in the list */
1473 void GenerateBuildShipList()
1474 {
1476 this->eng_list.clear();
1477
1478 for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
1479 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1480 EngineID eid = e->index;
1481 if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
1482
1483 /* Filter by name or NewGRF extra text */
1484 if (!FilterByText(e)) continue;
1485
1486 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1487
1488 if (eid == this->sel_engine) sel_id = eid;
1489 }
1490 this->SelectEngine(sel_id);
1491 }
1492
1493 /* Figure out what aircraft EngineIDs to put in the list */
1494 void GenerateBuildAircraftList()
1495 {
1497
1498 this->eng_list.clear();
1499
1500 const Station *st = this->listview_mode ? nullptr : Station::GetByTile(TileIndex(this->window_number));
1501
1502 /* Make list of all available planes.
1503 * Also check to see if the previously selected plane is still available,
1504 * and if not, reset selection to INVALID_ENGINE. This could be the case
1505 * when planes become obsolete and are removed */
1506 for (const Engine *e : Engine::IterateType(VEH_AIRCRAFT)) {
1507 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1508 EngineID eid = e->index;
1510 /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
1511 if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
1512
1513 /* Filter by name or NewGRF extra text */
1514 if (!FilterByText(e)) continue;
1515
1516 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1517
1518 if (eid == this->sel_engine) sel_id = eid;
1519 }
1520
1521 this->SelectEngine(sel_id);
1522 }
1523
1524 /* Generate the list of vehicles */
1525 void GenerateBuildList()
1526 {
1527 if (!this->eng_list.NeedRebuild()) return;
1528
1529 /* Update filter type in case the road/railtype of the depot got converted */
1530 this->UpdateFilterByTile();
1531
1532 this->eng_list.clear();
1533
1534 GUIEngineList list;
1535
1536 switch (this->vehicle_type) {
1537 default: NOT_REACHED();
1538 case VEH_TRAIN:
1539 this->GenerateBuildTrainList(list);
1540 GUIEngineListAddChildren(this->eng_list, list);
1541 this->eng_list.RebuildDone();
1542 return;
1543 case VEH_ROAD:
1544 this->GenerateBuildRoadVehList();
1545 break;
1546 case VEH_SHIP:
1547 this->GenerateBuildShipList();
1548 break;
1549 case VEH_AIRCRAFT:
1550 this->GenerateBuildAircraftList();
1551 break;
1552 }
1553
1554 this->FilterEngineList();
1555
1556 /* ensure primary engine of variant group is in list after filtering */
1557 std::vector<EngineID> variants;
1558 for (const auto &item : this->eng_list) {
1559 EngineID parent = item.variant_id;
1560 while (parent != INVALID_ENGINE) {
1561 variants.push_back(parent);
1562 parent = Engine::Get(parent)->info.variant_id;
1563 }
1564 }
1565
1566 for (const auto &variant : variants) {
1567 if (std::ranges::find(this->eng_list, variant, &GUIEngineListItem::engine_id) == this->eng_list.end()) {
1568 const Engine *e = Engine::Get(variant);
1569 this->eng_list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1570 }
1571 }
1572
1574 EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
1575
1576 this->eng_list.swap(list);
1577 GUIEngineListAddChildren(this->eng_list, list, INVALID_ENGINE, 0);
1578 this->eng_list.RebuildDone();
1579 }
1580
1581 DropDownList BuildCargoDropDownList() const
1582 {
1583 DropDownList list;
1584
1585 /* Add item for disabling filtering. */
1586 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY));
1587 /* Specific filters for trains. */
1588 if (this->vehicle_type == VEH_TRAIN) {
1589 /* Add item for locomotives only in case of trains. */
1590 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ENGINES), CargoFilterCriteria::CF_ENGINES));
1591 /* Add item for vehicles not carrying anything, e.g. train engines.
1592 * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
1593 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE));
1594 }
1595
1596 /* Add cargos */
1598 for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
1599 list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index()));
1600 }
1601
1602 return list;
1603 }
1604
1605 void BuildVehicle()
1606 {
1607 EngineID sel_eng = this->sel_engine;
1608 if (sel_eng == INVALID_ENGINE) return;
1609
1610 CargoType cargo = this->cargo_filter_criteria;
1611 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1612 if (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) {
1613 Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1614 } else {
1615 Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1616 }
1617
1618 /* Update last used variant in hierarchy and refresh if necessary. */
1619 bool refresh = false;
1621 while (parent != INVALID_ENGINE) {
1623 refresh |= (e->display_last_variant != sel_eng);
1624 e->display_last_variant = sel_eng;
1625 parent = e->info.variant_id;
1626 }
1627
1628 if (refresh) {
1629 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1630 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1631 }
1632 }
1633
1634 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1635 {
1636 switch (widget) {
1638 this->descending_sort_order ^= true;
1640 this->eng_list.ForceRebuild();
1641 this->SetDirty();
1642 break;
1643
1645 this->show_hidden_engines ^= true;
1647 this->eng_list.ForceRebuild();
1648 this->SetWidgetLoweredState(widget, this->show_hidden_engines);
1649 this->SetDirty();
1650 break;
1651
1652 case WID_BV_LIST: {
1654 const auto it = this->vscroll->GetScrolledItemFromWidget(this->eng_list, pt.y, this, WID_BV_LIST);
1655 if (it != this->eng_list.end()) {
1656 const auto &item = *it;
1657 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);
1658 if (item.flags.Test(EngineDisplayFlag::HasVariants) && IsInsideMM(r.left, r.right, pt.x)) {
1659 /* toggle folded flag on engine */
1661 Engine *engine = Engine::Get(item.variant_id);
1663
1664 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1665 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1666 return;
1667 }
1668 if (!item.flags.Test(EngineDisplayFlag::Shaded)) e = item.engine_id;
1669 }
1670 this->SelectEngine(e);
1671 this->SetDirty();
1672 if (_ctrl_pressed) {
1673 this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
1674 } else if (click_count > 1 && !this->listview_mode) {
1675 this->OnClick(pt, WID_BV_BUILD, 1);
1676 }
1677 break;
1678 }
1679
1680 case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
1681 DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
1682 break;
1683
1684 case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
1685 ShowDropDownList(this, this->BuildCargoDropDownList(), this->cargo_filter_criteria, widget);
1686 break;
1687
1688 case WID_BV_SHOW_HIDE: {
1689 const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1690 if (e != nullptr) {
1691 Command<CMD_SET_VEHICLE_VISIBILITY>::Post(this->sel_engine, !e->IsHidden(_current_company));
1692 }
1693 break;
1694 }
1695
1696 case WID_BV_BUILD:
1697 this->BuildVehicle();
1698 break;
1699
1700 case WID_BV_RENAME: {
1701 EngineID sel_eng = this->sel_engine;
1702 if (sel_eng != INVALID_ENGINE) {
1703 this->rename_engine = sel_eng;
1706 }
1707 break;
1708 }
1709 }
1710 }
1711
1717 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1718 {
1719 if (!gui_scope) return;
1720 /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
1721 if (this->vehicle_type == VEH_ROAD &&
1723 this->sort_criteria > 7) {
1724 this->sort_criteria = 0;
1726 }
1727 this->eng_list.ForceRebuild();
1728 }
1729
1730 void SetStringParameters(WidgetID widget) const override
1731 {
1732 switch (widget) {
1733 case WID_BV_CAPTION:
1734 if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) {
1735 const RailTypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
1737 } else if (this->vehicle_type == VEH_ROAD && !this->listview_mode) {
1738 const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype);
1740 } else {
1741 SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type);
1742 }
1743 break;
1744
1746 SetDParam(0, std::data(_engine_sort_listing[this->vehicle_type])[this->sort_criteria]);
1747 break;
1748
1750 SetDParam(0, this->GetCargoFilterLabel(this->cargo_filter_criteria));
1751 break;
1752
1753 case WID_BV_SHOW_HIDE: {
1754 const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1755 if (e != nullptr && e->IsHidden(_local_company)) {
1756 SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type);
1757 } else {
1758 SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1759 }
1760 break;
1761 }
1762 }
1763 }
1764
1766 {
1767 switch (widget) {
1768 case WID_BV_LIST:
1769 resize.height = GetEngineListHeight(this->vehicle_type);
1770 size.height = 3 * resize.height;
1771 size.width = std::max(size.width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165) + padding.width;
1772 break;
1773
1774 case WID_BV_PANEL:
1775 size.height = GetCharacterHeight(FS_NORMAL) * this->details_height + padding.height;
1776 break;
1777
1780 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
1781 d.height += padding.height;
1782 size = maxdim(size, d);
1783 break;
1784 }
1785
1787 size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList()).width + padding.width);
1788 break;
1789
1790 case WID_BV_BUILD:
1793 size.width += padding.width;
1794 size.height += padding.height;
1795 break;
1796
1797 case WID_BV_SHOW_HIDE:
1799 size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
1800 size.width += padding.width;
1801 size.height += padding.height;
1802 break;
1803 }
1804 }
1805
1806 void DrawWidget(const Rect &r, WidgetID widget) const override
1807 {
1808 switch (widget) {
1809 case WID_BV_LIST:
1811 this->vehicle_type,
1812 r,
1813 this->eng_list,
1814 *this->vscroll,
1815 this->sel_engine,
1816 false,
1818 );
1819 break;
1820
1822 this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
1823 break;
1824 }
1825 }
1826
1827 void OnPaint() override
1828 {
1829 this->GenerateBuildList();
1830 this->vscroll->SetCount(this->eng_list.size());
1831
1833
1834 /* Disable renaming engines in network games if you are not the server. */
1836
1837 this->DrawWidgets();
1838
1839 if (!this->IsShaded()) {
1840 int needed_height = this->details_height;
1841 /* Draw details panels. */
1842 if (this->sel_engine != INVALID_ENGINE) {
1843 const Rect r = this->GetWidget<NWidgetBase>(WID_BV_PANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1844 int text_end = DrawVehiclePurchaseInfo(r.left, r.right, r.top, this->sel_engine, this->te);
1846 }
1847 if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
1848 int resize = needed_height - this->details_height;
1849 this->details_height = needed_height;
1850 this->ReInit(0, resize * GetCharacterHeight(FS_NORMAL));
1851 return;
1852 }
1853 }
1854 }
1855
1856 void OnQueryTextFinished(std::optional<std::string> str) override
1857 {
1858 if (!str.has_value()) return;
1859
1860 Command<CMD_RENAME_ENGINE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, this->rename_engine, *str);
1861 }
1862
1863 void OnDropdownSelect(WidgetID widget, int index) override
1864 {
1865 switch (widget) {
1867 if (this->sort_criteria != index) {
1868 this->sort_criteria = index;
1870 this->eng_list.ForceRebuild();
1871 }
1872 break;
1873
1874 case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
1875 if (this->cargo_filter_criteria != index) {
1876 this->cargo_filter_criteria = index;
1878 /* deactivate filter if criteria is 'Show All', activate it otherwise */
1879 this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
1880 this->eng_list.ForceRebuild();
1881 this->SelectEngine(this->sel_engine);
1882 }
1883 break;
1884 }
1885 this->SetDirty();
1886 }
1887
1888 void OnResize() override
1889 {
1890 this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
1891 }
1892
1894 {
1895 if (wid == WID_BV_FILTER) {
1896 this->string_filter.SetFilterTerm(this->vehicle_editbox.text.GetText());
1897 this->InvalidateData();
1898 }
1899 }
1900
1902 {
1903 switch (hotkey) {
1906 SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
1907 return ES_HANDLED;
1908
1909 default:
1910 return ES_NOT_HANDLED;
1911 }
1912
1913 return ES_HANDLED;
1914 }
1915
1916 static inline HotkeyList hotkeys{"buildvehicle", {
1917 Hotkey('F', "focus_filter_box", BVHK_FOCUS_FILTER_BOX),
1918 }};
1919};
1920
1921static WindowDesc _build_vehicle_desc(
1922 WDP_AUTO, "build_vehicle", 240, 268,
1925 _nested_build_vehicle_widgets,
1926 &BuildVehicleWindow::hotkeys
1927);
1928
1929void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
1930{
1931 /* We want to be able to open both Available Train as Available Ships,
1932 * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number.
1933 * As it always is a low value, it won't collide with any real tile
1934 * number. */
1935 uint num = (tile == INVALID_TILE) ? (int)type : tile.base();
1936
1937 assert(IsCompanyBuildableVehicleType(type));
1938
1940
1941 new BuildVehicleWindow(_build_vehicle_desc, tile, type);
1942}
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.
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.
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group)
Engine drawing loop.
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:22
bool IsValidCargoType(CargoType t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:105
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
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 EnumBitSet & Flip(Tenum value)
Flip the enum value.
constexpr EnumBitSet & Reset(Tenum value)
Reset the enum value to not set.
constexpr bool Test(Tenum value) const
Test if the enum value is set.
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:1199
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:1139
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:117
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:169
uint8_t acceleration_type
Acceleration type of this rail type.
Definition rail.h:216
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:96
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:2533
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:28
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
RectPadding matrix
Padding of WWT_MATRIX items.
Definition window_gui.h:42
int hsep_indent
Width of identation for tree layouts.
Definition window_gui.h:63
Functions related to commands.
@ DC_QUERY_COST
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:1254
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:32
static const uint MAX_LENGTH_ENGINE_NAME_CHARS
The maximum length of an engine name in characters including '\0'.
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:23
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:31
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:30
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:922
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:851
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:988
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:774
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:54
@ 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
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 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:937
uint16_t GroupID
Type for all group identifiers.
Definition group_type.h:13
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:17
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(StringID 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:95
static constexpr CargoType CF_ENGINES
Show only engines (for rail vehicles only)
Definition cargo_type.h:96
static constexpr CargoType CF_ANY
Show all items independent of carried cargo (i.e. no filtering)
Definition cargo_type.h:94
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.
@ 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.
void StartTextRefStackUsage(const GRFFile *grffile, uint8_t numEntries, const uint32_t *values)
Start using the TTDP compatible string code parsing.
StringID GetGRFStringID(uint32_t grfid, GRFStringID stringid)
Returns the index for this stringid associated with its grfID.
void StopTextRefStackUsage()
Stop using the TTDP compatible string code parsing.
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:325
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:297
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:232
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:217
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:57
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1605
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:589
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.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:332
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 SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
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.
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 INVALID_ENGINE.
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:112
uint GetCount() const
Get the amount of cargos that have an amount.
Definition cargo_type.h:127
Specification of a cargo type.
Definition cargotype.h:77
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:140
StringID name
Name of this type of cargo.
Definition cargotype.h:94
GUISettings gui
settings related to the GUI
Dimensions (a width and height) of a rectangle in 2D.
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:109
EngineDisplayFlags flags
Flags for toggling/drawing (un)folded status and controlling indentation.
Definition engine_gui.h:23
EngineID variant_id
Variant group of the engine.
Definition engine_gui.h:22
EngineID engine_id
Engine to display in build purchase list.
Definition engine_gui.h:21
uint8_t indent
Display indentation level.
Definition engine_gui.h:24
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.
Tindex index
Index of this pool item.
static Titem * Get(size_t index)
Returns Titem with given index.
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:44
uint16_t pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition engine_type.h:58
RailType railtype
Railtype, mangled if elrail is disabled.
Definition engine_type.h:48
uint8_t pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition engine_type.h:59
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.
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:83
Station data structure.
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(const char *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:290
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:272
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:949
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:780
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1730
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:319
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:731
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3157
Window * parent
Parent window.
Definition window_gui.h:327
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:763
ResizeInfo resize
Resize information.
Definition window_gui.h:313
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:514
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1720
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:315
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:440
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:556
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:970
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:380
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:310
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:301
Stuff related to the text buffer GUI.
@ QSF_ENABLE_DEFAULT
enable the 'Default' button ("\0" is returned)
Definition textbuf_gui.h:21
@ QSF_LEN_IN_CHARS
the length of the string is counted in characters
Definition textbuf_gui.h:22
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:2142
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3058
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_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:62
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:46
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:41
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:57
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:55
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:60
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:56
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
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:1137
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:3217
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:3234
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