OpenTTD Source 20260512-master-g20b387b91f
build_vehicle_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "engine_base.h"
12#include "engine_func.h"
13#include "station_base.h"
14#include "network/network.h"
16#include "textbuf_gui.h"
17#include "command_func.h"
18#include "company_func.h"
19#include "vehicle_gui.h"
20#include "newgrf_badge.h"
21#include "newgrf_badge_config.h"
22#include "newgrf_badge_gui.h"
23#include "newgrf_engine.h"
24#include "newgrf_text.h"
25#include "group.h"
26#include "string_func.h"
27#include "strings_func.h"
28#include "window_func.h"
30#include "vehicle_func.h"
31#include "dropdown_type.h"
32#include "dropdown_func.h"
33#include "engine_gui.h"
34#include "cargotype.h"
36#include "autoreplace_func.h"
37#include "engine_cmd.h"
38#include "train_cmd.h"
39#include "vehicle_cmd.h"
40#include "zoom_func.h"
41#include "querystring_gui.h"
42#include "stringfilter_type.h"
43#include "hotkeys.h"
44
46
47#include "table/strings.h"
48
49#include "safeguards.h"
50
57{
58 return std::max<uint>(GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.matrix.Vertical(), GetVehicleImageCellSize(type, EIT_PURCHASE).height);
59}
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{
267 const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
268 const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
269
272 int r = va - vb;
273
274 /* Use EngineID to sort instead since we want consistent sorting */
275 if (r == 0) return EngineNumberSorter(a, b);
276 return _engine_sort_direction ? r > 0 : r < 0;
277}
278
281{
282 int val_a = (RailVehInfo(a.engine_id)->railveh_type == RailVehicleType::Wagon ? 1 : 0);
283 int val_b = (RailVehInfo(b.engine_id)->railveh_type == RailVehicleType::Wagon ? 1 : 0);
284 int r = val_a - val_b;
285
286 /* Use EngineID to sort instead since we want consistent sorting */
287 if (r == 0) return EngineNumberSorter(a, b);
288 return _engine_sort_direction ? r > 0 : r < 0;
289}
290
291/* Road vehicle sorting functions */
292
295{
298 int r = va - vb;
299
300 /* Use EngineID to sort instead since we want consistent sorting */
301 if (r == 0) return EngineNumberSorter(a, b);
302 return _engine_sort_direction ? r > 0 : r < 0;
303}
304
305/* Ship vehicle sorting functions */
306
309{
310 const Engine *e_a = Engine::Get(a.engine_id);
311 const Engine *e_b = Engine::Get(b.engine_id);
312
313 int va = e_a->GetDisplayDefaultCapacity();
314 int vb = e_b->GetDisplayDefaultCapacity();
315 int r = va - vb;
316
317 /* Use EngineID to sort instead since we want consistent sorting */
318 if (r == 0) return EngineNumberSorter(a, b);
319 return _engine_sort_direction ? r > 0 : r < 0;
320}
321
322/* Aircraft sorting functions */
323
326{
327 const Engine *e_a = Engine::Get(a.engine_id);
328 const Engine *e_b = Engine::Get(b.engine_id);
329
330 uint16_t mail_a, mail_b;
331 int va = e_a->GetDisplayDefaultCapacity(&mail_a);
332 int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
333 int r = va - vb;
334
335 if (r == 0) {
336 /* The planes have the same passenger capacity. Check mail capacity instead */
337 r = mail_a - mail_b;
338
339 if (r == 0) {
340 /* Use EngineID to sort instead since we want consistent sorting */
341 return EngineNumberSorter(a, b);
342 }
343 }
344 return _engine_sort_direction ? r > 0 : r < 0;
345}
346
349{
350 uint16_t r_a = Engine::Get(a.engine_id)->GetRange();
351 uint16_t r_b = Engine::Get(b.engine_id)->GetRange();
352
353 int r = r_a - r_b;
354
355 /* Use EngineID to sort instead since we want consistent sorting */
356 if (r == 0) return EngineNumberSorter(a, b);
357 return _engine_sort_direction ? r > 0 : r < 0;
358}
359
362std::initializer_list<EngList_SortTypeFunction * const>{
363 /* Trains */
375},
376std::initializer_list<EngList_SortTypeFunction * const>{
377 /* Road vehicles */
389},
390std::initializer_list<EngList_SortTypeFunction * const>{
391 /* Ships */
400},
401std::initializer_list<EngList_SortTypeFunction * const>{
402 /* Aircraft */
412}}};
413
419std::span<EngList_SortTypeFunction * const> GetEngineSortFunctions(VehicleType vehicle_type)
420{
421 assert(IsCompanyBuildableVehicleType(vehicle_type));
422 return _engine_sort_functions[vehicle_type];
423}
424
427std::initializer_list<const StringID>{
428 /* Trains */
429 STR_SORT_BY_ENGINE_ID,
430 STR_SORT_BY_COST,
431 STR_SORT_BY_MAX_SPEED,
432 STR_SORT_BY_POWER,
433 STR_SORT_BY_TRACTIVE_EFFORT,
434 STR_SORT_BY_INTRO_DATE,
435 STR_SORT_BY_NAME,
436 STR_SORT_BY_RUNNING_COST,
437 STR_SORT_BY_POWER_VS_RUNNING_COST,
438 STR_SORT_BY_RELIABILITY,
439 STR_SORT_BY_CARGO_CAPACITY,
440},
441std::initializer_list<const StringID>{
442 /* Road vehicles */
443 STR_SORT_BY_ENGINE_ID,
444 STR_SORT_BY_COST,
445 STR_SORT_BY_MAX_SPEED,
446 STR_SORT_BY_POWER,
447 STR_SORT_BY_TRACTIVE_EFFORT,
448 STR_SORT_BY_INTRO_DATE,
449 STR_SORT_BY_NAME,
450 STR_SORT_BY_RUNNING_COST,
451 STR_SORT_BY_POWER_VS_RUNNING_COST,
452 STR_SORT_BY_RELIABILITY,
453 STR_SORT_BY_CARGO_CAPACITY,
454},
455std::initializer_list<const StringID>{
456 /* Ships */
457 STR_SORT_BY_ENGINE_ID,
458 STR_SORT_BY_COST,
459 STR_SORT_BY_MAX_SPEED,
460 STR_SORT_BY_INTRO_DATE,
461 STR_SORT_BY_NAME,
462 STR_SORT_BY_RUNNING_COST,
463 STR_SORT_BY_RELIABILITY,
464 STR_SORT_BY_CARGO_CAPACITY,
465},
466std::initializer_list<const StringID>{
467 /* Aircraft */
468 STR_SORT_BY_ENGINE_ID,
469 STR_SORT_BY_COST,
470 STR_SORT_BY_MAX_SPEED,
471 STR_SORT_BY_INTRO_DATE,
472 STR_SORT_BY_NAME,
473 STR_SORT_BY_RUNNING_COST,
474 STR_SORT_BY_RELIABILITY,
475 STR_SORT_BY_CARGO_CAPACITY,
476 STR_SORT_BY_RANGE,
477}}};
478
484std::span<StringID const> GetEngineSortNames(VehicleType vehicle_type)
485{
486 assert(IsCompanyBuildableVehicleType(vehicle_type));
487 return _engine_sort_listing[vehicle_type];
488}
489
496static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoType cargo_type)
497{
498 if (cargo_type == CargoFilterCriteria::CF_ANY) {
499 return true;
500 } else if (cargo_type == CargoFilterCriteria::CF_ENGINES) {
501 return Engine::Get(item->engine_id)->GetPower() != 0;
502 } else {
503 CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(item->engine_id, true) & _standard_cargo_mask;
504 return (cargo_type == CargoFilterCriteria::CF_NONE ? refit_mask.None() : refit_mask.Test(cargo_type));
505 }
506}
507
508static GUIEngineList::FilterFunction * const _engine_filter_funcs[] = {
510};
511
512static uint GetCargoWeight(const CargoArray &cap, VehicleType vtype)
513{
514 uint weight = 0;
515 for (CargoType cargo{}; cargo < NUM_CARGO; ++cargo) {
516 if (cap[cargo] != 0) {
517 if (vtype == VehicleType::Train) {
518 weight += CargoSpec::Get(cargo)->WeightOfNUnitsInTrain(cap[cargo]);
519 } else {
520 weight += CargoSpec::Get(cargo)->WeightOfNUnits(cap[cargo]);
521 }
522 }
523 }
524 return weight;
525}
526
527static int DrawCargoCapacityInfo(int left, int right, int y, TestedEngineDetails &te, bool refittable)
528{
529 for (const CargoSpec *cs : _sorted_cargo_specs) {
530 CargoType cargo_type = cs->Index();
531 if (te.all_capacities[cargo_type] == 0) continue;
532
533 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, cargo_type, te.all_capacities[cargo_type], refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
535 }
536
537 return y;
538}
539
540/* Draw rail wagon specific details */
541static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
542{
543 const Engine *e = Engine::Get(engine_number);
544
545 /* Purchase cost */
546 if (te.cost != 0) {
547 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
548 } else {
549 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
550 }
552
553 /* Wagon weight - (including cargo) */
554 uint weight = e->GetDisplayWeight();
555 DrawString(left, right, y,
556 GetString(STR_PURCHASE_INFO_WEIGHT_CWEIGHT, weight, GetCargoWeight(te.all_capacities, VehicleType::Train) + weight));
558
559 /* Wagon speed limit, displayed if above zero */
560 if (_settings_game.vehicle.wagon_speed_limits) {
561 uint max_speed = e->GetDisplayMaxSpeed();
562 if (max_speed > 0) {
563 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED, PackVelocity(max_speed, e->type)));
565 }
566 }
567
568 /* Running cost */
569 if (rvi->running_cost_class != Price::Invalid) {
570 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
572 }
573
574 return y;
575}
576
577/* Draw locomotive specific details */
578static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
579{
580 const Engine *e = Engine::Get(engine_number);
581
582 /* Purchase Cost - Engine weight */
583 if (te.cost != 0) {
584 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_WEIGHT, e->GetCost() + te.cost, te.cost, e->GetDisplayWeight()));
585 } else {
586 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_WEIGHT, e->GetCost(), e->GetDisplayWeight()));
587 }
589
590 /* Supported rail types */
591 std::string railtypes{};
592 std::string_view list_separator = GetListSeparator();
593
594 for (const auto &rt : _sorted_railtypes) {
595 if (!rvi->railtypes.Test(rt)) continue;
596
597 if (!railtypes.empty()) railtypes += list_separator;
598 AppendStringInPlace(railtypes, GetRailTypeInfo(rt)->strings.name);
599 }
600 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_RAILTYPES, railtypes));
602
603 /* Max speed - Engine power */
604 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
606
607 /* Max tractive effort - not applicable if old acceleration or maglev */
608 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
609 bool is_maglev = true;
610 for (RailType rt : rvi->railtypes) {
612 }
613 if (!is_maglev) {
614 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
616 }
617 }
618
619 /* Running cost */
620 if (rvi->running_cost_class != Price::Invalid) {
621 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
623 }
624
625 /* Powered wagons power - Powered wagons extra weight */
626 if (rvi->pow_wag_power != 0) {
627 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, rvi->pow_wag_power, rvi->pow_wag_weight));
629 }
630
631 return y;
632}
633
634/* Draw road vehicle specific details */
635static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
636{
637 const Engine *e = Engine::Get(engine_number);
638
639 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) {
640 /* Purchase Cost */
641 if (te.cost != 0) {
642 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
643 } else {
644 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
645 }
647
648 /* Road vehicle weight - (including cargo) */
649 int16_t weight = e->GetDisplayWeight();
650 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_WEIGHT_CWEIGHT, weight, GetCargoWeight(te.all_capacities, VehicleType::Road) + weight));
652
653 /* Max speed - Engine power */
654 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
656
657 /* Max tractive effort */
658 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
660 } else {
661 /* Purchase cost - Max speed */
662 if (te.cost != 0) {
663 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
664 } else {
665 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
666 }
668 }
669
670 /* Running cost */
671 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
673
674 return y;
675}
676
677/* Draw ship specific details */
678static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
679{
680 const Engine *e = Engine::Get(engine_number);
681
682 /* Purchase cost - Max speed */
683 uint raw_speed = e->GetDisplayMaxSpeed();
684 uint ocean_speed = e->VehInfo<ShipVehicleInfo>().ApplyWaterClassSpeedFrac(raw_speed, true);
685 uint canal_speed = e->VehInfo<ShipVehicleInfo>().ApplyWaterClassSpeedFrac(raw_speed, false);
686
687 if (ocean_speed == canal_speed) {
688 if (te.cost != 0) {
689 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(ocean_speed, e->type)));
690 } else {
691 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(ocean_speed, e->type)));
692 }
694 } else {
695 if (te.cost != 0) {
696 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT, e->GetCost() + te.cost, te.cost));
697 } else {
698 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST, e->GetCost()));
699 }
701
702 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_OCEAN, PackVelocity(ocean_speed, e->type)));
704
705 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_CANAL, PackVelocity(canal_speed, e->type)));
707 }
708
709 /* Cargo type + capacity */
710 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, te.cargo, te.capacity, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
712
713 /* Running cost */
714 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
716
717 return y;
718}
719
730static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
731{
732 const Engine *e = Engine::Get(engine_number);
733
734 /* Purchase cost - Max speed */
735 if (te.cost != 0) {
736 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_REFIT_SPEED, e->GetCost() + te.cost, te.cost, PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
737 } else {
738 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_COST_SPEED, e->GetCost(), PackVelocity(e->GetDisplayMaxSpeed(), e->type)));
739 }
741
742 /* Cargo capacity */
743 if (te.mail_capacity > 0) {
744 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, te.cargo, te.capacity, GetCargoTypeByLabel(CT_MAIL), te.mail_capacity));
745 } else {
746 /* Note, if the default capacity is selected by the refit capacity
747 * callback, then the capacity shown is likely to be incorrect. */
748 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, te.cargo, te.capacity, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY));
749 }
751
752 /* Running cost */
753 DrawString(left, right, y, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR, e->GetRunningCost()));
755
756 /* Aircraft type */
757 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_TYPE, e->GetAircraftTypeText()));
759
760 /* Aircraft range, if available. */
761 uint16_t range = e->GetRange();
762 if (range != 0) {
763 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_AIRCRAFT_RANGE, range));
765 }
766
767 return y;
768}
769
770
776static std::optional<std::string> GetNewGRFAdditionalText(EngineID engine)
777{
778 std::array<int32_t, 16> regs100;
779 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr, regs100);
780 if (callback == CALLBACK_FAILED || callback == 0x400) return std::nullopt;
781 const GRFFile *grffile = Engine::Get(engine)->GetGRF();
782 assert(grffile != nullptr);
783 if (callback == 0x40F) {
784 return GetGRFStringWithTextStack(grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
785 }
786 if (callback > 0x400) {
788 return std::nullopt;
789 }
790
791 return GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, regs100);
792}
793
802static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
803{
804 auto text = GetNewGRFAdditionalText(engine);
805 if (!text) return y;
806 return DrawStringMultiLine(left, right, y, INT32_MAX, *text, TC_BLACK);
807}
808
809void TestedEngineDetails::FillDefaultCapacities(const Engine *e)
810{
811 this->cargo = e->GetDefaultCargoType();
812 if (e->type == VehicleType::Train || e->type == VehicleType::Road) {
814 this->capacity = this->all_capacities[this->cargo];
815 this->mail_capacity = 0;
816 } else {
818 this->all_capacities[this->cargo] = this->capacity;
819 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
820 this->all_capacities[GetCargoTypeByLabel(CT_MAIL)] = this->mail_capacity;
821 } else {
822 this->mail_capacity = 0;
823 }
824 }
825 if (this->all_capacities.GetCount() == 0) this->cargo = INVALID_CARGO;
826}
827
835int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
836{
837 const Engine *e = Engine::Get(engine_number);
838 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
839 bool refittable = IsArticulatedVehicleRefittable(engine_number);
840 bool articulated_cargo = false;
841
842 switch (e->type) {
843 default: NOT_REACHED();
846 y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->VehInfo<RailVehicleInfo>(), te);
847 } else {
848 y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->VehInfo<RailVehicleInfo>(), te);
849 }
850 articulated_cargo = true;
851 break;
852
854 y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te);
855 articulated_cargo = true;
856 break;
857
859 y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te);
860 break;
861
863 y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
864 break;
865 }
866
867 if (articulated_cargo) {
868 /* Cargo type + capacity, or N/A */
869 int new_y = DrawCargoCapacityInfo(left, right, y, te, refittable);
870
871 if (new_y == y) {
872 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_CAPACITY, INVALID_CARGO, 0, STR_EMPTY));
874 } else {
875 y = new_y;
876 }
877 }
878
879 /* Draw details that apply to all types except rail wagons. */
881 /* Design date - Life length */
882 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_DESIGNED_LIFE, ymd.year, TimerGameCalendar::DateToYear(e->GetLifeLengthInDays())));
884
885 /* Reliability */
886 DrawString(left, right, y, GetString(STR_PURCHASE_INFO_RELIABILITY, ToPercent16(e->reliability)));
888 }
889
890 if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
891
892 y = DrawBadgeNameList({left, y, right, INT16_MAX}, e->badges, GetGrfSpecFeature(e->type));
893
894 /* Additional text from NewGRF */
895 y = ShowAdditionalText(left, right, y, engine_number);
896
897 /* The NewGRF's name which the vehicle comes from */
898 const GRFConfig *config = GetGRFConfig(e->GetGRFID());
899 if (_settings_client.gui.show_newgrf_name && config != nullptr)
900 {
901 DrawString(left, right, y, config->GetName(), TC_BLACK);
903 }
904
905 return y;
906}
907
908static void DrawEngineBadgeColumn(const Rect &r, int column_group, const GUIBadgeClasses &badge_classes, const Engine *e, PaletteID remap)
909{
910 DrawBadgeColumn(r, column_group, badge_classes, e->badges, GetGrfSpecFeature(e->type), e->info.base_intro, remap);
911}
912
925void 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)
926{
927 static const VehicleTypeIndexArray<int8_t> sprite_y_offsets = { 0, 0, -1, -1 };
928
929 auto [first, last] = sb.GetVisibleRangeIterators(eng_list);
930
931 bool rtl = _current_text_dir == TD_RTL;
932 int step_size = GetEngineListHeight(type);
933 int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
934 int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
935 int sprite_width = sprite_left + sprite_right;
936 int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
938
939 auto badge_column_widths = badge_classes.GetColumnWidths();
940
941 Rect ir = r.WithHeight(step_size).Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
942 int sprite_y_offset = ScaleSpriteTrad(sprite_y_offsets[type]) + ir.Height() / 2;
943
944 Dimension replace_icon = {0, 0};
945 int count_width = 0;
946 if (show_count) {
947 replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
948
949 uint biggest_num_engines = 0;
950 for (auto it = first; it != last; ++it) {
951 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, it->engine_id);
952 biggest_num_engines = std::max(biggest_num_engines, num_engines);
953 }
954
955 count_width = GetStringBoundingBox(GetString(STR_JUST_COMMA, biggest_num_engines), FontSize::Small).width;
956 }
957
958 const int text_row_height = ir.Shrink(WidgetDimensions::scaled.matrix).Height();
959 const int normal_text_y_offset = (text_row_height - GetCharacterHeight(FontSize::Normal)) / 2;
960 const int small_text_y_offset = text_row_height - GetCharacterHeight(FontSize::Small);
961
962 const int offset = (rtl ? -circle_width : circle_width) / 2;
963 const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
964
965 for (auto it = first; it != last; ++it) {
966 const auto &item = *it;
967 const Engine *e = Engine::Get(item.engine_id);
968
969 uint indent = item.indent * WidgetDimensions::scaled.hsep_indent;
970 bool has_variants = item.flags.Test(EngineDisplayFlag::HasVariants);
971 bool is_folded = item.flags.Test(EngineDisplayFlag::IsFolded);
972 bool shaded = item.flags.Test(EngineDisplayFlag::Shaded);
973
974 Rect textr = ir.Shrink(WidgetDimensions::scaled.matrix);
975 Rect tr = ir.Indent(indent, rtl);
976
977 if (item.indent > 0) {
978 /* Draw tree continuation lines. */
979 int tx = (rtl ? ir.right : ir.left) + offset;
980 for (uint lvl = 1; lvl <= item.indent; ++lvl) {
981 if (HasBit(item.level_mask, lvl)) GfxDrawLine(tx, ir.top, tx, ir.bottom, linecolour, WidgetDimensions::scaled.fullbevel.top);
982 if (lvl < item.indent) tx += level_width;
983 }
984 /* Draw our node in the tree. */
985 int ycentre = CentreBounds(textr.top, textr.bottom, WidgetDimensions::scaled.fullbevel.top);
986 if (!HasBit(item.level_mask, item.indent)) GfxDrawLine(tx, ir.top, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
987 GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
988 }
989
990 if (has_variants) {
991 Rect fr = tr.WithWidth(circle_width, rtl);
992 DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, fr.WithY(textr), SA_CENTER);
993 }
994
995 tr = tr.Indent(circle_width + WidgetDimensions::scaled.hsep_normal, rtl);
996
997 /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
998 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
999 const PaletteID pal = (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(item.engine_id, _local_company);
1000
1001 if (badge_column_widths.size() >= 1 && badge_column_widths[0] > 0) {
1002 Rect br = tr.WithWidth(badge_column_widths[0], rtl);
1003 DrawEngineBadgeColumn(br, 0, badge_classes, e, pal);
1004 tr = tr.Indent(badge_column_widths[0], rtl);
1005 }
1006
1007 int sprite_x = tr.WithWidth(sprite_width, rtl).left + sprite_left;
1008 DrawVehicleEngine(r.left, r.right, sprite_x, tr.top + sprite_y_offset, item.engine_id, pal, EIT_PURCHASE);
1009
1010 tr = tr.Indent(sprite_width + WidgetDimensions::scaled.hsep_wide, rtl);
1011
1012 if (badge_column_widths.size() >= 2 && badge_column_widths[1] > 0) {
1013 Rect br = tr.WithWidth(badge_column_widths[1], rtl);
1014 DrawEngineBadgeColumn(br, 1, badge_classes, e, pal);
1015 tr = tr.Indent(badge_column_widths[1], rtl);
1016 }
1017
1018 if (show_count) {
1019 /* Rect for replace-protection icon. */
1020 Rect rr = tr.WithWidth(replace_icon.width, !rtl);
1021 tr = tr.Indent(replace_icon.width + WidgetDimensions::scaled.hsep_normal, !rtl);
1022 /* Rect for engine type count text. */
1023 Rect cr = tr.WithWidth(count_width, !rtl);
1024 tr = tr.Indent(count_width + WidgetDimensions::scaled.hsep_normal, !rtl);
1025
1026 DrawString(cr.left, cr.right, textr.top + small_text_y_offset, GetString(STR_JUST_COMMA, num_engines), TC_BLACK, SA_RIGHT | SA_FORCE, false, FontSize::Small);
1027
1028 if (EngineHasReplacementForCompany(Company::Get(_local_company), item.engine_id, selected_group)) {
1029 DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr, SA_CENTER);
1030 }
1031 }
1032
1033 if (badge_column_widths.size() >= 3 && badge_column_widths[2] > 0) {
1034 Rect br = tr.WithWidth(badge_column_widths[2], !rtl).Indent(WidgetDimensions::scaled.hsep_wide, rtl);
1035 DrawEngineBadgeColumn(br, 2, badge_classes, e, pal);
1036 tr = tr.Indent(badge_column_widths[2], !rtl);
1037 }
1038
1039 bool hidden = e->company_hidden.Test(_local_company);
1040 StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
1041 TextColour tc = (item.engine_id == selected_id) ? TC_WHITE : ((hidden | shaded) ? (TC_GREY | TC_FORCED | TC_NO_SHADE) : TC_BLACK);
1042
1043 /* Draw the value of the currently selected sort property to the right (or left in RTL), if applicable */
1044 std::string sort_prop_detail;
1045
1046 switch (GetEngineSortNames(type)[sort_criteria]) {
1047 case STR_SORT_BY_ENGINE_ID:
1048 /* No extra interesting info to show in this case */
1049 break;
1050 case STR_SORT_BY_COST:
1051 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_COST, e->GetCost());
1052 break;
1053 case STR_SORT_BY_MAX_SPEED:
1054 if (int max_speed = e->GetDisplayMaxSpeed(); max_speed != 0) {
1055 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_SPEED, PackVelocity(max_speed, Engine::Get(item.engine_id)->type));
1056 }
1057 break;
1058 case STR_SORT_BY_POWER:
1059 if (int power = e->GetPower(); power != 0) {
1060 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_POWER, power);
1061 }
1062 break;
1063 case STR_SORT_BY_TRACTIVE_EFFORT:
1064 /* Allow trucks, and allow trains that are not wagons */
1065 if (type == VehicleType::Road || (type == VehicleType::Train && e->VehInfo<RailVehicleInfo>().railveh_type != RailVehicleType::Wagon)) {
1066 auto max_te = e->GetDisplayMaxTractiveEffort();
1067 if (max_te != 0) {
1068 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_MAX_TE, max_te);
1069 }
1070 }
1071 break;
1072 case STR_SORT_BY_INTRO_DATE: {
1073 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
1074 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_INTRO_DATE, ymd.year);
1075 }
1076 break;
1077 case STR_SORT_BY_NAME:
1078 /* No extra interesting info to show in this case */
1079 break;
1080 case STR_SORT_BY_RUNNING_COST:
1081 if (int running_cost = e->GetRunningCost(); running_cost != 0) {
1082 sort_prop_detail = GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_SORT_DETAILS_RUNNINGCOST_PERIOD : STR_PURCHASE_SORT_DETAILS_RUNNINGCOST_YEAR, running_cost);
1083 }
1084 break;
1085 case STR_SORT_BY_POWER_VS_RUNNING_COST:
1086 /* NOTE: No point showing the actual values of power/running cost, because they are affected by cost factors, which make the math off */
1087 if (Money rc = e->GetRunningCost(); rc != 0) {
1088 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_POWER_VS_RUNNING_COST, 100 * e->GetPower() / rc, /* digits for DECIMAL */ 2);
1089 }
1090 break;
1091 case STR_SORT_BY_RELIABILITY:
1092 if (auto isWagon = e->type == VehicleType::Train && e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Wagon; !isWagon) {
1093 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_RELIABILITY, ToPercent16(e->reliability));
1094 }
1095 break;
1096 case STR_SORT_BY_CARGO_CAPACITY: {
1097 uint total_capacity;
1098 switch (type) {
1099 case VehicleType::Train:
1100 total_capacity = GetTotalCapacityOfArticulatedParts(item.engine_id) * (e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Multihead ? 2 : 1);
1101 break;
1102 case VehicleType::Road:
1103 total_capacity = GetTotalCapacityOfArticulatedParts(item.engine_id);
1104 break;
1105 case VehicleType::Ship:
1106 total_capacity = e->GetDisplayDefaultCapacity();
1107 break;
1108 case VehicleType::Aircraft: {
1109 uint16_t mail_cap;
1110 int aircraft_cap = e->GetDisplayDefaultCapacity(&mail_cap);
1111 total_capacity = aircraft_cap + mail_cap;
1112 }
1113 break;
1114 default:
1115 NOT_REACHED();
1116 break;
1117 }
1118 if (total_capacity != 0) {
1119 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_CAPACITY, total_capacity);
1120 }
1121 }
1122 break;
1123 case STR_SORT_BY_RANGE:
1124 if (e->type == VehicleType::Aircraft) {
1125 if (uint16_t range = e->GetRange(); range != 0) {
1126 sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_AIRCRAFT_RANGE, range);
1127 }
1128 }
1129 break;
1130 default:
1131 break;
1132 }
1133
1134 int sort_detail_width = 0;
1135 if (!sort_prop_detail.empty()) {
1136 DrawString(tr.left, tr.right, textr.top + normal_text_y_offset, sort_prop_detail, tc, SA_RIGHT, false, FontSize::Small);
1137
1138 /* If we have sort detail to show, also measure its width so that we can adjust the
1139 * main name drawing rectangle to not overlap. */
1140 sort_detail_width = GetStringBoundingBox(sort_prop_detail, FontSize::Small).width;
1141 }
1142
1143 /* If the count is visible then this is part of in-use autoreplace list. */
1144 auto engine_name = PackEngineNameDParam(item.engine_id, show_count ? EngineNameContext::AutoreplaceVehicleInUse : EngineNameContext::PurchaseList, item.indent);
1145 std::string name = GetString(str, engine_name);
1146
1147 /* The left/right bounds are adjusted to not overlap with the sort detail that is on the left/right depending on the RTL setting. */
1148 DrawString(tr.left + (rtl ? sort_detail_width : 0), tr.right - (rtl ? 0 : sort_detail_width), textr.top + normal_text_y_offset, name, tc);
1149
1150 ir = ir.Translate(0, step_size);
1151 }
1152}
1153
1161void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button)
1162{
1163 uint32_t hidden_mask = 0;
1164 /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
1165 if (vehicle_type == VehicleType::Road && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
1166 SetBit(hidden_mask, 3); // power
1167 SetBit(hidden_mask, 4); // tractive effort
1168 SetBit(hidden_mask, 8); // power by running costs
1169 }
1170 /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
1171 if (vehicle_type == VehicleType::Train && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
1172 SetBit(hidden_mask, 4); // tractive effort
1173 }
1174 ShowDropDownMenu(w, GetEngineSortNames(vehicle_type), selected, button, 0, hidden_mask);
1175}
1176
1184void GUIEngineListAddChildren(GUIEngineList &dst, const GUIEngineList &src, EngineID parent, uint8_t indent)
1185{
1186 for (const auto &item : src) {
1187 if (item.variant_id != parent || item.engine_id == parent) continue;
1188
1189 const Engine *e = Engine::Get(item.engine_id);
1190 EngineDisplayFlags flags = item.flags;
1191 if (e->display_last_variant != EngineID::Invalid()) flags.Reset(EngineDisplayFlag::Shaded);
1192 dst.emplace_back(e->display_last_variant == EngineID::Invalid() ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent);
1193
1194 /* Add variants if not folded */
1195 if (item.flags.Test(EngineDisplayFlag::HasVariants) && !item.flags.Test(EngineDisplayFlag::IsFolded)) {
1196 /* Add this engine again as a child */
1197 if (!item.flags.Test(EngineDisplayFlag::Shaded)) {
1198 dst.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags{}, indent + 1);
1199 }
1200 GUIEngineListAddChildren(dst, src, item.engine_id, indent + 1);
1201 }
1202 }
1203
1204 if (indent > 0 || dst.empty()) return;
1205
1206 /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
1207 uint16_t level_mask = 0;
1208 for (auto it = std::rbegin(dst); std::next(it) != std::rend(dst); ++it) {
1209 auto next_it = std::next(it);
1210 SB(level_mask, it->indent, 1, it->indent <= next_it->indent);
1211 next_it->level_mask = level_mask;
1212 }
1213}
1214
1216struct BuildVehicleWindow : Window {
1218 union {
1223 uint8_t sort_criteria = 0;
1224 bool show_hidden_engines = false;
1225 bool listview_mode = false;
1226 EngineID sel_engine = EngineID::Invalid();
1227 EngineID rename_engine = EngineID::Invalid();
1228 GUIEngineList eng_list{};
1231 Scrollbar *vscroll = nullptr;
1233 GUIBadgeClasses badge_classes{};
1234
1235 static constexpr int BADGE_COLUMNS = 3;
1236
1239
1240 std::pair<WidgetID, WidgetID> badge_filters{};
1241 BadgeFilterChoices badge_filter_choices{};
1242
1243 void SetBuyVehicleText()
1244 {
1245 NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
1246
1248 if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter_criteria;
1249
1250 if (refit) {
1251 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));
1252 } else {
1253 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));
1254 }
1255 }
1256
1258 {
1259 this->vehicle_type = type;
1260 this->listview_mode = tile == INVALID_TILE;
1261 this->window_number = this->listview_mode ? (int)type : tile.base();
1262
1266
1267 this->UpdateFilterByTile();
1268
1269 this->CreateNestedTree();
1270
1271 this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR);
1272
1273 /* If we are just viewing the list of vehicles, we do not need the Build button.
1274 * So we just hide it, and enlarge the Rename button by the now vacant place. */
1275 if (this->listview_mode) this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
1276
1277 NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_LIST);
1278 widget->SetToolTip(STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + to_underlying(type));
1279
1281 widget->SetToolTip(STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + to_underlying(type));
1282
1283 widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
1284 widget->SetStringTip(STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + to_underlying(type), STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + to_underlying(type));
1285
1287 widget->SetStringTip(STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + to_underlying(type), STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + to_underlying(type));
1288 widget->SetLowered(this->show_hidden_engines);
1289
1290 this->details_height = ((this->vehicle_type == VehicleType::Train) ? 10 : 9);
1291
1292 if (tile == INVALID_TILE) {
1293 this->FinishInitNested(type);
1294 } else {
1295 this->FinishInitNested(tile);
1296 }
1297
1299 this->vehicle_editbox.cancel_button = QueryString::ACTION_CLEAR;
1300
1301 this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
1302
1303 this->eng_list.ForceRebuild();
1304 this->GenerateBuildList(); // generate the list, since we need it in the next line
1305
1306 /* Select the first unshaded engine in the list as default when opening the window */
1307 EngineID engine = EngineID::Invalid();
1308 auto it = std::ranges::find_if(this->eng_list, [](const GUIEngineListItem &item) { return !item.flags.Test(EngineDisplayFlag::Shaded); });
1309 if (it != this->eng_list.end()) engine = it->engine_id;
1310 this->SelectEngine(engine);
1311 }
1312
1315 {
1316 switch (this->vehicle_type) {
1317 default: NOT_REACHED();
1318 case VehicleType::Train:
1319 if (this->listview_mode) {
1320 this->filter.railtype = INVALID_RAILTYPE;
1321 } else {
1322 this->filter.railtype = GetRailType(this->window_number);
1323 }
1324 break;
1325
1326 case VehicleType::Road:
1327 if (this->listview_mode) {
1328 this->filter.roadtype = INVALID_ROADTYPE;
1329 } else {
1330 this->filter.roadtype = GetRoadTypeRoad(this->window_number);
1331 if (this->filter.roadtype == INVALID_ROADTYPE) {
1332 this->filter.roadtype = GetRoadTypeTram(this->window_number);
1333 }
1334 }
1335 break;
1336
1337 case VehicleType::Ship:
1339 break;
1340 }
1341 }
1342
1343 StringID GetCargoFilterLabel(CargoType cargo_type) const
1344 {
1345 switch (cargo_type) {
1346 case CargoFilterCriteria::CF_ANY: return STR_PURCHASE_INFO_ALL_TYPES;
1347 case CargoFilterCriteria::CF_ENGINES: return STR_PURCHASE_INFO_ENGINES_ONLY;
1348 case CargoFilterCriteria::CF_NONE: return STR_PURCHASE_INFO_NONE;
1349 default: return CargoSpec::Get(cargo_type)->name;
1350 }
1351 }
1352
1355 {
1356 /* Set the last cargo filter criteria. */
1357 this->cargo_filter_criteria = _engine_sort_last_cargo_criteria[this->vehicle_type];
1358 if (this->cargo_filter_criteria < NUM_CARGO && !_standard_cargo_mask.Test(this->cargo_filter_criteria)) this->cargo_filter_criteria = CargoFilterCriteria::CF_ANY;
1359
1360 this->eng_list.SetFilterFuncs(_engine_filter_funcs);
1361 this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
1362 }
1363
1364 void SelectEngine(EngineID engine)
1365 {
1366 CargoType cargo = this->cargo_filter_criteria;
1367 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1368
1369 this->sel_engine = engine;
1370 this->SetBuyVehicleText();
1371
1372 if (this->sel_engine == EngineID::Invalid()) return;
1373
1374 const Engine *e = Engine::Get(this->sel_engine);
1375
1376 if (!this->listview_mode) {
1377 /* Query for cost and refitted capacity */
1378 auto [ret, veh_id, refit_capacity, refit_mail, cargo_capacities] = Command<Commands::BuildVehicle>::Do(DoCommandFlag::QueryCost, TileIndex(this->window_number), this->sel_engine, true, cargo, INVALID_CLIENT_ID);
1379 if (ret.Succeeded()) {
1380 this->te.cost = ret.GetCost() - e->GetCost();
1381 this->te.capacity = refit_capacity;
1382 this->te.mail_capacity = refit_mail;
1383 this->te.cargo = !IsValidCargoType(cargo) ? e->GetDefaultCargoType() : cargo;
1384 this->te.all_capacities = cargo_capacities;
1385 return;
1386 }
1387 }
1388
1389 /* Purchase test was not possible or failed, fill in the defaults instead. */
1390 this->te.cost = 0;
1391 this->te.FillDefaultCapacities(e);
1392 }
1393
1394 void OnInit() override
1395 {
1396 this->badge_classes = GUIBadgeClasses(GetGrfSpecFeature(this->vehicle_type));
1397 this->SetCargoFilterArray();
1398
1399 this->badge_filters = AddBadgeDropdownFilters(this, WID_BV_BADGE_FILTER, WID_BV_BADGE_FILTER, Colours::Grey, GetGrfSpecFeature(this->vehicle_type));
1400
1401 this->widget_lookup.clear();
1402 this->nested_root->FillWidgetLookup(this->widget_lookup);
1403 }
1404
1407 {
1408 this->eng_list.Filter(this->cargo_filter_criteria);
1409 if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
1410 this->SelectEngine(EngineID::Invalid());
1411 } 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
1412 this->SelectEngine(this->eng_list[0].engine_id);
1413 }
1414 }
1415
1422 {
1423 GUIEngineListItem item = {eid, eid, EngineDisplayFlags{}, 0};
1424 return CargoAndEngineFilter(&item, this->cargo_filter_criteria);
1425 }
1426
1432 bool FilterByText(const Engine *e)
1433 {
1434 /* Do not filter if the filter text box is empty */
1435 if (this->string_filter.IsEmpty()) return true;
1436
1437 /* Filter engine name */
1438 this->string_filter.ResetState();
1439 this->string_filter.AddLine(GetString(STR_ENGINE_NAME, PackEngineNameDParam(e->index, EngineNameContext::PurchaseList)));
1440
1441 /* Filter NewGRF extra text */
1442 auto text = GetNewGRFAdditionalText(e->index);
1443 if (text) this->string_filter.AddLine(*text);
1444
1445 return this->string_filter.GetState();
1446 }
1447
1448 /* Figure out what train EngineIDs to put in the list */
1449 void GenerateBuildTrainList(GUIEngineList &list)
1450 {
1451 FlatSet<EngineID> variants;
1452 EngineID sel_id = EngineID::Invalid();
1453 size_t num_engines = 0;
1454
1455 list.clear();
1456
1457 BadgeTextFilter btf(this->string_filter, GrfSpecFeature::Trains);
1458 BadgeDropdownFilter bdf(this->badge_filter_choices);
1459
1460 /* Make list of all available train engines and wagons.
1461 * Also check to see if the previously selected engine is still available,
1462 * and if not, reset selection to EngineID::Invalid(). This could be the case
1463 * when engines become obsolete and are removed */
1465 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1466 EngineID eid = e->index;
1467 const RailVehicleInfo *rvi = &e->VehInfo<RailVehicleInfo>();
1468
1469 if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtypes, this->filter.railtype)) continue;
1471
1472 /* Filter now! So num_engines and num_wagons is valid */
1473 if (!FilterSingleEngine(eid)) continue;
1474
1475 if (!bdf.Filter(e->badges)) continue;
1476
1477 /* Filter by name or NewGRF extra text */
1478 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1479
1480 list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1481
1482 if (rvi->railveh_type != RailVehicleType::Wagon) num_engines++;
1483
1484 /* Add all parent variants of this engine to the variant list */
1485 EngineID parent = e->info.variant_id;
1486 while (parent != EngineID::Invalid() && variants.insert(parent).second) {
1487 parent = Engine::Get(parent)->info.variant_id;
1488 }
1489
1490 if (eid == this->sel_engine) sel_id = eid;
1491 }
1492
1493 /* ensure primary engine of variant group is in list */
1494 for (const auto &variant : variants) {
1495 if (std::ranges::find(list, variant, &GUIEngineListItem::engine_id) == list.end()) {
1496 const Engine *e = Engine::Get(variant);
1497 list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1498 if (e->VehInfo<RailVehicleInfo>().railveh_type != RailVehicleType::Wagon) num_engines++;
1499 }
1500 }
1501
1502 this->SelectEngine(sel_id);
1503
1504 /* invalidate cached values for name sorter - engine names could change */
1505 _last_engine[0] = _last_engine[1] = EngineID::Invalid();
1506
1507 /* make engines first, and then wagons, sorted by selected sort_criteria */
1508 _engine_sort_direction = false;
1510
1511 /* and then sort engines */
1513 EngList_SortPartial(list, GetEngineSortFunctions(this->vehicle_type)[this->sort_criteria], 0, num_engines);
1514
1515 /* and finally sort wagons */
1516 EngList_SortPartial(list, GetEngineSortFunctions(this->vehicle_type)[this->sort_criteria], num_engines, list.size() - num_engines);
1517 }
1518
1521 {
1522 EngineID sel_id = EngineID::Invalid();
1523
1524 this->eng_list.clear();
1525
1526 BadgeTextFilter btf(this->string_filter, GrfSpecFeature::RoadVehicles);
1527 BadgeDropdownFilter bdf(this->badge_filter_choices);
1528
1529 for (const Engine *e : Engine::IterateType(VehicleType::Road)) {
1530 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1531 EngineID eid = e->index;
1533 if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->VehInfo<RoadVehicleInfo>().roadtype, this->filter.roadtype)) continue;
1534 if (!bdf.Filter(e->badges)) continue;
1535
1536 /* Filter by name or NewGRF extra text */
1537 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1538
1539 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1540
1541 if (eid == this->sel_engine) sel_id = eid;
1542 }
1543 this->SelectEngine(sel_id);
1544 }
1545
1548 {
1549 EngineID sel_id = EngineID::Invalid();
1550 this->eng_list.clear();
1551
1552 BadgeTextFilter btf(this->string_filter, GrfSpecFeature::Ships);
1553 BadgeDropdownFilter bdf(this->badge_filter_choices);
1554
1555 for (const Engine *e : Engine::IterateType(VehicleType::Ship)) {
1556 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1557 EngineID eid = e->index;
1559 if (!bdf.Filter(e->badges)) continue;
1560
1561 /* Filter by name or NewGRF extra text */
1562 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1563
1564 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1565
1566 if (eid == this->sel_engine) sel_id = eid;
1567 }
1568 this->SelectEngine(sel_id);
1569 }
1570
1573 {
1574 EngineID sel_id = EngineID::Invalid();
1575
1576 this->eng_list.clear();
1577
1578 const Station *st = this->listview_mode ? nullptr : Station::GetByTile(TileIndex(this->window_number));
1579
1580 BadgeTextFilter btf(this->string_filter, GrfSpecFeature::Aircraft);
1581 BadgeDropdownFilter bdf(this->badge_filter_choices);
1582
1583 /* Make list of all available planes.
1584 * Also check to see if the previously selected plane is still available,
1585 * and if not, reset selection to EngineID::Invalid(). This could be the case
1586 * when planes become obsolete and are removed */
1588 if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
1589 EngineID eid = e->index;
1591 /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
1592 if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
1593 if (!bdf.Filter(e->badges)) continue;
1594
1595 /* Filter by name or NewGRF extra text */
1596 if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
1597
1598 this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);
1599
1600 if (eid == this->sel_engine) sel_id = eid;
1601 }
1602
1603 this->SelectEngine(sel_id);
1604 }
1605
1608 {
1609 if (!this->eng_list.NeedRebuild()) return;
1610
1611 /* Update filter type in case the road/railtype of the depot got converted */
1612 this->UpdateFilterByTile();
1613
1614 this->eng_list.clear();
1615
1616 GUIEngineList list;
1617
1618 switch (this->vehicle_type) {
1619 default: NOT_REACHED();
1620 case VehicleType::Train:
1621 this->GenerateBuildTrainList(list);
1622 GUIEngineListAddChildren(this->eng_list, list);
1623 this->eng_list.RebuildDone();
1624 return;
1625 case VehicleType::Road:
1627 break;
1628 case VehicleType::Ship:
1629 this->GenerateBuildShipList();
1630 break;
1633 break;
1634 }
1635
1636 this->FilterEngineList();
1637
1638 /* ensure primary engine of variant group is in list after filtering */
1639 FlatSet<EngineID> variants;
1640 for (const auto &item : this->eng_list) {
1641 EngineID parent = item.variant_id;
1642 while (parent != EngineID::Invalid() && variants.insert(parent).second) {
1643 parent = Engine::Get(parent)->info.variant_id;
1644 }
1645 }
1646
1647 for (const auto &variant : variants) {
1648 if (std::ranges::find(this->eng_list, variant, &GUIEngineListItem::engine_id) == this->eng_list.end()) {
1649 const Engine *e = Engine::Get(variant);
1650 this->eng_list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
1651 }
1652 }
1653
1654 _engine_sort_direction = this->descending_sort_order;
1655 EngList_Sort(this->eng_list, GetEngineSortFunctions(this->vehicle_type)[this->sort_criteria]);
1656
1657 this->eng_list.swap(list);
1658 GUIEngineListAddChildren(this->eng_list, list, EngineID::Invalid(), 0);
1659 this->eng_list.RebuildDone();
1660 }
1661
1662 DropDownList BuildCargoDropDownList() const
1663 {
1664 DropDownList list;
1665
1666 /* Add item for disabling filtering. */
1667 list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY));
1668 /* Specific filters for trains. */
1669 if (this->vehicle_type == VehicleType::Train) {
1670 /* Add item for locomotives only in case of trains. */
1672 /* Add item for vehicles not carrying anything, e.g. train engines.
1673 * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
1675 }
1676
1677 /* Add cargos */
1678 Dimension d = GetLargestCargoIconSize();
1679 for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
1680 list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index()));
1681 }
1682
1683 return list;
1684 }
1685
1686 DropDownList BuildBadgeConfigurationList() const
1687 {
1688 static const auto separators = {STR_BADGE_CONFIG_PREVIEW, STR_BADGE_CONFIG_NAME};
1689 return BuildBadgeClassConfigurationList(this->badge_classes, BADGE_COLUMNS, separators, Colours::Grey);
1690 }
1691
1692 void BuildVehicle()
1693 {
1694 EngineID sel_eng = this->sel_engine;
1695 if (sel_eng == EngineID::Invalid()) return;
1696
1697 CargoType cargo = this->cargo_filter_criteria;
1698 if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
1699 if (this->vehicle_type == VehicleType::Train && RailVehInfo(sel_eng)->railveh_type == RailVehicleType::Wagon) {
1700 Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1701 } else {
1702 Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
1703 }
1704
1705 /* Update last used variant in hierarchy and refresh if necessary. */
1706 bool refresh = false;
1707 EngineID parent = sel_eng;
1708 while (parent != EngineID::Invalid()) {
1709 Engine *e = Engine::Get(parent);
1710 refresh |= (e->display_last_variant != sel_eng);
1711 e->display_last_variant = sel_eng;
1712 parent = e->info.variant_id;
1713 }
1714
1715 if (refresh) {
1716 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1717 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1718 }
1719 }
1720
1721 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1722 {
1723 switch (widget) {
1725 this->descending_sort_order ^= true;
1726 _engine_sort_last_order[this->vehicle_type] = this->descending_sort_order;
1727 this->eng_list.ForceRebuild();
1728 this->SetDirty();
1729 break;
1730
1732 this->show_hidden_engines ^= true;
1733 _engine_sort_show_hidden_engines[this->vehicle_type] = this->show_hidden_engines;
1734 this->eng_list.ForceRebuild();
1735 this->SetWidgetLoweredState(widget, this->show_hidden_engines);
1736 this->SetDirty();
1737 break;
1738
1739 case WID_BV_LIST: {
1740 EngineID e = EngineID::Invalid();
1741 const auto it = this->vscroll->GetScrolledItemFromWidget(this->eng_list, pt.y, this, WID_BV_LIST);
1742 if (it != this->eng_list.end()) {
1743 const auto &item = *it;
1744 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);
1745 if (item.flags.Test(EngineDisplayFlag::HasVariants) && IsInsideMM(r.left, r.right, pt.x)) {
1746 /* toggle folded flag on engine */
1747 assert(item.variant_id != EngineID::Invalid());
1748 Engine *engine = Engine::Get(item.variant_id);
1750
1751 InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
1752 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
1753 return;
1754 }
1755 if (!item.flags.Test(EngineDisplayFlag::Shaded)) e = item.engine_id;
1756 }
1757 this->SelectEngine(e);
1758 this->SetDirty();
1759 if (_ctrl_pressed) {
1760 this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
1761 } else if (click_count > 1 && !this->listview_mode) {
1762 this->OnClick(pt, WID_BV_BUILD, 1);
1763 }
1764 break;
1765 }
1766
1767 case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
1768 DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
1769 break;
1770
1771 case WID_BV_CARGO_FILTER_DROPDOWN: { // Select cargo filtering criteria dropdown menu
1772 static std::string cargo_filter;
1773 ShowDropDownList(this, this->BuildCargoDropDownList(), this->cargo_filter_criteria, widget, 0, DropDownOption::Filterable, &cargo_filter);
1774 break;
1775 }
1776
1778 if (this->badge_classes.GetClasses().empty()) break;
1779 ShowDropDownList(this, this->BuildBadgeConfigurationList(), -1, widget, 0, DropDownOption::Persist);
1780 break;
1781
1782 case WID_BV_SHOW_HIDE: {
1783 const Engine *e = (this->sel_engine == EngineID::Invalid()) ? nullptr : Engine::Get(this->sel_engine);
1784 if (e != nullptr) {
1785 Command<Commands::SetVehicleVisibility>::Post(this->sel_engine, !e->IsHidden(_current_company));
1786 }
1787 break;
1788 }
1789
1790 case WID_BV_BUILD:
1791 this->BuildVehicle();
1792 break;
1793
1794 case WID_BV_RENAME: {
1795 EngineID sel_eng = this->sel_engine;
1796 if (sel_eng != EngineID::Invalid()) {
1797 this->rename_engine = sel_eng;
1799 }
1800 break;
1801 }
1802
1803 default:
1804 if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
1805 PaletteID palette = SPR_2CCMAP_BASE + Company::Get(_local_company)->GetCompanyRecolourOffset(LS_DEFAULT);
1806 ShowDropDownList(this, this->GetWidget<NWidgetBadgeFilter>(widget)->GetDropDownList(palette), -1, widget, 0, DropDownOption::Filterable);
1807 }
1808 break;
1809 }
1810 }
1811
1817 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1818 {
1819 if (!gui_scope) return;
1820 /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
1821 if (this->vehicle_type == VehicleType::Road &&
1822 _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL &&
1823 this->sort_criteria > 7) {
1824 this->sort_criteria = 0;
1826 }
1827 this->eng_list.ForceRebuild();
1828 }
1829
1830 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1831 {
1832 switch (widget) {
1833 case WID_BV_CAPTION:
1834 if (this->vehicle_type == VehicleType::Train && !this->listview_mode) {
1835 const RailTypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
1836 return GetString(rti->strings.build_caption);
1837 }
1838 if (this->vehicle_type == VehicleType::Road && !this->listview_mode) {
1839 const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype);
1840 return GetString(rti->strings.build_caption);
1841 }
1842 return GetString((this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + to_underlying(this->vehicle_type));
1843
1845 return GetString(GetEngineSortNames(this->vehicle_type)[this->sort_criteria]);
1846
1848 return GetString(this->GetCargoFilterLabel(this->cargo_filter_criteria));
1849
1850 case WID_BV_SHOW_HIDE: {
1851 const Engine *e = (this->sel_engine == EngineID::Invalid()) ? nullptr : Engine::Get(this->sel_engine);
1852 if (e != nullptr && e->IsHidden(_local_company)) {
1853 return GetString(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + to_underlying(this->vehicle_type));
1854 }
1855 return GetString(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + to_underlying(this->vehicle_type));
1856 }
1857
1858 default:
1859 if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
1860 return this->GetWidget<NWidgetBadgeFilter>(widget)->GetStringParameter(this->badge_filter_choices);
1861 }
1862
1863 return this->Window::GetWidgetString(widget, stringid);
1864 }
1865 }
1866
1867 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1868 {
1869 switch (widget) {
1870 case WID_BV_LIST:
1871 fill.height = resize.height = GetEngineListHeight(this->vehicle_type);
1872 size.height = 3 * resize.height;
1873 size.width = std::max(size.width, this->badge_classes.GetTotalColumnsWidth() + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165) + padding.width;
1874 break;
1875
1876 case WID_BV_PANEL:
1877 size.height = GetCharacterHeight(FontSize::Normal) * this->details_height + padding.height;
1878 break;
1879
1882 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
1883 d.height += padding.height;
1884 size = maxdim(size, d);
1885 break;
1886 }
1887
1889 size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList()).width + padding.width);
1890 break;
1891
1893 /* Hide the configuration button if no configurable badges are present. */
1894 if (this->badge_classes.GetClasses().empty()) size = {0, 0};
1895 break;
1896
1897 case WID_BV_BUILD:
1898 size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + to_underlying(this->vehicle_type));
1899 size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + to_underlying(this->vehicle_type)));
1900 size.width += padding.width;
1901 size.height += padding.height;
1902 break;
1903
1904 case WID_BV_SHOW_HIDE:
1905 size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + to_underlying(this->vehicle_type));
1906 size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + to_underlying(this->vehicle_type)));
1907 size.width += padding.width;
1908 size.height += padding.height;
1909 break;
1910 }
1911 }
1912
1913 void DrawWidget(const Rect &r, WidgetID widget) const override
1914 {
1915 switch (widget) {
1916 case WID_BV_LIST:
1918 this->vehicle_type,
1919 r,
1920 this->eng_list,
1921 *this->vscroll,
1922 this->sel_engine,
1923 false,
1925 this->badge_classes,
1926 this->sort_criteria
1927 );
1928 break;
1929
1931 this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
1932 break;
1933 }
1934 }
1935
1936 void OnPaint() override
1937 {
1938 this->GenerateBuildList();
1939 this->vscroll->SetCount(this->eng_list.size());
1940
1941 this->SetWidgetsDisabledState(this->sel_engine == EngineID::Invalid(), WID_BV_SHOW_HIDE, WID_BV_BUILD);
1942
1943 /* Disable renaming engines in network games if you are not the server. */
1944 this->SetWidgetDisabledState(WID_BV_RENAME, this->sel_engine == EngineID::Invalid() || (_networking && !_network_server));
1945
1946 this->DrawWidgets();
1947
1948 if (!this->IsShaded()) {
1949 int needed_height = this->details_height;
1950 /* Draw details panels. */
1951 if (this->sel_engine != EngineID::Invalid()) {
1952 const Rect r = this->GetWidget<NWidgetBase>(WID_BV_PANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1953 int text_end = DrawVehiclePurchaseInfo(r.left, r.right, r.top, this->sel_engine, this->te);
1954 needed_height = std::max(needed_height, (text_end - r.top) / GetCharacterHeight(FontSize::Normal));
1955 }
1956 if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
1957 int resize = needed_height - this->details_height;
1958 this->details_height = needed_height;
1959 this->ReInit(0, resize * GetCharacterHeight(FontSize::Normal));
1960 return;
1961 }
1962 }
1963 }
1964
1965 void OnQueryTextFinished(std::optional<std::string> str) override
1966 {
1967 if (!str.has_value()) return;
1968
1969 Command<Commands::RenameEngine>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + to_underlying(this->vehicle_type), this->rename_engine, *str);
1970 }
1971
1972 void OnDropdownSelect(WidgetID widget, int index, int click_result) override
1973 {
1974 switch (widget) {
1976 if (this->sort_criteria != index) {
1977 this->sort_criteria = index;
1978 _engine_sort_last_criteria[this->vehicle_type] = this->sort_criteria;
1979 this->eng_list.ForceRebuild();
1980 }
1981 break;
1982
1983 case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
1984 if (this->cargo_filter_criteria != index) {
1985 this->cargo_filter_criteria = static_cast<CargoType>(index);
1986 _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter_criteria;
1987 /* deactivate filter if criteria is 'Show All', activate it otherwise */
1988 this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
1989 this->eng_list.ForceRebuild();
1990 this->SelectEngine(this->sel_engine);
1991 }
1992 break;
1993
1995 bool reopen = HandleBadgeConfigurationDropDownClick(GetGrfSpecFeature(this->vehicle_type), BADGE_COLUMNS, index, click_result, this->badge_filter_choices);
1996
1997 this->ReInit();
1998
1999 if (reopen) {
2000 ReplaceDropDownList(this, this->BuildBadgeConfigurationList(), -1);
2001 } else {
2003 }
2004
2005 /* We need to refresh if a filter is removed. */
2006 this->eng_list.ForceRebuild();
2007 break;
2008 }
2009
2010 default:
2011 if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
2012 if (index < 0) {
2013 ResetBadgeFilter(this->badge_filter_choices, this->GetWidget<NWidgetBadgeFilter>(widget)->GetBadgeClassID());
2014 } else {
2015 SetBadgeFilter(this->badge_filter_choices, BadgeID(index));
2016 }
2017 this->eng_list.ForceRebuild();
2018 }
2019 break;
2020 }
2021 this->SetDirty();
2022 }
2023
2024 void OnResize() override
2025 {
2026 this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
2027 }
2028
2029 void OnEditboxChanged(WidgetID wid) override
2030 {
2031 if (wid == WID_BV_FILTER) {
2032 this->string_filter.SetFilterTerm(this->vehicle_editbox.text.GetText());
2033 this->InvalidateData();
2034 }
2035 }
2036
2037 static inline HotkeyList hotkeys{"buildvehicle", {
2038 Hotkey('F', "focus_filter_box", WID_BV_FILTER),
2039 }};
2040};
2041
2044 WindowPosition::Automatic, "build_vehicle", 240, 268,
2047 _nested_build_vehicle_widgets,
2048 &BuildVehicleWindow::hotkeys
2049);
2050
2051void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
2052{
2053 /* We want to be able to open both Available Train as Available Ships,
2054 * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number.
2055 * As it always is a low value, it won't collide with any real tile
2056 * number. */
2057 uint num = (tile == INVALID_TILE) ? (int)type : tile.base();
2058
2059 assert(IsCompanyBuildableVehicleType(type));
2060
2062
2063 new BuildVehicleWindow(_build_vehicle_desc, tile, type);
2064}
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.
static WindowDesc _build_vehicle_desc(WindowPosition::Automatic, "build_vehicle", 240, 268, WC_BUILD_VEHICLE, WC_NONE, WindowDefaultFlag::Construction, _nested_build_vehicle_widgets, &BuildVehicleWindow::hotkeys)
Window definition for the build vehicle window.
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 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
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:493
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition engine.cpp:415
uint16_t GetRange() const
Get the range of an aircraft type.
Definition engine.cpp:478
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:182
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:343
TimerGameCalendar::Date intro_date
Date of introduction of the engine.
Definition engine_base.h:46
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
uint GetDisplayMaxSpeed() const
Returns max speed of the engine for display purposes.
Definition engine.cpp:383
EngineDisplayFlags display_flags
NOSAVE client-side-only display flags for build engine list.
Definition engine_base.h:64
uint GetDisplayWeight() const
Returns the weight of the engine for display purposes.
Definition engine.cpp:433
VehicleType type
Vehicle type, ie VehicleType::Road, VehicleType::Train, etc.
Definition engine_base.h:62
bool IsVariantHidden(CompanyID c) const
Check whether the engine variant chain is hidden in the GUI for the given company.
Definition engine.cpp:513
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:468
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity=nullptr) const
Determines the default cargo capacity of an engine for display purposes.
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
CompanyMask company_hidden
Bit for each company whether the engine is normally hidden in the build gui for that company.
Definition engine_base.h:41
Money GetRunningCost() const
Return how much the running costs of this engine are.
Definition engine.cpp:306
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:49
uint GetDisplayMaxTractiveEffort() const
Returns the tractive effort of the engine for display purposes.
Definition engine.cpp:451
bool IsHidden(CompanyID c) const
Check whether the engine is hidden in the GUI for the given company.
EngineID display_last_variant
NOSAVE client-side-only last variant selected.
Definition engine_base.h:65
Flat set implementation that uses a sorted vector for storage.
std::pair< const_iterator, bool > insert(const Tkey &key)
Insert a key into the set, if it does not already exist.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void 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:1255
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:1195
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:115
struct RailTypeInfo::@157247141350136173143103254227157213063052244122 strings
Strings associated with the rail type.
VehicleAccelerationModel acceleration_type
Acceleration type of this rail type.
Definition rail.h:215
StringID name
Name of this rail type.
Definition rail.h:165
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition rail.h:168
struct RoadTypeInfo::@070000167274302256150317022075324310363002361255 strings
Strings associated with the rail type.
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition road.h:80
Scrollbar data structure.
void SetCount(size_t num)
Sets the number of elements in the list.
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition widget.cpp:2532
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:1274
Base class for engines.
@ HasVariants
Set if engine has variants.
Definition engine_base.h:28
@ IsFolded
Set if display of variants should be folded (hidden).
Definition engine_base.h:29
@ Shaded
Set if engine should be masked.
Definition engine_base.h:30
Command definitions related to engines.
Functions related to engines.
uint GetTotalCapacityOfArticulatedParts(EngineID engine)
Get the capacity of an engine with articulated parts.
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare)
Sort all items using quick sort and given 'CompareItems' function.
void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items)
Sort selected range of items (on indices @ <begin, begin+num_items-1>).
void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
Draw an engine.
Engine GUI functions, used by build_vehicle_gui and autoreplace_gui.
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
@ Multihead
indicates a combination of two locomotives
Definition engine_type.h:33
@ 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.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:972
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:900
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:669
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:788
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:70
@ 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
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:390
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:400
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ Orange
Orange.
Definition gfx_type.h:297
@ Grey
Grey.
Definition gfx_type.h:299
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
@ TC_FORCED
Ignore colour changes from strings.
Definition gfx_type.h:332
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:331
Base class for groups and group functions.
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
Get the number of engines with EngineID id_e in the group with GroupID id_g and its sub-groups.
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart 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:980
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
Hotkey related functions.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
static constexpr CargoType CF_NONE
Show only items which do not carry cargo (e.g. train engines).
Definition cargo_type.h: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_ID
Client is not part of anything.
GrfSpecFeature GetGrfSpecFeature(VehicleType type)
Get the GrfSpecFeature associated with a VehicleType.
Definition newgrf.cpp:1905
@ Trains
Trains feature.
Definition newgrf.h:73
@ RoadVehicles
Road vehicles feature.
Definition newgrf.h:74
@ Ships
Ships feature.
Definition newgrf.h:75
@ Aircraft
Aircraft feature.
Definition newgrf.h:76
Functions related to NewGRF badges.
Functions related to NewGRF badge configuration.
int DrawBadgeNameList(Rect r, std::span< const BadgeID > badges, GrfSpecFeature)
Draw names for a list of badge labels.
void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span< const BadgeID > badges, GrfSpecFeature feature, std::optional< TimerGameCalendar::Date > introduction_date, PaletteID remap)
Draw a badge column group.
std::pair< WidgetID, WidgetID > AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature)
Add badge drop down filter widgets.
bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result, BadgeFilterChoices &choices)
Handle the badge configuration drop down selection.
void SetBadgeFilter(BadgeFilterChoices &choices, BadgeID badge_index)
Set badge filter choice for a class.
void ResetBadgeFilter(BadgeFilterChoices &choices, BadgeClassID badge_class_index)
Reset badge filter choice for a class.
GUI functions related to NewGRF badges.
@ CBID_VEHICLE_ADDITIONAL_TEXT
This callback is called from vehicle purchase lists.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles.
Functions for NewGRF engines.
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span< const int32_t > textstack)
Format a GRF string using the text ref stack for parameters.
Header of Action 04 "universal holder" structure and functions.
StrongType::Typedef< uint32_t, struct GRFStringIDTag, StrongType::Compare, StrongType::Integer > GRFStringID
Type for GRF-internal string IDs.
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
PixelColour GetColourGradient(Colours colour, 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:377
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:301
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition rail_map.h:115
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:25
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:32
bool HasPowerOnRoad(RoadType enginetype, RoadType tiletype)
Checks if an engine of the given RoadType got power on a tile with a given RoadType.
Definition road.h:230
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
RoadType GetRoadTypeRoad(Tile t)
Get the road type for RoadTramType being 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:23
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1619
Base classes/functions for stations.
Definition of base types and functions in a cross-platform compatible way.
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition string.cpp: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.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
GUI for building vehicles.
VehicleType vehicle_type
Type of vehicles shown in the window.
void 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:117
Specification of a cargo type.
Definition cargotype.h:75
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:139
StringID name
Name of this type of cargo.
Definition cargotype.h:92
Dimensions (a width and height) of a rectangle in 2D.
EngineID variant_id
Engine variant ID. If set, will be treated specially in purchase lists.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
Information about GRF, used in the game and (part of it) in savegames.
std::string GetName() const
Get the name of this grf.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:118
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:414
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:168
Data structure for an opened window.
Definition window_gui.h:274
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:992
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:835
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1822
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:321
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:786
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3262
Window * parent
Parent window.
Definition window_gui.h:329
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:518
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:818
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1089
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:516
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1812
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:563
WidgetLookup widget_lookup
Indexed access to the nested widget tree. Do not access directly, use Window::GetWidget() instead.
Definition window_gui.h:323
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1846
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:990
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:327
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
std::unique_ptr< NWidgetBase > nested_root
Root of the nested tree.
Definition window_gui.h:322
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
Stuff related to the text buffer GUI.
@ EnableDefault
enable the 'Default' button ("\0" is returned)
Definition textbuf_gui.h:20
@ LengthIsInChars
the length of the string is counted in characters
Definition textbuf_gui.h:21
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
Definition of the game-calendar-timer.
Command definitions related to trains.
void CcBuildWagon(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray, TileIndex tile, EngineID, bool, CargoType, ClientID)
Callback for building wagons.
Definition train_gui.cpp:29
PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition vehicle.cpp:2160
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3094
Command definitions for vehicles.
void CcBuildPrimaryVehicle(Commands, const CommandCost &result, VehicleID new_veh_id, uint, uint16_t, CargoArray)
This is the Callback method after the construction attempt of a primary vehicle.
Functions related to vehicles.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
uint ShowRefitOptionsList(int left, int right, int y, EngineID engine)
Display list of cargo types of the engine, for the purchase information window.
Functions related to the vehicle's GUIs.
@ EIT_PURCHASE
Vehicle drawn in purchase list, autoreplace gui, ...
VehicleType
Available vehicle types.
@ Ship
Ship vehicle type.
@ Invalid
Non-existing type of vehicle.
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ Train
Train vehicle type.
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:1209
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:3322
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:3340
Window functions not directly related to making/drawing windows.
@ Construction
This window is used for construction; close it whenever changing company.
Definition window_gui.h:153
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:219
@ SBS_UP
Sort descending.
Definition window_gui.h:220
@ Automatic
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:21
@ WC_REPLACE_VEHICLE
Replace vehicle window; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:51
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers:
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition zoom_func.h:107