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