OpenTTD Source: src/station_gui.cpp Source File

OpenTTD Source 15.3

station_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
10#include "stdafx.h"
11#include "debug.h"
12#include "gui.h"
13#include "textbuf_gui.h"
14#include "company_func.h"
15#include "command_func.h"
16#include "vehicle_gui.h"
17#include "cargotype.h"
18#include "station_gui.h"
19#include "strings_func.h"
20#include "string_func.h"
21#include "window_func.h"
22#include "viewport_func.h"
23#include "dropdown_type.h"
24#include "dropdown_func.h"
25#include "station_base.h"
26#include "waypoint_base.h"
27#include "tilehighlight_func.h"
28#include "company_base.h"
29#include "sortlist_type.h"
30#include "core/geometry_func.hpp"
31#include "vehiclelist.h"
32#include "town.h"
33#include "linkgraph/linkgraph.h"
34#include "zoom_func.h"
35#include "station_cmd.h"
36
37#include "widgets/station_widget.h"
38#include "widgets/misc_widget.h"
39
40#include "table/strings.h"
41
42#include "dropdown_common_type.h"
43
44#include "safeguards.h"
45
46 struct StationTypeFilter
47{
48 using StationType = Station;
49
50 static bool IsValidID(StationID id) { return Station::IsValidID(id); }
51 static bool IsValidBaseStation(const BaseStation *st) { return Station::IsExpected(st); }
52 static bool IsAcceptableWaypointTile(TileIndex) { return false; }
53 static constexpr bool IsWaypoint() { return false; }
54};
55
56template <bool ROAD, TileType TILE_TYPE>
57 struct GenericWaypointTypeFilter
58{
59 using StationType = Waypoint;
60
61 static bool IsValidID(StationID id) { return Waypoint::IsValidID(id) && HasBit(Waypoint::Get(id)->waypoint_flags, WPF_ROAD) == ROAD; }
62 static bool IsValidBaseStation(const BaseStation *st) { return Waypoint::IsExpected(st) && HasBit(Waypoint::From(st)->waypoint_flags, WPF_ROAD) == ROAD; }
63 static bool IsAcceptableWaypointTile(TileIndex tile) { return IsTileType(tile, TILE_TYPE); }
64 static constexpr bool IsWaypoint() { return true; }
65};
66using RailWaypointTypeFilter = GenericWaypointTypeFilter<false, MP_RAILWAY>;
67using RoadWaypointTypeFilter = GenericWaypointTypeFilter<true, MP_ROAD>;
68
77 int DrawStationCoverageAreaText(const Rect &r, StationCoverageType sct, int rad, bool supplies)
78{
79 TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
80 CargoTypes cargo_mask = 0;
81 if (_thd.drawstyle == HT_RECT && tile < Map::Size()) {
82 CargoArray cargoes;
83 if (supplies) {
84 cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
85 } else {
86 cargoes = GetAcceptanceAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
87 }
88
89 /* Convert cargo counts to a set of cargo bits, and draw the result. */
90 for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) {
91 switch (sct) {
92 case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(cargo, CargoClass::Passengers)) continue; break;
93 case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(cargo, CargoClass::Passengers)) continue; break;
94 case SCT_ALL: break;
95 default: NOT_REACHED();
96 }
97 if (cargoes[cargo] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, cargo);
98 }
99 }
100 return DrawStringMultiLine(r, GetString(supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO, cargo_mask));
101}
102
107template <typename T>
108 void FindStationsAroundSelection()
109{
110 /* With distant join we don't know which station will be selected, so don't show any */
111 if (_ctrl_pressed) {
112 SetViewportCatchmentSpecializedStation<typename T::StationType>(nullptr, true);
113 return;
114 }
115
116 /* Tile area for TileHighlightData */
117 TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1);
118
119 /* If the current tile is already a station, then it must be the nearest station. */
120 if (IsTileType(location.tile, MP_STATION) && GetTileOwner(location.tile) == _local_company) {
121 typename T::StationType *st = T::StationType::GetByTile(location.tile);
122 if (st != nullptr && T::IsValidBaseStation(st)) {
123 SetViewportCatchmentSpecializedStation<typename T::StationType>(st, true);
124 return;
125 }
126 }
127
128 /* Extended area by one tile */
129 uint x = TileX(location.tile);
130 uint y = TileY(location.tile);
131
132 /* Waypoints can only be built on existing rail/road tiles, so don't extend area if not highlighting a rail tile. */
133 int max_c = T::IsWaypoint() && !T::IsAcceptableWaypointTile(location.tile) ? 0 : 1;
134 TileArea ta(TileXY(std::max<int>(0, x - max_c), std::max<int>(0, y - max_c)), TileXY(std::min<int>(Map::MaxX(), x + location.w + max_c), std::min<int>(Map::MaxY(), y + location.h + max_c)));
135
136 typename T::StationType *adjacent = nullptr;
137
138 /* Direct loop instead of ForAllStationsAroundTiles as we are not interested in catchment area */
139 for (TileIndex tile : ta) {
140 if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) {
141 typename T::StationType *st = T::StationType::GetByTile(tile);
142 if (st == nullptr || !T::IsValidBaseStation(st)) continue;
143 if (adjacent != nullptr && st != adjacent) {
144 /* Multiple nearby, distant join is required. */
145 adjacent = nullptr;
146 break;
147 }
148 adjacent = st;
149 }
150 }
151 SetViewportCatchmentSpecializedStation<typename T::StationType>(adjacent, true);
152}
153
159 void CheckRedrawStationCoverage(const Window *w)
160{
161 /* Test if ctrl state changed */
162 static bool _last_ctrl_pressed;
163 if (_ctrl_pressed != _last_ctrl_pressed) {
164 _thd.dirty = 0xff;
165 _last_ctrl_pressed = _ctrl_pressed;
166 }
167
168 if (_thd.dirty & 1) {
169 _thd.dirty &= ~1;
170 w->SetDirty();
171
172 if (_settings_client.gui.station_show_coverage && _thd.drawstyle == HT_RECT) {
173 FindStationsAroundSelection<StationTypeFilter>();
174 }
175 }
176}
177
178template <typename T>
179void CheckRedrawWaypointCoverage()
180{
181 /* Test if ctrl state changed */
182 static bool _last_ctrl_pressed;
183 if (_ctrl_pressed != _last_ctrl_pressed) {
184 _thd.dirty = 0xff;
185 _last_ctrl_pressed = _ctrl_pressed;
186 }
187
188 if (_thd.dirty & 1) {
189 _thd.dirty &= ~1;
190
191 if (_thd.drawstyle == HT_RECT) {
192 FindStationsAroundSelection<T>();
193 }
194 }
195}
196
197void CheckRedrawRailWaypointCoverage(const Window *)
198{
199 CheckRedrawWaypointCoverage<RailWaypointTypeFilter>();
200}
201
202void CheckRedrawRoadWaypointCoverage(const Window *)
203{
204 CheckRedrawWaypointCoverage<RoadWaypointTypeFilter>();
205}
206
219 static void StationsWndShowStationRating(int left, int right, int y, CargoType cargo, uint amount, uint8_t rating)
220{
221 static const uint units_full = 576;
222 static const uint rating_full = 224;
223
224 const CargoSpec *cs = CargoSpec::Get(cargo);
225 if (!cs->IsValid()) return;
226
227 int padding = ScaleGUITrad(1);
228 int width = right - left;
229 PixelColour colour = cs->rating_colour;
230 TextColour tc = GetContrastColour(colour);
231 uint w = std::min(amount + 5, units_full) * width / units_full;
232
233 int height = GetCharacterHeight(FS_SMALL) + padding - 1;
234
235 if (amount > 30) {
236 /* Draw total cargo (limited) on station */
237 GfxFillRect(left, y, left + w - 1, y + height, colour);
238 } else {
239 /* Draw a (scaled) one pixel-wide bar of additional cargo meter, useful
240 * for stations with only a small amount (<=30) */
241 uint rest = ScaleGUITrad(amount) / 5;
242 if (rest != 0) {
243 GfxFillRect(left, y + height - rest, left + padding - 1, y + height, colour);
244 }
245 }
246
247 DrawString(left + padding, right, y, cs->abbrev, tc, SA_CENTER, false, FS_SMALL);
248
249 /* Draw green/red ratings bar (fits under the waiting bar) */
250 y += height + padding + 1;
251 GfxFillRect(left + padding, y, right - padding - 1, y + padding - 1, PC_RED);
252 w = std::min<uint>(rating, rating_full) * (width - padding - padding) / rating_full;
253 if (w != 0) GfxFillRect(left + padding, y, left + w - 1, y + padding - 1, PC_GREEN);
254}
255
256typedef GUIList<const Station*, const CargoTypes &> GUIStationList;
257
261 class CompanyStationsWindow : public Window
262{
263protected:
264 /* Runtime saved values */
265 struct FilterState {
266 Listing last_sorting;
267 StationFacilities facilities;
268 bool include_no_rating;
269 CargoTypes cargoes;
270 };
271
272 static inline FilterState initial_state = {
273 {false, 0},
274 {StationFacility::Train, StationFacility::TruckStop, StationFacility::BusStop, StationFacility::Airport, StationFacility::Dock},
275 true,
276 ALL_CARGOTYPES,
277 };
278
279 /* Constants for sorting stations */
280 static inline const StringID sorter_names[] = {
281 STR_SORT_BY_NAME,
282 STR_SORT_BY_FACILITY,
283 STR_SORT_BY_WAITING_TOTAL,
284 STR_SORT_BY_WAITING_AVAILABLE,
285 STR_SORT_BY_RATING_MAX,
286 STR_SORT_BY_RATING_MIN,
287 };
288 static const std::initializer_list<GUIStationList::SortFunction * const> sorter_funcs;
289
290 FilterState filter{};
291 GUIStationList stations{filter.cargoes};
292 Scrollbar *vscroll = nullptr;
293 uint rating_width = 0;
294 bool filter_expanded = false;
295 std::array<uint16_t, NUM_CARGO> stations_per_cargo_type{};
296 uint16_t stations_per_cargo_type_no_rating = 0;
297
303 void BuildStationsList(const Owner owner)
304 {
305 if (!this->stations.NeedRebuild()) return;
306
307 Debug(misc, 3, "Building station list for company {}", owner);
308
309 this->stations.clear();
310 this->stations_per_cargo_type.fill(0);
311 this->stations_per_cargo_type_no_rating = 0;
312
313 for (const Station *st : Station::Iterate()) {
314 if (this->filter.facilities.Any(st->facilities)) { // only stations with selected facilities
315 if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
316 bool has_rating = false;
317 /* Add to the station/cargo counts. */
318 for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) {
319 if (st->goods[cargo].HasRating()) this->stations_per_cargo_type[cargo]++;
320 }
321 for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) {
322 if (st->goods[cargo].HasRating()) {
323 has_rating = true;
324 if (HasBit(this->filter.cargoes, cargo)) {
325 this->stations.push_back(st);
326 break;
327 }
328 }
329 }
330 /* Stations with no cargo rating. */
331 if (!has_rating) {
332 if (this->filter.include_no_rating) this->stations.push_back(st);
333 this->stations_per_cargo_type_no_rating++;
334 }
335 }
336 }
337 }
338
339 this->stations.RebuildDone();
340
341 this->vscroll->SetCount(this->stations.size()); // Update the scrollbar
342 }
343
345 static bool StationNameSorter(const Station * const &a, const Station * const &b, const CargoTypes &)
346 {
347 int r = StrNaturalCompare(a->GetCachedName(), b->GetCachedName()); // Sort by name (natural sorting).
348 if (r == 0) return a->index < b->index;
349 return r < 0;
350 }
351
353 static bool StationTypeSorter(const Station * const &a, const Station * const &b, const CargoTypes &)
354 {
355 return a->facilities < b->facilities;
356 }
357
359 static bool StationWaitingTotalSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
360 {
361 int diff = 0;
362
363 for (CargoType cargo : SetCargoBitIterator(cargo_filter)) {
364 diff += a->goods[cargo].TotalCount() - b->goods[cargo].TotalCount();
365 }
366
367 return diff < 0;
368 }
369
371 static bool StationWaitingAvailableSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
372 {
373 int diff = 0;
374
375 for (CargoType cargo : SetCargoBitIterator(cargo_filter)) {
376 diff += a->goods[cargo].AvailableCount() - b->goods[cargo].AvailableCount();
377 }
378
379 return diff < 0;
380 }
381
383 static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
384 {
385 uint8_t maxr1 = 0;
386 uint8_t maxr2 = 0;
387
388 for (CargoType cargo : SetCargoBitIterator(cargo_filter)) {
389 if (a->goods[cargo].HasRating()) maxr1 = std::max(maxr1, a->goods[cargo].rating);
390 if (b->goods[cargo].HasRating()) maxr2 = std::max(maxr2, b->goods[cargo].rating);
391 }
392
393 return maxr1 < maxr2;
394 }
395
397 static bool StationRatingMinSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
398 {
399 uint8_t minr1 = 255;
400 uint8_t minr2 = 255;
401
402 for (CargoType cargo : SetCargoBitIterator(cargo_filter)) {
403 if (a->goods[cargo].HasRating()) minr1 = std::min(minr1, a->goods[cargo].rating);
404 if (b->goods[cargo].HasRating()) minr2 = std::min(minr2, b->goods[cargo].rating);
405 }
406
407 return minr1 > minr2;
408 }
409
411 void SortStationsList()
412 {
413 if (!this->stations.Sort()) return;
414
415 /* Set the modified widget dirty */
416 this->SetWidgetDirty(WID_STL_LIST);
417 }
418
419public:
420 CompanyStationsWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
421 {
422 /* Load initial filter state. */
423 this->filter = CompanyStationsWindow::initial_state;
424 if (this->filter.cargoes == ALL_CARGOTYPES) this->filter.cargoes = _cargo_mask;
425
426 this->stations.SetListing(this->filter.last_sorting);
427 this->stations.SetSortFuncs(CompanyStationsWindow::sorter_funcs);
428 this->stations.ForceRebuild();
429 this->stations.NeedResort();
430 this->SortStationsList();
431
432 this->CreateNestedTree();
433 this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR);
434 this->FinishInitNested(window_number);
435 this->owner = this->window_number;
436
437 if (this->filter.cargoes == ALL_CARGOTYPES) this->filter.cargoes = _cargo_mask;
438
439 for (uint i = 0; i < 5; i++) {
440 if (HasBit(this->filter.facilities.base(), i)) this->LowerWidget(i + WID_STL_TRAIN);
441 }
442
443 this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->SetString(CompanyStationsWindow::sorter_names[this->stations.SortType()]);
444 }
445
446 ~CompanyStationsWindow()
447 {
448 /* Save filter state. */
449 this->filter.last_sorting = this->stations.GetListing();
450 CompanyStationsWindow::initial_state = this->filter;
451 }
452
453 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
454 {
455 switch (widget) {
456 case WID_STL_SORTBY: {
457 Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->GetString());
458 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
459 d.height += padding.height;
460 size = maxdim(size, d);
461 break;
462 }
463
464 case WID_STL_SORTDROPBTN: {
465 Dimension d = GetStringListBoundingBox(CompanyStationsWindow::sorter_names);
466 d.width += padding.width;
467 d.height += padding.height;
468 size = maxdim(size, d);
469 break;
470 }
471
472 case WID_STL_LIST:
473 fill.height = resize.height = std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL) + ScaleGUITrad(3));
474 size.height = padding.height + 5 * resize.height;
475
476 /* Determine appropriate width for mini station rating graph */
477 this->rating_width = 0;
478 for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
479 this->rating_width = std::max(this->rating_width, GetStringBoundingBox(cs->abbrev, FS_SMALL).width);
480 }
481 /* Approximately match original 16 pixel wide rating bars by multiplying string width by 1.6 */
482 this->rating_width = this->rating_width * 16 / 10;
483 break;
484 }
485 }
486
487 void OnPaint() override
488 {
489 this->BuildStationsList(this->window_number);
490 this->SortStationsList();
491
492 this->DrawWidgets();
493 }
494
495 void DrawWidget(const Rect &r, WidgetID widget) const override
496 {
497 switch (widget) {
498 case WID_STL_SORTBY:
499 /* draw arrow pointing up/down for ascending/descending sorting */
500 this->DrawSortButtonState(WID_STL_SORTBY, this->stations.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
501 break;
502
503 case WID_STL_LIST: {
504 bool rtl = _current_text_dir == TD_RTL;
505 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
506 uint line_height = this->GetWidget<NWidgetBase>(widget)->resize_y;
507 /* Spacing between station name and first rating graph. */
508 int text_spacing = WidgetDimensions::scaled.hsep_wide;
509 /* Spacing between additional rating graphs. */
510 int rating_spacing = WidgetDimensions::scaled.hsep_normal;
511
512 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->stations);
513 for (auto it = first; it != last; ++it) {
514 const Station *st = *it;
515 assert(st->xy != INVALID_TILE);
516
517 /* Do not do the complex check HasStationInUse here, it may be even false
518 * when the order had been removed and the station list hasn't been removed yet */
519 assert(st->owner == owner || st->owner == OWNER_NONE);
520
521 int x = DrawString(tr.left, tr.right, tr.top + (line_height - GetCharacterHeight(FS_NORMAL)) / 2, GetString(STR_STATION_LIST_STATION, st->index, st->facilities));
522 x += rtl ? -text_spacing : text_spacing;
523
524 /* show cargo waiting and station ratings */
525 for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
526 CargoType cargo_type = cs->Index();
527 if (st->goods[cargo_type].HasRating()) {
528 /* For RTL we work in exactly the opposite direction. So
529 * decrement the space needed first, then draw to the left
530 * instead of drawing to the left and then incrementing
531 * the space. */
532 if (rtl) {
533 x -= rating_width + rating_spacing;
534 if (x < tr.left) break;
535 }
536 StationsWndShowStationRating(x, x + rating_width, tr.top, cargo_type, st->goods[cargo_type].TotalCount(), st->goods[cargo_type].rating);
537 if (!rtl) {
538 x += rating_width + rating_spacing;
539 if (x > tr.right) break;
540 }
541 }
542 }
543 tr.top += line_height;
544 }
545
546 if (this->vscroll->GetCount() == 0) { // company has no stations
547 DrawString(tr.left, tr.right, tr.top + (line_height - GetCharacterHeight(FS_NORMAL)) / 2, STR_STATION_LIST_NONE);
548 return;
549 }
550 break;
551 }
552 }
553 }
554
555 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
556 {
557 if (widget == WID_STL_CAPTION) {
558 return GetString(STR_STATION_LIST_CAPTION, this->window_number, this->vscroll->GetCount());
559 }
560
561 if (widget == WID_STL_CARGODROPDOWN) {
562 if (this->filter.cargoes == 0) return GetString(this->filter.include_no_rating ? STR_STATION_LIST_CARGO_FILTER_ONLY_NO_RATING : STR_STATION_LIST_CARGO_FILTER_NO_CARGO_TYPES);
563 if (this->filter.cargoes == _cargo_mask) return GetString(this->filter.include_no_rating ? STR_STATION_LIST_CARGO_FILTER_ALL_AND_NO_RATING : STR_CARGO_TYPE_FILTER_ALL);
564 if (CountBits(this->filter.cargoes) == 1 && !this->filter.include_no_rating) return GetString(CargoSpec::Get(FindFirstBit(this->filter.cargoes))->name);
565 return GetString(STR_STATION_LIST_CARGO_FILTER_MULTIPLE);
566 }
567
568 return this->Window::GetWidgetString(widget, stringid);
569 }
570
571 DropDownList BuildCargoDropDownList(bool expanded) const
572 {
573 /* Define a custom item consisting of check mark, count string, icon and name string. */
574 using DropDownListCargoItem = DropDownCheck<DropDownString<DropDownListIconItem, FS_SMALL, true>>;
575
576 DropDownList list;
577 list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_SELECT_ALL, CargoFilterCriteria::CF_SELECT_ALL));
578 list.push_back(MakeDropDownListDividerItem());
579
580 bool any_hidden = false;
581
582 uint16_t count = this->stations_per_cargo_type_no_rating;
583 if (count == 0 && !expanded) {
584 any_hidden = true;
585 } else {
586 list.push_back(std::make_unique<DropDownString<DropDownListCheckedItem, FS_SMALL, true>>(fmt::format("{}", count), 0, this->filter.include_no_rating, GetString(STR_STATION_LIST_CARGO_FILTER_NO_RATING), CargoFilterCriteria::CF_NO_RATING, false, count == 0));
587 }
588
589 Dimension d = GetLargestCargoIconSize();
590 for (const CargoSpec *cs : _sorted_cargo_specs) {
591 count = this->stations_per_cargo_type[cs->Index()];
592 if (count == 0 && !expanded) {
593 any_hidden = true;
594 } else {
595 list.push_back(std::make_unique<DropDownListCargoItem>(HasBit(this->filter.cargoes, cs->Index()), fmt::format("{}", count), d, cs->GetCargoIcon(), PAL_NONE, GetString(cs->name), cs->Index(), false, count == 0));
596 }
597 }
598
599 if (!expanded && any_hidden) {
600 if (list.size() > 2) list.push_back(MakeDropDownListDividerItem());
601 list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_EXPAND, CargoFilterCriteria::CF_EXPAND_LIST));
602 }
603
604 return list;
605 }
606
607 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
608 {
609 switch (widget) {
610 case WID_STL_LIST: {
611 auto it = this->vscroll->GetScrolledItemFromWidget(this->stations, pt.y, this, WID_STL_LIST, WidgetDimensions::scaled.framerect.top);
612 if (it == this->stations.end()) return; // click out of list bound
613
614 const Station *st = *it;
615 /* do not check HasStationInUse - it is slow and may be invalid */
616 assert(st->owner == this->window_number || st->owner == OWNER_NONE);
617
618 if (_ctrl_pressed) {
619 ShowExtraViewportWindow(st->xy);
620 } else {
621 ScrollMainWindowToTile(st->xy);
622 }
623 break;
624 }
625
626 case WID_STL_TRAIN:
627 case WID_STL_TRUCK:
628 case WID_STL_BUS:
629 case WID_STL_AIRPLANE:
630 case WID_STL_SHIP:
631 if (_ctrl_pressed) {
632 this->filter.facilities.Flip(static_cast<StationFacility>(widget - WID_STL_TRAIN));
633 this->ToggleWidgetLoweredState(widget);
634 } else {
635 for (StationFacility i : this->filter.facilities) {
636 this->RaiseWidget(to_underlying(i) + WID_STL_TRAIN);
637 }
638 this->filter.facilities = {};
639 this->filter.facilities.Set(static_cast<StationFacility>(widget - WID_STL_TRAIN));
640 this->LowerWidget(widget);
641 }
642 this->stations.ForceRebuild();
643 this->SetDirty();
644 break;
645
646 case WID_STL_FACILALL:
647 for (WidgetID i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) {
648 this->LowerWidget(i);
649 }
650
651 this->filter.facilities = {StationFacility::Train, StationFacility::TruckStop, StationFacility::BusStop, StationFacility::Airport, StationFacility::Dock};
652 this->stations.ForceRebuild();
653 this->SetDirty();
654 break;
655
656 case WID_STL_SORTBY: // flip sorting method asc/desc
657 this->stations.ToggleSortOrder();
658 this->SetDirty();
659 break;
660
661 case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu
662 ShowDropDownMenu(this, CompanyStationsWindow::sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0);
663 break;
664
665 case WID_STL_CARGODROPDOWN:
666 this->filter_expanded = false;
667 ShowDropDownList(this, this->BuildCargoDropDownList(this->filter_expanded), -1, widget, 0, DropDownOption::Persist);
668 break;
669 }
670 }
671
672 void OnDropdownSelect(WidgetID widget, int index, int) override
673 {
674 if (widget == WID_STL_SORTDROPBTN) {
675 if (this->stations.SortType() != index) {
676 this->stations.SetSortType(index);
677
678 /* Display the current sort variant */
679 this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->SetString(CompanyStationsWindow::sorter_names[this->stations.SortType()]);
680
681 this->SetDirty();
682 }
683 }
684
685 if (widget == WID_STL_CARGODROPDOWN) {
686 FilterState oldstate = this->filter;
687
688 if (index >= 0 && index < NUM_CARGO) {
689 if (_ctrl_pressed) {
690 ToggleBit(this->filter.cargoes, index);
691 } else {
692 this->filter.cargoes = 1ULL << index;
693 this->filter.include_no_rating = false;
694 }
695 } else if (index == CargoFilterCriteria::CF_NO_RATING) {
696 if (_ctrl_pressed) {
697 this->filter.include_no_rating = !this->filter.include_no_rating;
698 } else {
699 this->filter.include_no_rating = true;
700 this->filter.cargoes = 0;
701 }
702 } else if (index == CargoFilterCriteria::CF_SELECT_ALL) {
703 this->filter.cargoes = _cargo_mask;
704 this->filter.include_no_rating = true;
705 } else if (index == CargoFilterCriteria::CF_EXPAND_LIST) {
706 this->filter_expanded = true;
707 ReplaceDropDownList(this, this->BuildCargoDropDownList(this->filter_expanded));
708 return;
709 }
710
711 if (oldstate.cargoes != this->filter.cargoes || oldstate.include_no_rating != this->filter.include_no_rating) {
712 this->stations.ForceRebuild();
713 this->SetDirty();
714
715 /* Only refresh the list if it's changed. */
716 if (_ctrl_pressed) ReplaceDropDownList(this, this->BuildCargoDropDownList(this->filter_expanded));
717 }
718
719 /* Always close the list if ctrl is not pressed. */
720 if (!_ctrl_pressed) this->CloseChildWindows(WC_DROPDOWN_MENU);
721 }
722 }
723
724 void OnGameTick() override
725 {
726 if (this->stations.NeedResort()) {
727 Debug(misc, 3, "Periodic rebuild station list company {}", static_cast<int>(this->window_number));
728 this->SetDirty();
729 }
730 }
731
732 void OnResize() override
733 {
734 this->vscroll->SetCapacityFromWidget(this, WID_STL_LIST, WidgetDimensions::scaled.framerect.Vertical());
735 }
736
742 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
743 {
744 if (data == 0) {
745 /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
746 this->stations.ForceRebuild();
747 } else {
748 this->stations.ForceResort();
749 }
750 }
751};
752
753/* Available station sorting functions */
754const std::initializer_list<GUIStationList::SortFunction * const> CompanyStationsWindow::sorter_funcs = {
755 &StationNameSorter,
756 &StationTypeSorter,
757 &StationWaitingTotalSorter,
758 &StationWaitingAvailableSorter,
759 &StationRatingMaxSorter,
760 &StationRatingMinSorter
761};
762
763static constexpr std::initializer_list<NWidgetPart> _nested_company_stations_widgets = {
764 NWidget(NWID_HORIZONTAL),
765 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
766 NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION),
767 NWidget(WWT_SHADEBOX, COLOUR_GREY),
768 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
769 NWidget(WWT_STICKYBOX, COLOUR_GREY),
770 EndContainer(),
771 NWidget(NWID_HORIZONTAL),
772 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetStringTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE_TOOLTIP), SetFill(0, 1),
773 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetStringTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE_TOOLTIP), SetFill(0, 1),
774 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetStringTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE_TOOLTIP), SetFill(0, 1),
775 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetStringTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE_TOOLTIP), SetFill(0, 1),
776 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetStringTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE_TOOLTIP), SetFill(0, 1),
777 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_FACILALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetStringTip(STR_ABBREV_ALL, STR_STATION_LIST_SELECT_ALL_FACILITIES_TOOLTIP), SetTextStyle(TC_BLACK, FS_SMALL), SetFill(0, 1),
778 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 0), SetFill(0, 1), EndContainer(),
779 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_CARGODROPDOWN), SetFill(1, 0), SetToolTip(STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE_TOOLTIP),
780 NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
781 EndContainer(),
782 NWidget(NWID_HORIZONTAL),
783 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
784 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetStringTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten.
785 NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
786 EndContainer(),
787 NWidget(NWID_HORIZONTAL),
788 NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_LIST), SetMinimalSize(346, 125), SetResize(1, 10), SetToolTip(STR_STATION_LIST_TOOLTIP), SetScrollbar(WID_STL_SCROLLBAR), EndContainer(),
789 NWidget(NWID_VERTICAL),
790 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_STL_SCROLLBAR),
791 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
792 EndContainer(),
793 EndContainer(),
794};
795
796static WindowDesc _company_stations_desc(
797 WDP_AUTO, "list_stations", 358, 162,
798 WC_STATION_LIST, WC_NONE,
799 {},
800 _nested_company_stations_widgets
801);
802
808 void ShowCompanyStations(CompanyID company)
809{
810 if (!Company::IsValidID(company)) return;
811
812 AllocateWindowDescFront<CompanyStationsWindow>(_company_stations_desc, company);
813}
814
815static constexpr std::initializer_list<NWidgetPart> _nested_station_view_widgets = {
816 NWidget(NWID_HORIZONTAL),
817 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
818 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_RENAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_STATION_VIEW_EDIT_TOOLTIP),
819 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION),
820 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_LOCATION), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetSpriteTip(SPR_GOTO_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
821 NWidget(WWT_SHADEBOX, COLOUR_GREY),
822 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
823 NWidget(WWT_STICKYBOX, COLOUR_GREY),
824 EndContainer(),
825 NWidget(NWID_HORIZONTAL),
826 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetStringTip(STR_STATION_VIEW_GROUP),
827 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetToolTip(STR_TOOLTIP_GROUP_ORDER),
828 EndContainer(),
829 NWidget(NWID_HORIZONTAL),
830 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
831 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetToolTip(STR_TOOLTIP_SORT_CRITERIA),
832 EndContainer(),
833 NWidget(NWID_HORIZONTAL),
834 NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_WAITING), SetMinimalSize(237, 44), SetResize(1, 10), SetScrollbar(WID_SV_SCROLLBAR), EndContainer(),
835 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SV_SCROLLBAR),
836 EndContainer(),
837 NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_ACCEPT_RATING_LIST), SetMinimalSize(249, 23), SetResize(1, 0), EndContainer(),
838 NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
839 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1),
840 SetStringTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
841 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SV_CLOSE_AIRPORT_SEL),
842 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
843 SetStringTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
844 EndContainer(),
845 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CATCHMENT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
846 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetStringTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
847 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetStringTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
848 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetStringTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
849 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetStringTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
850 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
851 EndContainer(),
852};
853
854enum SortOrder : uint8_t {
855 SO_DESCENDING,
856 SO_ASCENDING
857};
858
859class CargoDataEntry;
860
861 enum class CargoSortType : uint8_t {
862 AsGrouping,
863 Count,
864 StationString,
865 StationID,
866 CargoType,
867};
868
869 class CargoSorter {
870public:
871 using is_transparent = void;
872 CargoSorter(CargoSortType t = CargoSortType::StationID, SortOrder o = SO_ASCENDING) : type(t), order(o) {}
873 CargoSortType GetSortType() {return this->type;}
874 bool operator()(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const;
875 bool operator()(const CargoDataEntry &cd1, const std::unique_ptr<CargoDataEntry> &cd2) const { return this->operator()(cd1, *cd2); }
876 bool operator()(const std::unique_ptr<CargoDataEntry> &cd1, const CargoDataEntry &cd2) const { return this->operator()(*cd1, cd2); }
877 bool operator()(const std::unique_ptr<CargoDataEntry> &cd1, const std::unique_ptr<CargoDataEntry> &cd2) const { return this->operator()(*cd1, *cd2); }
878
879private:
880 CargoSortType type;
881 SortOrder order;
882
883 template <class Tid>
884 bool SortId(Tid st1, Tid st2) const;
885 bool SortCount(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const;
886 bool SortStation(StationID st1, StationID st2) const;
887};
888
889typedef std::set<std::unique_ptr<CargoDataEntry>, CargoSorter> CargoDataSet;
890
896 class CargoDataEntry {
897public:
898 CargoDataEntry();
899 ~CargoDataEntry();
900
906 CargoDataEntry &InsertOrRetrieve(StationID station)
907 {
908 return this->InsertOrRetrieve<StationID>(station);
909 }
910
916 CargoDataEntry &InsertOrRetrieve(CargoType cargo)
917 {
918 return this->InsertOrRetrieve<CargoType>(cargo);
919 }
920
921 void Update(uint count);
922
927 void Remove(StationID station)
928 {
929 CargoDataEntry t(station);
930 this->Remove(t);
931 }
932
937 void Remove(CargoType cargo)
938 {
939 CargoDataEntry t(cargo);
940 this->Remove(t);
941 }
942
948 CargoDataEntry *Retrieve(StationID station) const
949 {
950 CargoDataEntry t(station);
951 return this->Retrieve(this->children->find(t));
952 }
953
959 CargoDataEntry *Retrieve(CargoType cargo) const
960 {
961 CargoDataEntry t(cargo);
962 return this->Retrieve(this->children->find(t));
963 }
964
965 void Resort(CargoSortType type, SortOrder order);
966
970 StationID GetStation() const { return this->station; }
971
975 CargoType GetCargo() const { return this->cargo; }
976
980 uint GetCount() const { return this->count; }
981
985 CargoDataEntry *GetParent() const { return this->parent; }
986
990 uint GetNumChildren() const { return this->num_children; }
991
995 CargoDataSet::iterator Begin() const { return this->children->begin(); }
996
1000 CargoDataSet::iterator End() const { return this->children->end(); }
1001
1005 bool HasTransfers() const { return this->transfers; }
1006
1010 void SetTransfers(bool value) { this->transfers = value; }
1011
1012 void Clear();
1013
1014 CargoDataEntry(StationID station, uint count, CargoDataEntry *parent);
1015 CargoDataEntry(CargoType cargo, uint count, CargoDataEntry *parent);
1016 CargoDataEntry(StationID station);
1017 CargoDataEntry(CargoType cargo);
1018
1019private:
1020 CargoDataEntry *Retrieve(CargoDataSet::iterator i) const;
1021
1022 template <class Tid>
1023 CargoDataEntry &InsertOrRetrieve(Tid s);
1024
1025 void Remove(CargoDataEntry &entry);
1026 void IncrementSize();
1027
1028 CargoDataEntry *parent;
1029 const union {
1030 StationID station;
1031 struct {
1032 CargoType cargo;
1033 bool transfers;
1034 };
1035 };
1036 uint num_children;
1037 uint count;
1038 std::unique_ptr<CargoDataSet> children;
1039};
1040
1041CargoDataEntry::CargoDataEntry() :
1042 parent(nullptr),
1043 station(StationID::Invalid()),
1044 num_children(0),
1045 count(0),
1046 children(std::make_unique<CargoDataSet>(CargoSorter(CargoSortType::CargoType)))
1047{}
1048
1049CargoDataEntry::CargoDataEntry(CargoType cargo, uint count, CargoDataEntry *parent) :
1050 parent(parent),
1051 cargo(cargo),
1052 num_children(0),
1053 count(count),
1054 children(std::make_unique<CargoDataSet>())
1055{}
1056
1057CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) :
1058 parent(parent),
1059 station(station),
1060 num_children(0),
1061 count(count),
1062 children(std::make_unique<CargoDataSet>())
1063{}
1064
1065CargoDataEntry::CargoDataEntry(StationID station) :
1066 parent(nullptr),
1067 station(station),
1068 num_children(0),
1069 count(0),
1070 children(nullptr)
1071{}
1072
1073CargoDataEntry::CargoDataEntry(CargoType cargo) :
1074 parent(nullptr),
1075 cargo(cargo),
1076 num_children(0),
1077 count(0),
1078 children(nullptr)
1079{}
1080
1081CargoDataEntry::~CargoDataEntry()
1082{
1083 this->Clear();
1084}
1085
1089 void CargoDataEntry::Clear()
1090{
1091 if (this->children != nullptr) this->children->clear();
1092 if (this->parent != nullptr) this->parent->count -= this->count;
1093 this->count = 0;
1094 this->num_children = 0;
1095}
1096
1103 void CargoDataEntry::Remove(CargoDataEntry &entry)
1104{
1105 CargoDataSet::iterator i = this->children->find(entry);
1106 if (i != this->children->end()) this->children->erase(i);
1107}
1108
1115template <class Tid>
1116 CargoDataEntry &CargoDataEntry::InsertOrRetrieve(Tid child_id)
1117{
1118 CargoDataEntry tmp(child_id);
1119 CargoDataSet::iterator i = this->children->find(tmp);
1120 if (i == this->children->end()) {
1121 IncrementSize();
1122 return **(this->children->insert(std::make_unique<CargoDataEntry>(child_id, 0, this)).first);
1123 } else {
1124 assert(this->children->value_comp().GetSortType() != CargoSortType::Count);
1125 return **i;
1126 }
1127}
1128
1134 void CargoDataEntry::Update(uint count)
1135{
1136 this->count += count;
1137 if (this->parent != nullptr) this->parent->Update(count);
1138}
1139
1143 void CargoDataEntry::IncrementSize()
1144{
1145 ++this->num_children;
1146 if (this->parent != nullptr) this->parent->IncrementSize();
1147}
1148
1149void CargoDataEntry::Resort(CargoSortType type, SortOrder order)
1150{
1151 auto new_children = std::make_unique<CargoDataSet>(CargoSorter(type, order));
1152 new_children->merge(*this->children);
1153 this->children = std::move(new_children);
1154}
1155
1156 CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const
1157{
1158 if (i == this->children->end()) {
1159 return nullptr;
1160 } else {
1161 assert(this->children->value_comp().GetSortType() != CargoSortType::Count);
1162 return i->get();
1163 }
1164}
1165
1166bool CargoSorter::operator()(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const
1167{
1168 switch (this->type) {
1169 case CargoSortType::StationID:
1170 return this->SortId<StationID>(cd1.GetStation(), cd2.GetStation());
1171 case CargoSortType::CargoType:
1172 return this->SortId<CargoType>(cd1.GetCargo(), cd2.GetCargo());
1173 case CargoSortType::Count:
1174 return this->SortCount(cd1, cd2);
1175 case CargoSortType::StationString:
1176 return this->SortStation(cd1.GetStation(), cd2.GetStation());
1177 default:
1178 NOT_REACHED();
1179 }
1180}
1181
1182template <class Tid>
1183bool CargoSorter::SortId(Tid st1, Tid st2) const
1184{
1185 return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1;
1186}
1187
1188bool CargoSorter::SortCount(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const
1189{
1190 uint c1 = cd1.GetCount();
1191 uint c2 = cd2.GetCount();
1192 if (c1 == c2) {
1193 return this->SortStation(cd1.GetStation(), cd2.GetStation());
1194 } else if (this->order == SO_ASCENDING) {
1195 return c1 < c2;
1196 } else {
1197 return c2 < c1;
1198 }
1199}
1200
1201bool CargoSorter::SortStation(StationID st1, StationID st2) const
1202{
1203 if (!Station::IsValidID(st1)) {
1204 return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2);
1205 } else if (!Station::IsValidID(st2)) {
1206 return order == SO_DESCENDING;
1207 }
1208
1209 int res = StrNaturalCompare(Station::Get(st1)->GetCachedName(), Station::Get(st2)->GetCachedName()); // Sort by name (natural sorting).
1210 if (res == 0) {
1211 return this->SortId(st1, st2);
1212 } else {
1213 return (this->order == SO_ASCENDING) ? res < 0 : res > 0;
1214 }
1215}
1216
1220 struct StationViewWindow : public Window {
1224 struct RowDisplay {
1225 RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {}
1226 RowDisplay(CargoDataEntry *f, CargoType n) : filter(f), next_cargo(n) {}
1227
1231 CargoDataEntry *filter;
1232 union {
1236 StationID next_station;
1237
1241 CargoType next_cargo;
1242 };
1243 };
1244
1245 typedef std::vector<RowDisplay> CargoDataVector;
1246
1247 static const int NUM_COLUMNS = 4;
1248
1252 enum Invalidation : uint16_t {
1253 INV_FLOWS = 0x100,
1254 INV_CARGO = 0x200
1255 };
1256
1260 enum Grouping : uint8_t {
1261 GR_SOURCE,
1262 GR_NEXT,
1263 GR_DESTINATION,
1264 GR_CARGO,
1265 };
1266
1270 enum Mode : uint8_t {
1271 MODE_WAITING,
1272 MODE_PLANNED
1273 };
1274
1275 uint expand_shrink_width = 0;
1276 int rating_lines = RATING_LINES;
1277 int accepts_lines = ACCEPTS_LINES;
1278 int line_height = 0;
1279 Dimension cargo_icon_size{};
1280 Scrollbar *vscroll = nullptr;
1281
1282 /* Height of the #WID_SV_ACCEPT_RATING_LIST widget for different views. */
1283 static constexpr uint RATING_LINES = 13;
1284 static constexpr uint ACCEPTS_LINES = 3;
1285
1287 static inline const StringID sort_names[] = {
1288 STR_STATION_VIEW_WAITING_STATION,
1289 STR_STATION_VIEW_WAITING_AMOUNT,
1290 STR_STATION_VIEW_PLANNED_STATION,
1291 STR_STATION_VIEW_PLANNED_AMOUNT,
1292 };
1294 static inline const StringID group_names[] = {
1295 STR_STATION_VIEW_GROUP_S_V_D,
1296 STR_STATION_VIEW_GROUP_S_D_V,
1297 STR_STATION_VIEW_GROUP_V_S_D,
1298 STR_STATION_VIEW_GROUP_V_D_S,
1299 STR_STATION_VIEW_GROUP_D_S_V,
1300 STR_STATION_VIEW_GROUP_D_V_S,
1301 };
1302
1309 std::array<CargoSortType, NUM_COLUMNS> sortings{};
1310
1312 std::array<SortOrder, NUM_COLUMNS> sort_orders{};
1313
1314 int scroll_to_row = INT_MAX;
1315 int grouping_index = 0;
1316 Mode current_mode{};
1317 std::array<Grouping, NUM_COLUMNS> groupings;
1318
1319 CargoDataEntry expanded_rows{};
1320 CargoDataEntry cached_destinations{};
1321 CargoDataVector displayed_rows{};
1322
1323 StationViewWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
1324 {
1325 this->CreateNestedTree();
1326 this->GetWidget<NWidgetStacked>(WID_SV_CLOSE_AIRPORT_SEL)->SetDisplayedPlane(Station::Get(window_number)->facilities.Test(StationFacility::Airport) ? 0 : SZSP_NONE);
1327 this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
1328 /* Nested widget tree creation is done in two steps to ensure that this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */
1329 this->FinishInitNested(window_number);
1330
1331 this->groupings[0] = GR_CARGO;
1332 this->sortings[0] = CargoSortType::AsGrouping;
1333 this->SelectGroupBy(_settings_client.gui.station_gui_group_order);
1334 this->SelectSortBy(_settings_client.gui.station_gui_sort_by);
1335 this->sort_orders[0] = SO_ASCENDING;
1336 this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order);
1337 this->owner = Station::Get(window_number)->owner;
1338 }
1339
1340 void OnInit() override
1341 {
1342 this->cargo_icon_size = GetLargestCargoIconSize();
1343 this->line_height = std::max<int>(GetCharacterHeight(FS_NORMAL), this->cargo_icon_size.height);
1344 this->expand_shrink_width = std::max(GetCharacterWidth(FS_NORMAL, '-'), GetCharacterWidth(FS_NORMAL, '+'));
1345 }
1346
1347 void Close([[maybe_unused]] int data = 0) override
1348 {
1349 CloseWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->window_number).ToWindowNumber(), false);
1350 CloseWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).ToWindowNumber(), false);
1351 CloseWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).ToWindowNumber(), false);
1352 CloseWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).ToWindowNumber(), false);
1353
1354 SetViewportCatchmentStation(Station::Get(this->window_number), false);
1355 this->Window::Close();
1356 }
1357
1368 void ShowCargo(CargoDataEntry *data, CargoType cargo, StationID source, StationID next, StationID dest, uint count)
1369 {
1370 if (count == 0) return;
1371 bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1372 const CargoDataEntry *expand = &this->expanded_rows;
1373 for (int i = 0; i < NUM_COLUMNS && expand != nullptr; ++i) {
1374 switch (groupings[i]) {
1375 case GR_CARGO:
1376 assert(i == 0);
1377 data = &data->InsertOrRetrieve(cargo);
1378 data->SetTransfers(source != this->window_number);
1379 expand = expand->Retrieve(cargo);
1380 break;
1381 case GR_SOURCE:
1382 if (auto_distributed || source != this->window_number) {
1383 data = &data->InsertOrRetrieve(source);
1384 expand = expand->Retrieve(source);
1385 }
1386 break;
1387 case GR_NEXT:
1388 if (auto_distributed) {
1389 data = &data->InsertOrRetrieve(next);
1390 expand = expand->Retrieve(next);
1391 }
1392 break;
1393 case GR_DESTINATION:
1394 if (auto_distributed) {
1395 data = &data->InsertOrRetrieve(dest);
1396 expand = expand->Retrieve(dest);
1397 }
1398 break;
1399 }
1400 }
1401 data->Update(count);
1402 }
1403
1404 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1405 {
1406 switch (widget) {
1407 case WID_SV_WAITING:
1408 fill.height = resize.height = this->line_height;
1409 size.height = 4 * resize.height + padding.height;
1410 break;
1411
1412 case WID_SV_ACCEPT_RATING_LIST:
1413 size.height = ((this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->GetString() == STR_STATION_VIEW_RATINGS_BUTTON) ? this->accepts_lines : this->rating_lines) * GetCharacterHeight(FS_NORMAL) + padding.height;
1414 break;
1415 }
1416 }
1417
1418 void OnPaint() override
1419 {
1420 const Station *st = Station::Get(this->window_number);
1421 CargoDataEntry cargo;
1422 BuildCargoList(&cargo, st);
1423
1424 this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar
1425
1426 /* disable some buttons */
1427 this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company);
1428 this->SetWidgetDisabledState(WID_SV_TRAINS, !st->facilities.Test(StationFacility::Train));
1429 this->SetWidgetDisabledState(WID_SV_ROADVEHS, !st->facilities.Test(StationFacility::TruckStop) && !st->facilities.Test(StationFacility::BusStop));
1430 this->SetWidgetDisabledState(WID_SV_SHIPS, !st->facilities.Test(StationFacility::Dock));
1431 this->SetWidgetDisabledState(WID_SV_PLANES, !st->facilities.Test(StationFacility::Airport));
1432 this->SetWidgetDisabledState(WID_SV_CLOSE_AIRPORT, !st->facilities.Test(StationFacility::Airport) || st->owner != _local_company || st->owner == OWNER_NONE); // Also consider SE, where _local_company == OWNER_NONE
1433 this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, st->facilities.Test(StationFacility::Airport) && st->airport.blocks.Test(AirportBlock::AirportClosed));
1434
1435 extern const Station *_viewport_highlight_station;
1436 this->SetWidgetDisabledState(WID_SV_CATCHMENT, st->facilities.None());
1437 this->SetWidgetLoweredState(WID_SV_CATCHMENT, _viewport_highlight_station == st);
1438
1439 this->DrawWidgets();
1440
1441 if (!this->IsShaded()) {
1442 /* Draw 'accepted cargo' or 'cargo ratings'. */
1443 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SV_ACCEPT_RATING_LIST);
1444 const Rect r = wid->GetCurrentRect();
1445 if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->GetString() == STR_STATION_VIEW_RATINGS_BUTTON) {
1446 int lines = this->DrawAcceptedCargo(r);
1447 if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window.
1448 this->accepts_lines = lines;
1449 this->ReInit();
1450 return;
1451 }
1452 } else {
1453 int lines = this->DrawCargoRatings(r);
1454 if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window.
1455 this->rating_lines = lines;
1456 this->ReInit();
1457 return;
1458 }
1459 }
1460
1461 /* Draw arrow pointing up/down for ascending/descending sorting */
1462 this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN);
1463
1464 int pos = this->vscroll->GetPosition();
1465
1466 int maxrows = this->vscroll->GetCapacity();
1467
1468 displayed_rows.clear();
1469
1470 /* Draw waiting cargo. */
1471 NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SV_WAITING);
1472 Rect waiting_rect = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
1473 this->DrawEntries(cargo, waiting_rect, pos, maxrows, 0);
1474 scroll_to_row = INT_MAX;
1475 }
1476 }
1477
1478 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1479 {
1480 if (widget == WID_SV_CAPTION) {
1481 const Station *st = Station::Get(this->window_number);
1482 return GetString(STR_STATION_VIEW_CAPTION, st->index, st->facilities);
1483 }
1484
1485 return this->Window::GetWidgetString(widget, stringid);
1486 }
1487
1493 void RecalcDestinations(CargoType cargo)
1494 {
1495 const Station *st = Station::Get(this->window_number);
1496 CargoDataEntry &entry = cached_destinations.InsertOrRetrieve(cargo);
1497 entry.Clear();
1498
1499 if (!st->goods[cargo].HasData()) return;
1500
1501 for (const auto &it : st->goods[cargo].GetData().flows) {
1502 StationID from = it.first;
1503 CargoDataEntry &source_entry = entry.InsertOrRetrieve(from);
1504 uint32_t prev_count = 0;
1505 for (const auto &flow_it : *it.second.GetShares()) {
1506 StationID via = flow_it.second;
1507 CargoDataEntry &via_entry = source_entry.InsertOrRetrieve(via);
1508 if (via == this->window_number) {
1509 via_entry.InsertOrRetrieve(via).Update(flow_it.first - prev_count);
1510 } else {
1511 EstimateDestinations(cargo, from, via, flow_it.first - prev_count, via_entry);
1512 }
1513 prev_count = flow_it.first;
1514 }
1515 }
1516 }
1517
1527 void EstimateDestinations(CargoType cargo, StationID source, StationID next, uint count, CargoDataEntry &dest)
1528 {
1529 if (Station::IsValidID(next) && Station::IsValidID(source)) {
1530 GoodsEntry &ge = Station::Get(next)->goods[cargo];
1531 if (!ge.HasData()) return;
1532
1533 CargoDataEntry tmp;
1534 const FlowStatMap &flowmap = ge.GetData().flows;
1535 FlowStatMap::const_iterator map_it = flowmap.find(source);
1536 if (map_it != flowmap.end()) {
1537 const FlowStat::SharesMap *shares = map_it->second.GetShares();
1538 uint32_t prev_count = 0;
1539 for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) {
1540 tmp.InsertOrRetrieve(i->second).Update(i->first - prev_count);
1541 prev_count = i->first;
1542 }
1543 }
1544
1545 if (tmp.GetCount() == 0) {
1546 dest.InsertOrRetrieve(StationID::Invalid()).Update(count);
1547 } else {
1548 uint sum_estimated = 0;
1549 while (sum_estimated < count) {
1550 for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) {
1551 CargoDataEntry &child = **i;
1552 uint estimate = DivideApprox(child.GetCount() * count, tmp.GetCount());
1553 if (estimate == 0) estimate = 1;
1554
1555 sum_estimated += estimate;
1556 if (sum_estimated > count) {
1557 estimate -= sum_estimated - count;
1558 sum_estimated = count;
1559 }
1560
1561 if (estimate > 0) {
1562 if (child.GetStation() == next) {
1563 dest.InsertOrRetrieve(next).Update(estimate);
1564 } else {
1565 EstimateDestinations(cargo, source, child.GetStation(), estimate, dest);
1566 }
1567 }
1568 }
1569
1570 }
1571 }
1572 } else {
1573 dest.InsertOrRetrieve(StationID::Invalid()).Update(count);
1574 }
1575 }
1576
1583 void BuildFlowList(CargoType cargo, const FlowStatMap &flows, CargoDataEntry *entry)
1584 {
1585 const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(cargo);
1586 for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1587 StationID from = it->first;
1588 const CargoDataEntry *source_entry = source_dest->Retrieve(from);
1589 const FlowStat::SharesMap *shares = it->second.GetShares();
1590 for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1591 const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second);
1592 for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1593 CargoDataEntry &dest_entry = **dest_it;
1594 ShowCargo(entry, cargo, from, flow_it->second, dest_entry.GetStation(), dest_entry.GetCount());
1595 }
1596 }
1597 }
1598 }
1599
1606 void BuildCargoList(CargoType cargo, const StationCargoList &packets, CargoDataEntry *entry)
1607 {
1608 const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(cargo);
1609 for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) {
1610 const CargoPacket *cp = *it;
1611 StationID next = it.GetKey();
1612
1613 const CargoDataEntry *source_entry = source_dest->Retrieve(cp->GetFirstStation());
1614 if (source_entry == nullptr) {
1615 this->ShowCargo(entry, cargo, cp->GetFirstStation(), next, StationID::Invalid(), cp->Count());
1616 continue;
1617 }
1618
1619 const CargoDataEntry *via_entry = source_entry->Retrieve(next);
1620 if (via_entry == nullptr) {
1621 this->ShowCargo(entry, cargo, cp->GetFirstStation(), next, StationID::Invalid(), cp->Count());
1622 continue;
1623 }
1624
1625 uint remaining = cp->Count();
1626 for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End();) {
1627 CargoDataEntry &dest_entry = **dest_it;
1628
1629 /* Advance iterator here instead of in the for statement to test whether this is the last entry */
1630 ++dest_it;
1631
1632 uint val;
1633 if (dest_it == via_entry->End()) {
1634 /* Allocate all remaining waiting cargo to the last destination to avoid
1635 * waiting cargo being "lost", and the displayed total waiting cargo
1636 * not matching GoodsEntry::TotalCount() */
1637 val = remaining;
1638 } else {
1639 val = std::min<uint>(remaining, DivideApprox(cp->Count() * dest_entry.GetCount(), via_entry->GetCount()));
1640 remaining -= val;
1641 }
1642 this->ShowCargo(entry, cargo, cp->GetFirstStation(), next, dest_entry.GetStation(), val);
1643 }
1644 }
1645 this->ShowCargo(entry, cargo, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount());
1646 }
1647
1653 void BuildCargoList(CargoDataEntry *entry, const Station *st)
1654 {
1655 for (CargoType cargo = 0; cargo < NUM_CARGO; ++cargo) {
1656
1657 if (this->cached_destinations.Retrieve(cargo) == nullptr) {
1658 this->RecalcDestinations(cargo);
1659 }
1660
1661 const GoodsEntry &ge = st->goods[cargo];
1662 if (!ge.HasData()) continue;
1663
1664 if (this->current_mode == MODE_WAITING) {
1665 this->BuildCargoList(cargo, ge.GetData().cargo, entry);
1666 } else {
1667 this->BuildFlowList(cargo, ge.GetData().flows, entry);
1668 }
1669 }
1670 }
1671
1676 void SetDisplayedRow(const CargoDataEntry &entry)
1677 {
1678 std::list<StationID> stations;
1679 const CargoDataEntry *parent = entry.GetParent();
1680 if (parent->GetParent() == nullptr) {
1681 this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, entry.GetCargo()));
1682 return;
1683 }
1684
1685 StationID next = entry.GetStation();
1686 while (parent->GetParent()->GetParent() != nullptr) {
1687 stations.push_back(parent->GetStation());
1688 parent = parent->GetParent();
1689 }
1690
1691 CargoType cargo = parent->GetCargo();
1692 CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo);
1693 while (!stations.empty()) {
1694 filter = filter->Retrieve(stations.back());
1695 stations.pop_back();
1696 }
1697
1698 this->displayed_rows.push_back(RowDisplay(filter, next));
1699 }
1700
1709 StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any) const
1710 {
1711 if (station == this->window_number) {
1712 return here;
1713 } else if (station == StationID::Invalid()) {
1714 return any;
1715 } else if (station == NEW_STATION) {
1716 return STR_STATION_VIEW_RESERVED;
1717 } else {
1718 return other_station;
1719 }
1720 }
1721
1722 StringID GetGroupingString(Grouping grouping, StationID station) const
1723 {
1724 switch (grouping) {
1725 case GR_SOURCE: return this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY);
1726 case GR_NEXT: return this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY);
1727 case GR_DESTINATION: return this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY);
1728 default: NOT_REACHED();
1729 }
1730 }
1731
1739 StringID SearchNonStop(CargoDataEntry &cd, StationID station, int column)
1740 {
1741 assert(column < NUM_COLUMNS);
1742 CargoDataEntry *parent = cd.GetParent();
1743 for (int i = column - 1; i > 0; --i) {
1744 if (this->groupings[i] == GR_DESTINATION) {
1745 if (parent->GetStation() == station) {
1746 return STR_STATION_VIEW_NONSTOP;
1747 } else {
1748 return STR_STATION_VIEW_VIA;
1749 }
1750 }
1751 parent = parent->GetParent();
1752 }
1753
1754 if (column < NUM_COLUMNS - 1 && this->groupings[column + 1] == GR_DESTINATION) {
1755 CargoDataSet::iterator begin = cd.Begin();
1756 CargoDataSet::iterator end = cd.End();
1757 if (begin != end && ++(cd.Begin()) == end && (*(begin))->GetStation() == station) {
1758 return STR_STATION_VIEW_NONSTOP;
1759 } else {
1760 return STR_STATION_VIEW_VIA;
1761 }
1762 }
1763
1764 return STR_STATION_VIEW_VIA;
1765 }
1766
1773 void DrawCargoIcons(CargoType cargo, uint waiting, const Rect &r) const
1774 {
1775 int width = ScaleSpriteTrad(10);
1776 uint num = std::min<uint>((waiting + (width / 2)) / width, r.Width() / width); // maximum is width / 10 icons so it won't overflow
1777 if (num == 0) return;
1778
1779 SpriteID sprite = CargoSpec::Get(cargo)->GetCargoIcon();
1780
1781 int x = _current_text_dir == TD_RTL ? r.left : r.right - num * width;
1782 int y = CentreBounds(r.top, r.bottom, this->cargo_icon_size.height);
1783 do {
1784 DrawSprite(sprite, PAL_NONE, x, y);
1785 x += width;
1786 } while (--num);
1787 }
1788
1799 int DrawEntries(CargoDataEntry &entry, const Rect &r, int pos, int maxrows, int column, CargoType cargo = INVALID_CARGO)
1800 {
1801 assert(column < NUM_COLUMNS);
1802 if (this->sortings[column] == CargoSortType::AsGrouping) {
1803 if (this->groupings[column] != GR_CARGO) {
1804 entry.Resort(CargoSortType::StationString, this->sort_orders[column]);
1805 }
1806 } else {
1807 entry.Resort(CargoSortType::Count, this->sort_orders[column]);
1808 }
1809 int text_y_offset = (this->line_height - GetCharacterHeight(FS_NORMAL)) / 2;
1810 for (CargoDataSet::iterator i = entry.Begin(); i != entry.End(); ++i) {
1811 CargoDataEntry &cd = **i;
1812
1813 Grouping grouping = this->groupings[column];
1814 if (grouping == GR_CARGO) cargo = cd.GetCargo();
1815 bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1816
1817 if (pos > -maxrows && pos <= 0) {
1818 StringID str = STR_EMPTY;
1819 StationID station = StationID::Invalid();
1820 int y = r.top - pos * this->line_height;
1821 if (this->groupings[column] == GR_CARGO) {
1822 str = STR_STATION_VIEW_WAITING_CARGO;
1823 this->DrawCargoIcons(cd.GetCargo(), cd.GetCount(), Rect(r.left + this->expand_shrink_width, y, r.right - this->expand_shrink_width, y + this->line_height - 1));
1824 } else {
1825 if (!auto_distributed) grouping = GR_SOURCE;
1826 station = cd.GetStation();
1827 str = this->GetGroupingString(grouping, station);
1828 if (grouping == GR_NEXT && str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column);
1829
1830 if (pos == -this->scroll_to_row && Station::IsValidID(station)) {
1831 ScrollMainWindowToTile(Station::Get(station)->xy);
1832 }
1833 }
1834
1835 bool rtl = _current_text_dir == TD_RTL;
1836 Rect text = r.Indent(column * WidgetDimensions::scaled.hsep_indent, rtl).Indent(this->expand_shrink_width, !rtl);
1837 Rect shrink = r.WithWidth(this->expand_shrink_width, !rtl);
1838
1839 DrawString(text.left, text.right, y + text_y_offset, GetString(str, cargo, cd.GetCount(), station));
1840
1841 if (column < NUM_COLUMNS - 1) {
1842 std::string_view sym;
1843 if (cd.GetNumChildren() > 0) {
1844 sym = "-";
1845 } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) {
1846 sym = "+";
1847 } else {
1848 /* Only draw '+' if there is something to be shown. */
1849 const GoodsEntry &ge = Station::Get(this->window_number)->goods[cargo];
1850 if (ge.HasData()) {
1851 const StationCargoList &cargo_list = ge.GetData().cargo;
1852 if (grouping == GR_CARGO && (cargo_list.ReservedCount() > 0 || cd.HasTransfers())) {
1853 sym = "+";
1854 }
1855 }
1856 }
1857 if (!sym.empty()) DrawString(shrink.left, shrink.right, y + text_y_offset, sym, TC_YELLOW);
1858 }
1859 this->SetDisplayedRow(cd);
1860 }
1861 --pos;
1862 if ((auto_distributed || column == 0) && column < NUM_COLUMNS - 1) {
1863 pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo);
1864 }
1865 }
1866 return pos;
1867 }
1868
1874 int DrawAcceptedCargo(const Rect &r) const
1875 {
1876 const Station *st = Station::Get(this->window_number);
1877 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
1878
1879 int bottom = DrawStringMultiLine(tr.left, tr.right, tr.top, INT32_MAX, GetString(STR_STATION_VIEW_ACCEPTS_CARGO, GetAcceptanceMask(st)));
1880 return CeilDiv(bottom - r.top - WidgetDimensions::scaled.framerect.top, GetCharacterHeight(FS_NORMAL));
1881 }
1882
1888 int DrawCargoRatings(const Rect &r) const
1889 {
1890 const Station *st = Station::Get(this->window_number);
1891 bool rtl = _current_text_dir == TD_RTL;
1892 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
1893
1894 if (st->town->exclusive_counter > 0) {
1895 tr.top = DrawStringMultiLine(tr, GetString(st->town->exclusivity == st->owner ? STR_STATION_VIEW_EXCLUSIVE_RIGHTS_SELF : STR_STATION_VIEW_EXCLUSIVE_RIGHTS_COMPANY, st->town->exclusivity));
1896 tr.top += WidgetDimensions::scaled.vsep_wide;
1897 }
1898
1899 DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_STATION_VIEW_SUPPLY_RATINGS_TITLE_MINUTE : STR_STATION_VIEW_SUPPLY_RATINGS_TITLE_MONTH);
1900 tr.top += GetCharacterHeight(FS_NORMAL);
1901
1902 for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
1903 const GoodsEntry *ge = &st->goods[cs->Index()];
1904 if (!ge->HasRating()) continue;
1905
1906 const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph);
1907 DrawString(tr.Indent(WidgetDimensions::scaled.hsep_indent, rtl),
1908 GetString(STR_STATION_VIEW_CARGO_SUPPLY_RATING,
1909 cs->name,
1910 lg != nullptr ? lg->Monthly((*lg)[ge->node].supply) : 0,
1911 STR_CARGO_RATING_APPALLING + (ge->rating >> 5),
1912 ToPercent8(ge->rating)));
1913 tr.top += GetCharacterHeight(FS_NORMAL);
1914 }
1915 return CeilDiv(tr.top - r.top - WidgetDimensions::scaled.framerect.top, GetCharacterHeight(FS_NORMAL));
1916 }
1917
1923 template <class Tid>
1924 void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
1925 {
1926 if (filter->Retrieve(next) != nullptr) {
1927 filter->Remove(next);
1928 } else {
1929 filter->InsertOrRetrieve(next);
1930 }
1931 }
1932
1937 void HandleCargoWaitingClick(int row)
1938 {
1939 if (row < 0 || (uint)row >= this->displayed_rows.size()) return;
1940 if (_ctrl_pressed) {
1941 this->scroll_to_row = row;
1942 } else {
1943 RowDisplay &display = this->displayed_rows[row];
1944 if (display.filter == &this->expanded_rows) {
1945 this->HandleCargoWaitingClick<CargoType>(display.filter, display.next_cargo);
1946 } else {
1947 this->HandleCargoWaitingClick<StationID>(display.filter, display.next_station);
1948 }
1949 }
1950 this->SetWidgetDirty(WID_SV_WAITING);
1951 }
1952
1953 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1954 {
1955 Window *w = FindWindowByClass(WC_QUERY_STRING);
1956
1957 switch (widget) {
1958 case WID_SV_WAITING:
1959 this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WidgetDimensions::scaled.framerect.top) - this->vscroll->GetPosition());
1960 break;
1961
1962 case WID_SV_CATCHMENT:
1963 SetViewportCatchmentStation(Station::Get(this->window_number), !this->IsWidgetLowered(WID_SV_CATCHMENT));
1964
1965 if (w != nullptr && this->IsWidgetLowered(WID_SV_CATCHMENT)) {
1966 if (w->parent->window_class == WC_STATION_VIEW && w->IsWidgetLowered(WID_QS_MOVE)) SetViewportStationRect(Station::Get(w->parent->window_number), true);
1967 if (w->parent->window_class == WC_WAYPOINT_VIEW && w->IsWidgetLowered(WID_QS_MOVE)) SetViewportWaypointRect(Waypoint::Get(w->parent->window_number), true);
1968 }
1969 break;
1970
1971 case WID_SV_LOCATION:
1972 if (_ctrl_pressed) {
1973 ShowExtraViewportWindow(Station::Get(this->window_number)->xy);
1974 } else {
1975 ScrollMainWindowToTile(Station::Get(this->window_number)->xy);
1976 }
1977 break;
1978
1979 case WID_SV_ACCEPTS_RATINGS: {
1980 /* Swap between 'accepts' and 'ratings' view. */
1981 int height_change;
1982 NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS);
1983 if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->GetString() == STR_STATION_VIEW_RATINGS_BUTTON) {
1984 nwi->SetStringTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view.
1985 height_change = this->rating_lines - this->accepts_lines;
1986 } else {
1987 nwi->SetStringTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view.
1988 height_change = this->accepts_lines - this->rating_lines;
1989 }
1990 this->ReInit(0, height_change * GetCharacterHeight(FS_NORMAL));
1991 break;
1992 }
1993
1994 case WID_SV_RENAME:
1995 ShowQueryString(GetString(STR_STATION_NAME, this->window_number), STR_STATION_VIEW_EDIT_STATION_SIGN, MAX_LENGTH_STATION_NAME_CHARS,
1996 this, CS_ALPHANUMERAL, {QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars, QueryStringFlag::EnableMove});
1997 break;
1998
1999 case WID_SV_CLOSE_AIRPORT:
2000 Command<CMD_OPEN_CLOSE_AIRPORT>::Post(this->window_number);
2001 break;
2002
2003 case WID_SV_TRAINS: // Show list of scheduled trains to this station
2004 case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station
2005 case WID_SV_SHIPS: // Show list of scheduled ships to this station
2006 case WID_SV_PLANES: { // Show list of scheduled aircraft to this station
2007 Owner owner = Station::Get(this->window_number)->owner;
2008 ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), static_cast<StationID>(this->window_number));
2009 break;
2010 }
2011
2012 case WID_SV_SORT_BY: {
2013 /* The initial selection is composed of current mode and
2014 * sorting criteria for columns 1, 2, and 3. Column 0 is always
2015 * sorted by cargo type. The others can theoretically be sorted
2016 * by different things but there is no UI for that. */
2017 ShowDropDownMenu(this, StationViewWindow::sort_names,
2018 this->current_mode * 2 + (this->sortings[1] == CargoSortType::Count ? 1 : 0),
2019 WID_SV_SORT_BY, 0, 0);
2020 break;
2021 }
2022
2023 case WID_SV_GROUP_BY: {
2024 ShowDropDownMenu(this, StationViewWindow::group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
2025 break;
2026 }
2027
2028 case WID_SV_SORT_ORDER: { // flip sorting method asc/desc
2029 this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING);
2030 this->SetTimeout();
2031 this->LowerWidget(WID_SV_SORT_ORDER);
2032 break;
2033 }
2034 }
2035 }
2036
2041 void SelectSortOrder(SortOrder order)
2042 {
2043 this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order;
2044 _settings_client.gui.station_gui_sort_order = this->sort_orders[1];
2045 this->SetDirty();
2046 }
2047
2052 void SelectSortBy(int index)
2053 {
2054 _settings_client.gui.station_gui_sort_by = index;
2055 switch (StationViewWindow::sort_names[index]) {
2056 case STR_STATION_VIEW_WAITING_STATION:
2057 this->current_mode = MODE_WAITING;
2058 this->sortings[1] = this->sortings[2] = this->sortings[3] = CargoSortType::AsGrouping;
2059 break;
2060 case STR_STATION_VIEW_WAITING_AMOUNT:
2061 this->current_mode = MODE_WAITING;
2062 this->sortings[1] = this->sortings[2] = this->sortings[3] = CargoSortType::Count;
2063 break;
2064 case STR_STATION_VIEW_PLANNED_STATION:
2065 this->current_mode = MODE_PLANNED;
2066 this->sortings[1] = this->sortings[2] = this->sortings[3] = CargoSortType::AsGrouping;
2067 break;
2068 case STR_STATION_VIEW_PLANNED_AMOUNT:
2069 this->current_mode = MODE_PLANNED;
2070 this->sortings[1] = this->sortings[2] = this->sortings[3] = CargoSortType::Count;
2071 break;
2072 default:
2073 NOT_REACHED();
2074 }
2075 /* Display the current sort variant */
2076 this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->SetString(StationViewWindow::sort_names[index]);
2077 this->SetDirty();
2078 }
2079
2084 void SelectGroupBy(int index)
2085 {
2086 this->grouping_index = index;
2087 _settings_client.gui.station_gui_group_order = index;
2088 this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->SetString(StationViewWindow::group_names[index]);
2089 switch (StationViewWindow::group_names[index]) {
2090 case STR_STATION_VIEW_GROUP_S_V_D:
2091 this->groupings[1] = GR_SOURCE;
2092 this->groupings[2] = GR_NEXT;
2093 this->groupings[3] = GR_DESTINATION;
2094 break;
2095 case STR_STATION_VIEW_GROUP_S_D_V:
2096 this->groupings[1] = GR_SOURCE;
2097 this->groupings[2] = GR_DESTINATION;
2098 this->groupings[3] = GR_NEXT;
2099 break;
2100 case STR_STATION_VIEW_GROUP_V_S_D:
2101 this->groupings[1] = GR_NEXT;
2102 this->groupings[2] = GR_SOURCE;
2103 this->groupings[3] = GR_DESTINATION;
2104 break;
2105 case STR_STATION_VIEW_GROUP_V_D_S:
2106 this->groupings[1] = GR_NEXT;
2107 this->groupings[2] = GR_DESTINATION;
2108 this->groupings[3] = GR_SOURCE;
2109 break;
2110 case STR_STATION_VIEW_GROUP_D_S_V:
2111 this->groupings[1] = GR_DESTINATION;
2112 this->groupings[2] = GR_SOURCE;
2113 this->groupings[3] = GR_NEXT;
2114 break;
2115 case STR_STATION_VIEW_GROUP_D_V_S:
2116 this->groupings[1] = GR_DESTINATION;
2117 this->groupings[2] = GR_NEXT;
2118 this->groupings[3] = GR_SOURCE;
2119 break;
2120 }
2121 this->SetDirty();
2122 }
2123
2124 void OnDropdownSelect(WidgetID widget, int index, int) override
2125 {
2126 if (widget == WID_SV_SORT_BY) {
2127 this->SelectSortBy(index);
2128 } else {
2129 this->SelectGroupBy(index);
2130 }
2131 }
2132
2133 void OnQueryTextFinished(std::optional<std::string> str) override
2134 {
2135 if (!str.has_value()) return;
2136
2137 Command<CMD_RENAME_STATION>::Post(STR_ERROR_CAN_T_RENAME_STATION, this->window_number, *str);
2138 }
2139
2140 void OnResize() override
2141 {
2142 this->vscroll->SetCapacityFromWidget(this, WID_SV_WAITING, WidgetDimensions::scaled.framerect.Vertical());
2143 }
2144
2150 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2151 {
2152 if (gui_scope) {
2153 if (data >= 0 && data < NUM_CARGO) {
2154 this->cached_destinations.Remove((CargoType)data);
2155 } else {
2156 this->ReInit();
2157 }
2158 }
2159 }
2160};
2161
2162static WindowDesc _station_view_desc(
2163 WDP_AUTO, "view_station", 249, 117,
2164 WC_STATION_VIEW, WC_NONE,
2165 {},
2166 _nested_station_view_widgets
2167);
2168
2174 void ShowStationViewWindow(StationID station)
2175{
2176 AllocateWindowDescFront<StationViewWindow>(_station_view_desc, station);
2177}
2178
2180 struct TileAndStation {
2181 TileIndex tile;
2182 StationID station;
2183};
2184
2185static std::vector<TileAndStation> _deleted_stations_nearby;
2186static std::vector<StationID> _stations_nearby_list;
2187
2195template <class T>
2196 static void AddNearbyStation(TileIndex tile, TileArea *ctx)
2197{
2198 /* First check if there were deleted stations here */
2199 for (auto it = _deleted_stations_nearby.begin(); it != _deleted_stations_nearby.end(); /* nothing */) {
2200 if (it->tile == tile) {
2201 _stations_nearby_list.push_back(it->station);
2202 it = _deleted_stations_nearby.erase(it);
2203 } else {
2204 ++it;
2205 }
2206 }
2207
2208 /* Check if own station and if we stay within station spread */
2209 if (!IsTileType(tile, MP_STATION)) return;
2210
2211 StationID sid = GetStationIndex(tile);
2212
2213 /* This station is (likely) a waypoint */
2214 if (!T::IsValidID(sid)) return;
2215
2216 BaseStation *st = BaseStation::Get(sid);
2217 if (st->owner != _local_company || std::ranges::find(_stations_nearby_list, sid) != _stations_nearby_list.end()) return;
2218
2219 if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
2220 _stations_nearby_list.push_back(sid);
2221 }
2222}
2223
2233template <class T>
2234 static void FindStationsNearby(TileArea ta, bool distant_join)
2235{
2236 TileArea ctx = ta;
2237
2238 _stations_nearby_list.clear();
2239 _stations_nearby_list.push_back(NEW_STATION);
2240 _deleted_stations_nearby.clear();
2241
2242 /* Look for deleted stations */
2243 for (const BaseStation *st : BaseStation::Iterate()) {
2244 if (T::IsValidBaseStation(st) && !st->IsInUse() && st->owner == _local_company) {
2245 /* Include only within station spread (yes, it is strictly less than) */
2246 if (std::max(DistanceMax(ta.tile, st->xy), DistanceMax(TileAddXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) {
2247 _deleted_stations_nearby.emplace_back(st->xy, st->index);
2248
2249 /* Add the station when it's within where we're going to build */
2250 if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
2251 IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
2252 AddNearbyStation<T>(st->xy, &ctx);
2253 }
2254 }
2255 }
2256 }
2257
2258 /* Add stations that are within station tile area. Stations do not have to occupy all tiles */
2259 for (auto t : ta) {
2260 AddNearbyStation<T>(t, &ctx);
2261 }
2262
2263 /* Only search tiles where we have a chance to stay within the station spread.
2264 * The complete check needs to be done in the callback as we don't know the
2265 * extent of the found station, yet. */
2266 if (distant_join && std::min(ta.w, ta.h) >= _settings_game.station.station_spread) return;
2267 uint max_dist = distant_join ? _settings_game.station.station_spread - std::min(ta.w, ta.h) : 1;
2268
2269 for (auto tile : SpiralTileSequence(TileAddByDir(ctx.tile, DIR_N), max_dist, ta.w, ta.h)) {
2270 AddNearbyStation<T>(tile, &ctx);
2271 }
2272}
2273
2274static constexpr std::initializer_list<NWidgetPart> _nested_select_station_widgets = {
2275 NWidget(NWID_HORIZONTAL),
2276 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
2277 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetStringTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2278 NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
2279 EndContainer(),
2280 NWidget(NWID_HORIZONTAL),
2281 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(),
2282 NWidget(NWID_VERTICAL),
2283 NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR),
2284 NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
2285 EndContainer(),
2286 EndContainer(),
2287};
2288
2293template <class T>
2294 struct SelectStationWindow : Window {
2295 StationPickerCmdProc select_station_proc{};
2296 TileArea area{};
2297 Scrollbar *vscroll = nullptr;
2298
2299 SelectStationWindow(WindowDesc &desc, TileArea ta, StationPickerCmdProc&& proc) :
2300 Window(desc),
2301 select_station_proc(std::move(proc)),
2302 area(ta)
2303 {
2304 this->CreateNestedTree();
2305 this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
2306 this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->SetString(T::IsWaypoint() ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION);
2307 this->FinishInitNested(0);
2308 this->OnInvalidateData(0);
2309
2310 _thd.freeze = true;
2311 }
2312
2313 void Close([[maybe_unused]] int data = 0) override
2314 {
2315 SetViewportCatchmentSpecializedStation<typename T::StationType>(nullptr, true);
2316
2317 _thd.freeze = false;
2318 this->Window::Close();
2319 }
2320
2321 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2322 {
2323 if (widget != WID_JS_PANEL) return;
2324
2325 /* Determine the widest string */
2326 Dimension d = GetStringBoundingBox(T::IsWaypoint() ? STR_JOIN_WAYPOINT_CREATE_SPLIT_WAYPOINT : STR_JOIN_STATION_CREATE_SPLIT_STATION);
2327 for (const auto &station : _stations_nearby_list) {
2328 if (station == NEW_STATION) continue;
2329 const BaseStation *st = BaseStation::Get(station);
2330 d = maxdim(d, GetStringBoundingBox(T::IsWaypoint()
2331 ? GetString(STR_STATION_LIST_WAYPOINT, st->index)
2332 : GetString(STR_STATION_LIST_STATION, st->index, st->facilities)));
2333 }
2334
2335 fill.height = resize.height = d.height;
2336 d.height *= 5;
2337 d.width += padding.width;
2338 d.height += padding.height;
2339 size = d;
2340 }
2341
2342 void DrawWidget(const Rect &r, WidgetID widget) const override
2343 {
2344 if (widget != WID_JS_PANEL) return;
2345
2346 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
2347 auto [first, last] = this->vscroll->GetVisibleRangeIterators(_stations_nearby_list);
2348 for (auto it = first; it != last; ++it, tr.top += this->resize.step_height) {
2349 if (*it == NEW_STATION) {
2350 DrawString(tr, T::IsWaypoint() ? STR_JOIN_WAYPOINT_CREATE_SPLIT_WAYPOINT : STR_JOIN_STATION_CREATE_SPLIT_STATION);
2351 } else {
2352 const BaseStation *st = BaseStation::Get(*it);
2353 DrawString(tr, T::IsWaypoint()
2354 ? GetString(STR_STATION_LIST_WAYPOINT, st->index)
2355 : GetString(STR_STATION_LIST_STATION, st->index, st->facilities));
2356 }
2357 }
2358
2359 }
2360
2361 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2362 {
2363 if (widget != WID_JS_PANEL) return;
2364
2365 auto it = this->vscroll->GetScrolledItemFromWidget(_stations_nearby_list, pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top);
2366 if (it == _stations_nearby_list.end()) return;
2367
2368 /* Execute stored Command */
2369 this->select_station_proc(false, *it);
2370
2371 /* Close Window; this might cause double frees! */
2372 CloseWindowById(WC_SELECT_STATION, 0);
2373 }
2374
2375 void OnRealtimeTick([[maybe_unused]] uint delta_ms) override
2376 {
2377 if (_thd.dirty & 2) {
2378 _thd.dirty &= ~2;
2379 this->SetDirty();
2380 }
2381 }
2382
2383 void OnResize() override
2384 {
2385 this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.Vertical());
2386 }
2387
2393 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2394 {
2395 if (!gui_scope) return;
2396 FindStationsNearby<T>(this->area, true);
2397 this->vscroll->SetCount(_stations_nearby_list.size());
2398 this->SetDirty();
2399 }
2400
2401 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
2402 {
2403 if (widget != WID_JS_PANEL) {
2404 SetViewportCatchmentSpecializedStation<typename T::StationType>(nullptr, true);
2405 return;
2406 }
2407
2408 /* Show coverage area of station under cursor */
2409 auto it = this->vscroll->GetScrolledItemFromWidget(_stations_nearby_list, pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top);
2410 const typename T::StationType *st = it == _stations_nearby_list.end() || *it == NEW_STATION ? nullptr : T::StationType::Get(*it);
2411 SetViewportCatchmentSpecializedStation<typename T::StationType>(st, true);
2412 }
2413};
2414
2415static WindowDesc _select_station_desc(
2416 WDP_AUTO, "build_station_join", 200, 180,
2417 WC_SELECT_STATION, WC_NONE,
2418 WindowDefaultFlag::Construction,
2419 _nested_select_station_widgets
2420);
2421
2422
2430template <class T>
2431 static bool StationJoinerNeeded(const StationPickerCmdProc &proc)
2432{
2433 /* Only show selection if distant join is enabled in the settings */
2434 if (!_settings_game.station.distant_join_stations) return false;
2435
2436 /* If a window is already opened and we didn't ctrl-click,
2437 * return true (i.e. just flash the old window) */
2438 Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
2439 if (selection_window != nullptr) {
2440 /* Abort current distant-join and start new one */
2441 selection_window->Close();
2442 UpdateTileSelection();
2443 }
2444
2445 /* only show the popup, if we press ctrl */
2446 if (!_ctrl_pressed) return false;
2447
2448 /* Now check if we could build there */
2449 return proc(true, StationID::Invalid());
2450}
2451
2458template <class T>
2459 void ShowSelectBaseStationIfNeeded(TileArea ta, StationPickerCmdProc&& proc)
2460{
2461 if (StationJoinerNeeded<T>(proc)) {
2462 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
2463 FindStationsNearby<T>(ta, false);
2464 new SelectStationWindow<T>(_select_station_desc, ta, std::move(proc));
2465 } else {
2466 proc(false, StationID::Invalid());
2467 }
2468}
2469
2475 void ShowSelectStationIfNeeded(TileArea ta, StationPickerCmdProc proc)
2476{
2477 ShowSelectBaseStationIfNeeded<StationTypeFilter>(ta, std::move(proc));
2478}
2479
2485 void ShowSelectRailWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
2486{
2487 ShowSelectBaseStationIfNeeded<RailWaypointTypeFilter>(ta, std::move(proc));
2488}
2489
2495 void ShowSelectRoadWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
2496{
2497 ShowSelectBaseStationIfNeeded<RoadWaypointTypeFilter>(ta, std::move(proc));
2498}
AirportBlock::AirportClosed
@ AirportClosed
Dummy block for indicating a closed airport.
SetBit
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Definition bitmath_func.hpp:121
FindFirstBit
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
Definition bitmath_func.hpp:189
CountBits
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
Definition bitmath_func.hpp:238
HasBit
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition bitmath_func.hpp:103
ToggleBit
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
Definition bitmath_func.hpp:157
CargoType
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
NUM_CARGO
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
GetLargestCargoIconSize
Dimension GetLargestCargoIconSize()
Get dimensions of largest cargo icon.
Definition cargotype.cpp:163
_sorted_standard_cargo_specs
std::span< const CargoSpec * > _sorted_standard_cargo_specs
Standard cargo specifications sorted alphabetically by name.
Definition cargotype.cpp:191
_sorted_cargo_specs
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Definition cargotype.cpp:190
_cargo_mask
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:31
cargotype.h
Types/functions related to cargoes.
CargoClass::Passengers
@ Passengers
Passengers.
IsCargoInClass
bool IsCargoInClass(CargoType cargo, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:236
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
BaseBitSet::base
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
Definition base_bitset_type.hpp:219
BaseBitSet::None
constexpr bool None() const
Test if none of the values are set.
Definition base_bitset_type.hpp:188
BaseBitSet::Flip
constexpr Timpl & Flip(Tvalue_type value)
Flip the value-th bit.
Definition base_bitset_type.hpp:116
BaseBitSet::Set
constexpr Timpl & Set()
Set all bits.
Definition base_bitset_type.hpp:40
BaseBitSet::Any
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Definition base_bitset_type.hpp:170
CargoDataEntry
A cargo data entry representing one possible row in the station view window's top part.
Definition station_gui.cpp:896
CargoDataEntry::count
uint count
sum of counts of all children or amount of cargo for this entry.
Definition station_gui.cpp:1037
CargoDataEntry::Clear
void Clear()
Delete all subentries, reset count and num_children and adapt parent's count.
Definition station_gui.cpp:1089
CargoDataEntry::GetStation
StationID GetStation() const
Get the station ID for this entry.
Definition station_gui.cpp:970
CargoDataEntry::IncrementSize
void IncrementSize()
Increment.
Definition station_gui.cpp:1143
CargoDataEntry::SetTransfers
void SetTransfers(bool value)
Set the transfers state.
Definition station_gui.cpp:1010
CargoDataEntry::GetCargo
CargoType GetCargo() const
Get the cargo type for this entry.
Definition station_gui.cpp:975
CargoDataEntry::num_children
uint num_children
the number of subentries belonging to this entry.
Definition station_gui.cpp:1036
CargoDataEntry::Remove
void Remove(CargoType cargo)
Remove a child associated with the given cargo.
Definition station_gui.cpp:937
CargoDataEntry::Retrieve
CargoDataEntry * Retrieve(StationID station) const
Retrieve a child for the given station.
Definition station_gui.cpp:948
CargoDataEntry::GetCount
uint GetCount() const
Get the cargo count for this entry.
Definition station_gui.cpp:980
CargoDataEntry::GetParent
CargoDataEntry * GetParent() const
Get the parent entry for this entry.
Definition station_gui.cpp:985
CargoDataEntry::station
StationID station
ID of the station this entry is associated with.
Definition station_gui.cpp:1030
CargoDataEntry::cargo
CargoType cargo
ID of the cargo this entry is associated with.
Definition station_gui.cpp:1032
CargoDataEntry::InsertOrRetrieve
CargoDataEntry & InsertOrRetrieve(StationID station)
Insert a new child or retrieve an existing child using a station ID as ID.
Definition station_gui.cpp:906
CargoDataEntry::InsertOrRetrieve
CargoDataEntry & InsertOrRetrieve(CargoType cargo)
Insert a new child or retrieve an existing child using a cargo type as ID.
Definition station_gui.cpp:916
CargoDataEntry::End
CargoDataSet::iterator End() const
Get an iterator pointing to the end of the set of children.
Definition station_gui.cpp:1000
CargoDataEntry::Update
void Update(uint count)
Update the count for this entry and propagate the change to the parent entry if there is one.
Definition station_gui.cpp:1134
CargoDataEntry::children
std::unique_ptr< CargoDataSet > children
the children of this entry.
Definition station_gui.cpp:1038
CargoDataEntry::transfers
bool transfers
If there are transfers for this cargo.
Definition station_gui.cpp:1033
CargoDataEntry::Begin
CargoDataSet::iterator Begin() const
Get an iterator pointing to the begin of the set of children.
Definition station_gui.cpp:995
CargoDataEntry::HasTransfers
bool HasTransfers() const
Has this entry transfers.
Definition station_gui.cpp:1005
CargoDataEntry::Retrieve
CargoDataEntry * Retrieve(CargoType cargo) const
Retrieve a child for the given cargo.
Definition station_gui.cpp:959
CargoDataEntry::parent
CargoDataEntry * parent
the parent of this entry.
Definition station_gui.cpp:1028
CargoDataEntry::Remove
void Remove(StationID station)
Remove a child associated with the given station.
Definition station_gui.cpp:927
CargoDataEntry::GetNumChildren
uint GetNumChildren() const
Get the number of children for this entry.
Definition station_gui.cpp:990
CargoList::Packets
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Definition cargopacket.h:320
CargoList< StationCargoList, StationCargoPacketMap >::ConstIterator
Tcont::const_iterator ConstIterator
The const iterator for our container.
Definition cargopacket.h:281
CargoSorter
Definition station_gui.cpp:869
CommandCost::Succeeded
bool Succeeded() const
Did this command succeed?
Definition command_type.h:168
CompanyStationsWindow
The list of stations per company.
Definition station_gui.cpp:262
CompanyStationsWindow::StationRatingMaxSorter
static bool StationRatingMaxSorter(const Station *const &a, const Station *const &b, const CargoTypes &cargo_filter)
Sort stations by their rating.
Definition station_gui.cpp:383
CompanyStationsWindow::stations_per_cargo_type
std::array< uint16_t, NUM_CARGO > stations_per_cargo_type
Number of stations with a rating for each cargo type.
Definition station_gui.cpp:295
CompanyStationsWindow::UpdateWidgetSize
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.
Definition station_gui.cpp:453
CompanyStationsWindow::OnResize
void OnResize() override
Called after the window got resized.
Definition station_gui.cpp:732
CompanyStationsWindow::SortStationsList
void SortStationsList()
Sort the stations list.
Definition station_gui.cpp:411
CompanyStationsWindow::StationRatingMinSorter
static bool StationRatingMinSorter(const Station *const &a, const Station *const &b, const CargoTypes &cargo_filter)
Sort stations by their rating.
Definition station_gui.cpp:397
CompanyStationsWindow::OnInvalidateData
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition station_gui.cpp:742
CompanyStationsWindow::OnDropdownSelect
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
Definition station_gui.cpp:672
CompanyStationsWindow::StationWaitingAvailableSorter
static bool StationWaitingAvailableSorter(const Station *const &a, const Station *const &b, const CargoTypes &cargo_filter)
Sort stations by their available waiting cargo.
Definition station_gui.cpp:371
CompanyStationsWindow::OnClick
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition station_gui.cpp:607
CompanyStationsWindow::GetWidgetString
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition station_gui.cpp:555
CompanyStationsWindow::OnPaint
void OnPaint() override
The window must be repainted.
Definition station_gui.cpp:487
CompanyStationsWindow::StationNameSorter
static bool StationNameSorter(const Station *const &a, const Station *const &b, const CargoTypes &)
Sort stations by their name.
Definition station_gui.cpp:345
CompanyStationsWindow::DrawWidget
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition station_gui.cpp:495
CompanyStationsWindow::StationTypeSorter
static bool StationTypeSorter(const Station *const &a, const Station *const &b, const CargoTypes &)
Sort stations by their type.
Definition station_gui.cpp:353
CompanyStationsWindow::OnGameTick
void OnGameTick() override
Called once per (game) tick.
Definition station_gui.cpp:724
CompanyStationsWindow::StationWaitingTotalSorter
static bool StationWaitingTotalSorter(const Station *const &a, const Station *const &b, const CargoTypes &cargo_filter)
Sort stations by their waiting cargo.
Definition station_gui.cpp:359
CompanyStationsWindow::BuildStationsList
void BuildStationsList(const Owner owner)
(Re)Build station list
Definition station_gui.cpp:303
CompanyStationsWindow::stations_per_cargo_type_no_rating
uint16_t stations_per_cargo_type_no_rating
Number of stations without a rating.
Definition station_gui.cpp:296
DropDownCheck
Drop down checkmark component.
Definition dropdown_common_type.h:157
DropDownString
Drop down string component.
Definition dropdown_common_type.h:56
EnumBitSet< StationFacility, uint8_t >
FlowStatMap
Flow descriptions by origin stations.
Definition station_base.h:149
GUIList
List template of 'things' T to sort in a GUI.
Definition sortlist_type.h:43
GUIList::RebuildDone
void RebuildDone()
Notify the sortlist that the rebuild is done.
Definition sortlist_type.h:405
GUIList::SetListing
void SetListing(Listing l)
Import sort conditions.
Definition sortlist_type.h:148
GUIList::IsDescSortOrder
bool IsDescSortOrder() const
Check if the sort order is descending.
Definition sortlist_type.h:242
GUIList::ToggleSortOrder
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
Definition sortlist_type.h:252
GUIList::NeedRebuild
bool NeedRebuild() const
Check if a rebuild is needed.
Definition sortlist_type.h:387
GUIList::ForceRebuild
void ForceRebuild()
Force that a rebuild is needed.
Definition sortlist_type.h:395
GUIList::Sort
bool Sort(Comp compare)
Sort the list.
Definition sortlist_type.h:266
GUIList::ForceResort
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
Definition sortlist_type.h:232
GUIList::SortType
uint8_t SortType() const
Get the sorttype of the list.
Definition sortlist_type.h:110
GUIList::GetListing
Listing GetListing() const
Export current sort conditions.
Definition sortlist_type.h:134
GUIList::SetSortFuncs
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
Definition sortlist_type.h:293
GUIList::NeedResort
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
Definition sortlist_type.h:218
GUIList::SetSortType
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
Definition sortlist_type.h:120
LinkGraph
A connected component of a link graph.
Definition linkgraph.h:37
LinkGraph::Monthly
uint Monthly(uint base) const
Scale a value to its monthly equivalent, based on last compression.
Definition linkgraph.h:249
NWidgetBase
Baseclass for nested widgets.
Definition widget_type.h:137
NWidgetCore
Base class for a 'real' widget.
Definition widget_type.h:371
NWidgetCore::SetStringTip
void SetStringTip(StringID string, StringID tool_tip)
Set string and tool tip of the nested widget.
Definition widget.cpp:1192
Scrollbar
Scrollbar data structure.
Definition widget_type.h:711
Scrollbar::GetCapacity
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition widget_type.h:746
Scrollbar::SetCount
void SetCount(size_t num)
Sets the number of elements in the list.
Definition widget_type.h:795
Scrollbar::GetScrolledItemFromWidget
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.
Definition widget_type.h:894
Scrollbar::GetScrolledRowFromWidget
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition widget.cpp:2453
Scrollbar::SetCapacityFromWidget
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:2527
Scrollbar::GetCount
size_type GetCount() const
Gets the number of elements in the list.
Definition widget_type.h:737
Scrollbar::GetVisibleRangeIterators
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Definition widget_type.h:875
Scrollbar::GetPosition
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition widget_type.h:755
SpiralTileSequence
Generate TileIndices around a center tile or tile area, with increasing distance.
Definition tilearea_type.h:316
StationCargoList
CargoList that is used for stations.
Definition cargopacket.h:519
StationCargoList::ReservedCount
uint ReservedCount() const
Returns sum of cargo reserved for loading onto vehicles.
Definition cargopacket.h:587
TimerGameEconomy::UsingWallclockUnits
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
Definition timer_game_economy.cpp:98
WidgetDimensions::framerect
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
WidgetDimensions::scaled
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
WidgetDimensions::vsep_wide
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:60
WidgetDimensions::hsep_wide
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
WidgetDimensions::hsep_normal
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
WidgetDimensions::hsep_indent
int hsep_indent
Width of indentation for tree layouts.
Definition window_gui.h:63
command_func.h
Functions related to commands.
company_base.h
Definition of stuff that is very close to a company, like the company struct itself.
_local_company
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition company_cmd.cpp:55
company_func.h
Functions related to companies.
OWNER_NONE
static constexpr Owner OWNER_NONE
The tile has no ownership.
Definition company_type.h:26
DivideApprox
int DivideApprox(int a, int b)
Deterministic approximate division.
Definition math_func.cpp:22
debug.h
Functions related to debugging.
Debug
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
DIR_N
@ DIR_N
North.
Definition direction_type.h:26
ShowDropDownMenu
void ShowDropDownMenu(Window *w, std::span< const StringID > strings, int selected, WidgetID button, uint32_t disabled_mask, uint32_t hidden_mask, uint width)
Show a dropdown menu window near a widget of the parent window.
Definition dropdown.cpp:458
ShowDropDownList
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options)
Show a drop down list.
Definition dropdown.cpp:418
dropdown_common_type.h
Common drop down list components.
dropdown_func.h
Functions related to the drop down widget.
dropdown_type.h
Types related to the drop down widget.
DropDownList
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
Definition dropdown_type.h:56
DropDownOption::Persist
@ Persist
Set if this dropdown should stay open after an option is selected.
to_underlying
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
GetCharacterHeight
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
maxdim
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Definition geometry_func.cpp:22
geometry_func.hpp
Geometry functions.
CentreBounds
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
Definition geometry_type.hpp:26
GetStringBoundingBox
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:897
GetStringListBoundingBox
Dimension GetStringListBoundingBox(std::span< const StringID > list, FontSize fontsize)
Get maximum dimension of a list of strings.
Definition gfx.cpp:935
DrawString
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:668
_ctrl_pressed
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
DrawSprite
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1034
GetCharacterWidth
uint8_t GetCharacterWidth(FontSize size, char32_t key)
Return width of character glyph.
Definition gfx.cpp:1273
DrawStringMultiLine
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:785
GfxFillRect
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:115
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
FS_SMALL
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:250
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
SA_CENTER
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
TextColour
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
SetFill
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition widget_type.h:1222
SetSpriteTip
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
Definition widget_type.h:1254
SetScrollbar
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition widget_type.h:1402
SetStringTip
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
Definition widget_type.h:1243
SetAspect
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
Definition widget_type.h:1413
SetTextStyle
constexpr NWidgetPart SetTextStyle(TextColour colour, FontSize size=FS_NORMAL)
Widget part function for setting the text style.
Definition widget_type.h:1201
SetMinimalSize
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition widget_type.h:1159
SetToolTip
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
Definition widget_type.h:1321
EndContainer
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition widget_type.h:1232
NWidget
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
Definition widget_type.h:1427
SetResize
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition widget_type.h:1148
Window::SetDirty
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:968
gui.h
GUI functions that shouldn't be here.
ShowExtraViewportWindow
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Definition viewport_gui.cpp:159
linkgraph.h
Declaration of link graph classes used for cargo distribution.
DT_MANUAL
@ DT_MANUAL
Manual distribution. No link graph calculations are run.
Definition linkgraph_type.h:24
DistanceMax
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition map.cpp:201
TileAddXY
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:483
TileVirtXY
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:416
TileAddByDir
TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition map_func.h:612
TileXY
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:385
TileY
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:438
TileX
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:428
IsInsideBS
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
Definition math_func.hpp:252
CeilDiv
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition math_func.hpp:310
ToPercent8
constexpr uint ToPercent8(uint i)
Converts a "fract" value 0..255 to "percent" value 0..100.
Definition math_func.hpp:285
ShowQueryString
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.
Definition misc_gui.cpp:1064
misc_widget.h
Types related to the misc widgets.
WID_QS_MOVE
@ WID_QS_MOVE
Move button.
Definition misc_widget.h:39
CargoFilterCriteria::CF_EXPAND_LIST
static constexpr CargoType CF_EXPAND_LIST
Expand list to show all items (station list)
Definition cargo_type.h:100
CargoFilterCriteria::CF_NO_RATING
static constexpr CargoType CF_NO_RATING
Show items with no rating (station list)
Definition cargo_type.h:98
CargoFilterCriteria::CF_SELECT_ALL
static constexpr CargoType CF_SELECT_ALL
Select all items (station list)
Definition cargo_type.h:99
Invalid
@ Invalid
GRF is unusable with this version of OpenTTD.
Definition newgrf_config.h:28
GetContrastColour
TextColour GetContrastColour(PixelColour background, uint8_t threshold)
Determine a contrasty text colour for a coloured background.
Definition palette.cpp:361
PC_GREEN
static constexpr PixelColour PC_GREEN
Green palette colour.
Definition palette_func.h:113
PC_RED
static constexpr PixelColour PC_RED
Red palette colour.
Definition palette_func.h:103
safeguards.h
A number of safeguards to prevent using unsafe methods.
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
sortlist_type.h
Base types for having sorted lists in GUIs.
SortListFlag::Resort
@ Resort
instruct the code to resort the list in the next loop
station_base.h
Base classes/functions for stations.
GetAcceptanceAroundTiles
CargoArray GetAcceptanceAroundTiles(TileIndex center_tile, int w, int h, int rad, CargoTypes *always_accepted)
Get the acceptance of cargoes around the tile in 1/8.
Definition station_cmd.cpp:571
HasStationInUse
bool HasStationInUse(StationID station, bool include_company, CompanyID company)
Tests whether the company's vehicles have this station in orders.
Definition station_cmd.cpp:2859
GetAcceptanceMask
CargoTypes GetAcceptanceMask(const Station *st)
Get a mask of the cargo types that the station accepts.
Definition station_cmd.cpp:489
GetProductionAroundTiles
CargoArray GetProductionAroundTiles(TileIndex north_tile, int w, int h, int rad)
Get the cargo types being produced around the tile (in a rectangle).
Definition station_cmd.cpp:533
station_cmd.h
Command definitions related to stations.
StationsWndShowStationRating
static void StationsWndShowStationRating(int left, int right, int y, CargoType cargo, uint amount, uint8_t rating)
Draw small boxes of cargo amount and ratings data at the given coordinates.
Definition station_gui.cpp:219
ShowSelectStationIfNeeded
void ShowSelectStationIfNeeded(TileArea ta, StationPickerCmdProc proc)
Show the station selection window when needed.
Definition station_gui.cpp:2475
CargoSortType
CargoSortType
Definition station_gui.cpp:861
CargoSortType::StationID
@ StationID
by station id
CargoSortType::CargoType
@ CargoType
by cargo type
CargoSortType::AsGrouping
@ AsGrouping
by the same principle the entries are being grouped
CargoSortType::StationString
@ StationString
by station name
CargoSortType::Count
@ Count
by amount of cargo
ShowSelectRailWaypointIfNeeded
void ShowSelectRailWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
Show the rail waypoint selection window when needed.
Definition station_gui.cpp:2485
FindStationsAroundSelection
void FindStationsAroundSelection()
Find stations adjacent to the current tile highlight area, so that existing coverage area can be draw...
Definition station_gui.cpp:108
DrawStationCoverageAreaText
int DrawStationCoverageAreaText(const Rect &r, StationCoverageType sct, int rad, bool supplies)
Calculates and draws the accepted or supplied cargo around the selected tile(s)
Definition station_gui.cpp:77
ShowStationViewWindow
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
Definition station_gui.cpp:2174
CheckRedrawStationCoverage
void CheckRedrawStationCoverage(const Window *w)
Check whether we need to redraw the station coverage text.
Definition station_gui.cpp:159
ShowCompanyStations
void ShowCompanyStations(CompanyID company)
Opens window with list of company's stations.
Definition station_gui.cpp:808
ShowSelectBaseStationIfNeeded
void ShowSelectBaseStationIfNeeded(TileArea ta, StationPickerCmdProc &&proc)
Show the station selection window when needed.
Definition station_gui.cpp:2459
FindStationsNearby
static void FindStationsNearby(TileArea ta, bool distant_join)
Circulate around the to-be-built station to find stations we could join.
Definition station_gui.cpp:2234
AddNearbyStation
static void AddNearbyStation(TileIndex tile, TileArea *ctx)
Add station on this tile to _stations_nearby_list if it's fully within the station spread.
Definition station_gui.cpp:2196
StationJoinerNeeded
static bool StationJoinerNeeded(const StationPickerCmdProc &proc)
Check whether we need to show the station selection window.
Definition station_gui.cpp:2431
ShowSelectRoadWaypointIfNeeded
void ShowSelectRoadWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
Show the road waypoint selection window when needed.
Definition station_gui.cpp:2495
station_gui.h
Contains enums and function declarations connected with stations GUI.
StationCoverageType
StationCoverageType
Types of cargo to display for station coverage.
Definition station_gui.h:21
SCT_NON_PASSENGERS_ONLY
@ SCT_NON_PASSENGERS_ONLY
Draw all non-passenger class cargoes.
Definition station_gui.h:23
SCT_PASSENGERS_ONLY
@ SCT_PASSENGERS_ONLY
Draw only passenger class cargoes.
Definition station_gui.h:22
SCT_ALL
@ SCT_ALL
Draw all cargoes.
Definition station_gui.h:24
GetStationIndex
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
StationFacility
StationFacility
The facilities a station might be having.
Definition station_type.h:50
StationFacility::Dock
@ Dock
Station with a dock.
StationFacility::TruckStop
@ TruckStop
Station with truck stops.
StationFacility::Train
@ Train
Station with train station.
StationFacility::Airport
@ Airport
Station with an airport.
StationFacility::BusStop
@ BusStop
Station with bus stops.
MAX_LENGTH_STATION_NAME_CHARS
static const uint MAX_LENGTH_STATION_NAME_CHARS
The maximum length of a station name in characters including '\0'.
Definition station_type.h:124
station_widget.h
Types related to the station widgets.
WID_SV_CLOSE_AIRPORT
@ WID_SV_CLOSE_AIRPORT
'Close airport' button.
Definition station_widget.h:26
WID_SV_SORT_ORDER
@ WID_SV_SORT_ORDER
'Sort order' button
Definition station_widget.h:18
WID_SV_CATCHMENT
@ WID_SV_CATCHMENT
Toggle catchment area highlight.
Definition station_widget.h:32
WID_SV_ROADVEHS
@ WID_SV_ROADVEHS
List of scheduled road vehs button.
Definition station_widget.h:29
WID_SV_SCROLLBAR
@ WID_SV_SCROLLBAR
Scrollbar.
Definition station_widget.h:21
WID_SV_CAPTION
@ WID_SV_CAPTION
Caption of the window.
Definition station_widget.h:15
WID_SV_GROUP
@ WID_SV_GROUP
label for "group by"
Definition station_widget.h:16
WID_SV_RENAME
@ WID_SV_RENAME
'Rename' button.
Definition station_widget.h:25
WID_SV_SORT_BY
@ WID_SV_SORT_BY
'Sort by' button
Definition station_widget.h:19
WID_SV_GROUP_BY
@ WID_SV_GROUP_BY
'Group by' button
Definition station_widget.h:17
WID_SV_PLANES
@ WID_SV_PLANES
List of scheduled planes button.
Definition station_widget.h:31
WID_SV_ACCEPT_RATING_LIST
@ WID_SV_ACCEPT_RATING_LIST
List of accepted cargoes / rating of cargoes.
Definition station_widget.h:22
WID_SV_WAITING
@ WID_SV_WAITING
List of waiting cargo.
Definition station_widget.h:20
WID_SV_SHIPS
@ WID_SV_SHIPS
List of scheduled ships button.
Definition station_widget.h:30
WID_SV_LOCATION
@ WID_SV_LOCATION
'Location' button.
Definition station_widget.h:23
WID_SV_TRAINS
@ WID_SV_TRAINS
List of scheduled trains button.
Definition station_widget.h:28
WID_SV_ACCEPTS_RATINGS
@ WID_SV_ACCEPTS_RATINGS
'Accepts' / 'Ratings' button.
Definition station_widget.h:24
WID_SV_CLOSE_AIRPORT_SEL
@ WID_SV_CLOSE_AIRPORT_SEL
Container for 'close airport' button, which can be hidden.
Definition station_widget.h:27
WID_STL_CAPTION
@ WID_STL_CAPTION
Caption of the window.
Definition station_widget.h:38
WID_STL_TRUCK
@ WID_STL_TRUCK
'TRUCK' button - list only facilities where is a truck stop.
Definition station_widget.h:44
WID_STL_SCROLLBAR
@ WID_STL_SCROLLBAR
Scrollbar next to the main panel.
Definition station_widget.h:40
WID_STL_SORTDROPBTN
@ WID_STL_SORTDROPBTN
Dropdown button.
Definition station_widget.h:51
WID_STL_SORTBY
@ WID_STL_SORTBY
'Sort by' button - reverse sort direction.
Definition station_widget.h:50
WID_STL_TRAIN
@ WID_STL_TRAIN
'TRAIN' button - list only facilities where is a railroad station.
Definition station_widget.h:43
WID_STL_BUS
@ WID_STL_BUS
'BUS' button - list only facilities where is a bus stop.
Definition station_widget.h:45
WID_STL_FACILALL
@ WID_STL_FACILALL
'ALL' button - list all facilities.
Definition station_widget.h:48
WID_STL_LIST
@ WID_STL_LIST
The main panel, list of stations.
Definition station_widget.h:39
WID_STL_SHIP
@ WID_STL_SHIP
'SHIP' button - list only facilities where is a dock.
Definition station_widget.h:47
WID_STL_CARGODROPDOWN
@ WID_STL_CARGODROPDOWN
Cargo type dropdown list.
Definition station_widget.h:53
WID_STL_AIRPLANE
@ WID_STL_AIRPLANE
'AIRPLANE' button - list only facilities where is an airport.
Definition station_widget.h:46
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
StrNaturalCompare
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition string.cpp:427
string_func.h
Functions related to low-level strings.
CS_ALPHANUMERAL
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
_current_text_dir
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
strings_func.h
Functions related to OTTD's strings.
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition strings_type.h:19
TD_RTL
@ TD_RTL
Text is written right-to-left by default.
Definition strings_type.h:27
Airport::blocks
AirportBlocks blocks
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
Definition station_base.h:374
BaseStation
Base class for all station-ish types.
Definition base_station_base.h:58
BaseStation::xy
TileIndex xy
Base tile of the station.
Definition base_station_base.h:59
BaseStation::facilities
StationFacilities facilities
The facilities that this station has.
Definition base_station_base.h:69
BaseStation::owner
Owner owner
The owner of this station.
Definition base_station_base.h:68
BaseStation::rect
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Definition base_station_base.h:84
BaseStation::town
Town * town
The town this station is associated with.
Definition base_station_base.h:67
CargoArray
Class for storing amounts of cargo.
Definition cargo_type.h:111
CargoPacket
Container for cargo from the same location and time.
Definition cargopacket.h:41
CargoPacket::Count
uint16_t Count() const
Gets the number of 'items' in this packet.
Definition cargopacket.h:158
CargoPacket::GetFirstStation
StationID GetFirstStation() const
Gets the ID of the station where the cargo was loaded for the first time.
Definition cargopacket.h:209
CargoSpec
Specification of a cargo type.
Definition cargotype.h:74
CargoSpec::Get
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
CargoSpec::abbrev
StringID abbrev
Two letter abbreviation for this cargo type.
Definition cargotype.h:95
CargoSpec::GetCargoIcon
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition cargotype.cpp:176
CargoSpec::name
StringID name
Name of this type of cargo.
Definition cargotype.h:91
CargoSpec::IsValid
bool IsValid() const
Tests for validity of this cargospec.
Definition cargotype.h:118
ClientSettings::gui
GUISettings gui
settings related to the GUI
Definition settings_type.h:650
CommandHelper
Definition command_func.h:84
CompanyStationsWindow::FilterState
Definition station_gui.cpp:265
CompanyStationsWindow::FilterState::cargoes
CargoTypes cargoes
bitmap of cargo types to include
Definition station_gui.cpp:269
CompanyStationsWindow::FilterState::facilities
StationFacilities facilities
types of stations of interest
Definition station_gui.cpp:267
CompanyStationsWindow::FilterState::include_no_rating
bool include_no_rating
Whether we should include stations with no cargo rating.
Definition station_gui.cpp:268
Coord2D< int >
Coord2D::y
T y
Y coordinate.
Definition geometry_type.hpp:35
Coord2D::x
T x
X coordinate.
Definition geometry_type.hpp:34
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition geometry_type.hpp:56
GUISettings::persistent_buildingtools
bool persistent_buildingtools
keep the building tools active after usage
Definition settings_type.h:225
GUISettings::station_gui_group_order
uint8_t station_gui_group_order
the order of grouping cargo entries in the station gui
Definition settings_type.h:242
GUISettings::station_gui_sort_order
uint8_t station_gui_sort_order
the sort order of entries in the station gui - ascending or descending
Definition settings_type.h:244
GUISettings::station_show_coverage
bool station_show_coverage
whether to highlight coverage area
Definition settings_type.h:224
GUISettings::station_gui_sort_by
uint8_t station_gui_sort_by
sort cargo entries in the station gui by station name or amount
Definition settings_type.h:243
GameSettings::station
StationSettings station
settings related to station management
Definition settings_type.h:644
GameSettings::linkgraph
LinkGraphSettings linkgraph
settings for link graph calculations
Definition settings_type.h:643
GenericWaypointTypeFilter
Definition station_gui.cpp:58
GoodsEntry::GoodsEntryData::flows
FlowStatMap flows
Planned flows through this station.
Definition station_base.h:214
GoodsEntry::GoodsEntryData::cargo
StationCargoList cargo
The cargo packets of cargo waiting in this station.
Definition station_base.h:213
GoodsEntry
Stores station stats for a single cargo.
Definition station_base.h:167
GoodsEntry::HasRating
bool HasRating() const
Does this cargo have a rating at this station?
Definition station_base.h:267
GoodsEntry::node
NodeID node
ID of node in link graph referring to this goods entry.
Definition station_base.h:223
GoodsEntry::GetData
const GoodsEntryData & GetData() const
Get optional cargo packet/flow data.
Definition station_base.h:317
GoodsEntry::link_graph
LinkGraphID link_graph
Link graph this station belongs to.
Definition station_base.h:224
GoodsEntry::rating
uint8_t rating
Station rating for this cargo.
Definition station_base.h:235
GoodsEntry::HasData
bool HasData() const
Test if this goods entry has optional cargo packet/flow data.
Definition station_base.h:305
Listing
Data structure describing how to show the list (what sort direction and criteria).
Definition sortlist_type.h:26
Map::MaxY
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:308
Map::MaxX
static uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:299
Map::Size
static uint Size()
Get the size of the map.
Definition map_func.h:290
OrthogonalTileArea
Represents the covered area of e.g.
Definition tilearea_type.h:18
OrthogonalTileArea::w
uint16_t w
The width of the area.
Definition tilearea_type.h:20
OrthogonalTileArea::tile
TileIndex tile
The base tile of the area.
Definition tilearea_type.h:19
OrthogonalTileArea::h
uint16_t h
The height of the area.
Definition tilearea_type.h:21
PixelColour
Colour for pixel/line drawing.
Definition gfx_type.h:405
PoolID< uint16_t, struct StationIDTag, 64000, 0xFFFF >
Pool::PoolItem<&_station_pool >::Iterate
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition pool_type.hpp:436
Pool::PoolItem<&_station_pool >::Get
static Titem * Get(auto index)
Returns Titem with given index.
Definition pool_type.hpp:387
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Pool::PoolItem<&_company_pool >::IsValidID
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition pool_type.hpp:376
Pool::PoolItem<&_link_graph_pool >::GetIfValid
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Definition pool_type.hpp:398
Rect
Specification of a rectangle with absolute coordinates of all edges.
Definition geometry_type.hpp:101
Rect::WithWidth
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Definition geometry_type.hpp:211
Rect::Width
int Width() const
Get width of Rect.
Definition geometry_type.hpp:111
Rect::Shrink
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Definition geometry_type.hpp:124
Rect::Indent
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Definition geometry_type.hpp:224
ResizeInfo::step_height
uint step_height
Step-size of height resize changes.
Definition window_gui.h:213
SelectStationWindow
Window for selecting stations/waypoints to (distant) join to.
Definition station_gui.cpp:2294
SelectStationWindow::DrawWidget
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition station_gui.cpp:2342
SelectStationWindow::OnRealtimeTick
void OnRealtimeTick(uint delta_ms) override
Called periodically.
Definition station_gui.cpp:2375
SelectStationWindow::OnClick
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition station_gui.cpp:2361
SelectStationWindow::OnInvalidateData
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition station_gui.cpp:2393
SelectStationWindow::OnResize
void OnResize() override
Called after the window got resized.
Definition station_gui.cpp:2383
SelectStationWindow::Close
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition station_gui.cpp:2313
SelectStationWindow::OnMouseOver
void OnMouseOver(Point pt, WidgetID widget) override
The mouse is currently moving over the window or has just moved outside of the window.
Definition station_gui.cpp:2401
SelectStationWindow::area
TileArea area
Location of new station.
Definition station_gui.cpp:2296
SelectStationWindow::UpdateWidgetSize
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.
Definition station_gui.cpp:2321
SetBitIterator
Iterable ensemble of each set bit in a value.
Definition bitmath_func.hpp:277
SpecializedStation< Station, false >::IsValidID
static bool IsValidID(auto index)
Tests whether given index is a valid index for station of this type.
Definition base_station_base.h:239
SpecializedStation< Station, false >::IsExpected
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
Definition base_station_base.h:229
SpecializedStation< Station, false >::Iterate
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
Definition base_station_base.h:299
SpecializedStation< Waypoint, true >::Get
static Waypoint * Get(auto index)
Gets station with given index.
Definition base_station_base.h:248
SpecializedStation< Waypoint, true >::From
static Waypoint * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
Definition base_station_base.h:277
StationSettings::station_spread
uint8_t station_spread
amount a station may spread
Definition settings_type.h:597
StationSettings::distant_join_stations
bool distant_join_stations
allow to join non-adjacent stations
Definition settings_type.h:595
StationTypeFilter
Definition station_gui.cpp:47
StationViewWindow::RowDisplay
A row being displayed in the cargo view (as opposed to being "hidden" behind a plus sign).
Definition station_gui.cpp:1224
StationViewWindow::RowDisplay::next_station
StationID next_station
ID of the station belonging to the entry actually displayed if it's to/from/via.
Definition station_gui.cpp:1236
StationViewWindow::RowDisplay::filter
CargoDataEntry * filter
Parent of the cargo entry belonging to the row.
Definition station_gui.cpp:1231
StationViewWindow::RowDisplay::next_cargo
CargoType next_cargo
ID of the cargo belonging to the entry actually displayed if it's cargo.
Definition station_gui.cpp:1241
StationViewWindow
The StationView window.
Definition station_gui.cpp:1220
StationViewWindow::HandleCargoWaitingClick
void HandleCargoWaitingClick(int row)
Handle a click on a specific row in the cargo view.
Definition station_gui.cpp:1937
StationViewWindow::DrawEntries
int DrawEntries(CargoDataEntry &entry, const Rect &r, int pos, int maxrows, int column, CargoType cargo=INVALID_CARGO)
Draw the given cargo entries in the station GUI.
Definition station_gui.cpp:1799
StationViewWindow::OnQueryTextFinished
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
Definition station_gui.cpp:2133
StationViewWindow::OnDropdownSelect
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
Definition station_gui.cpp:2124
StationViewWindow::Mode
Mode
Display mode of the cargo view.
Definition station_gui.cpp:1270
StationViewWindow::MODE_PLANNED
@ MODE_PLANNED
Show cargo planned to pass through the station.
Definition station_gui.cpp:1272
StationViewWindow::MODE_WAITING
@ MODE_WAITING
Show cargo waiting at the station.
Definition station_gui.cpp:1271
StationViewWindow::groupings
std::array< Grouping, NUM_COLUMNS > groupings
Grouping modes for the different columns.
Definition station_gui.cpp:1317
StationViewWindow::EstimateDestinations
void EstimateDestinations(CargoType cargo, StationID source, StationID next, uint count, CargoDataEntry &dest)
Estimate the amounts of cargo per final destination for a given cargo, source station and next hop an...
Definition station_gui.cpp:1527
StationViewWindow::SelectSortBy
void SelectSortBy(int index)
Select a new sort criterium for the cargo view.
Definition station_gui.cpp:2052
StationViewWindow::OnResize
void OnResize() override
Called after the window got resized.
Definition station_gui.cpp:2140
StationViewWindow::SearchNonStop
StringID SearchNonStop(CargoDataEntry &cd, StationID station, int column)
Determine if we need to show the special "non-stop" string.
Definition station_gui.cpp:1739
StationViewWindow::Close
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition station_gui.cpp:1347
StationViewWindow::Grouping
Grouping
Type of grouping used in each of the "columns".
Definition station_gui.cpp:1260
StationViewWindow::GR_SOURCE
@ GR_SOURCE
Group by source of cargo ("from").
Definition station_gui.cpp:1261
StationViewWindow::GR_NEXT
@ GR_NEXT
Group by next station ("via").
Definition station_gui.cpp:1262
StationViewWindow::GR_CARGO
@ GR_CARGO
Group by cargo type.
Definition station_gui.cpp:1264
StationViewWindow::GR_DESTINATION
@ GR_DESTINATION
Group by estimated final destination ("to").
Definition station_gui.cpp:1263
StationViewWindow::BuildCargoList
void BuildCargoList(CargoType cargo, const StationCargoList &packets, CargoDataEntry *entry)
Build up the cargo view for WAITING mode and a specific cargo.
Definition station_gui.cpp:1606
StationViewWindow::DrawCargoRatings
int DrawCargoRatings(const Rect &r) const
Draw cargo ratings in the WID_SV_ACCEPT_RATING_LIST widget.
Definition station_gui.cpp:1888
StationViewWindow::NUM_COLUMNS
static const int NUM_COLUMNS
Number of "columns" in the cargo view: cargo, from, via, to.
Definition station_gui.cpp:1247
StationViewWindow::OnInit
void OnInit() override
Notification that the nested widget tree gets initialized.
Definition station_gui.cpp:1340
StationViewWindow::RecalcDestinations
void RecalcDestinations(CargoType cargo)
Rebuild the cache for estimated destinations which is used to quickly show the "destination" entries ...
Definition station_gui.cpp:1493
StationViewWindow::line_height
int line_height
Height of a cargo line.
Definition station_gui.cpp:1278
StationViewWindow::cargo_icon_size
Dimension cargo_icon_size
Size of largest cargo icon.
Definition station_gui.cpp:1279
StationViewWindow::Invalidation
Invalidation
Type of data invalidation.
Definition station_gui.cpp:1252
StationViewWindow::INV_FLOWS
@ INV_FLOWS
The planned flows have been recalculated and everything has to be updated.
Definition station_gui.cpp:1253
StationViewWindow::INV_CARGO
@ INV_CARGO
Some cargo has been added or removed.
Definition station_gui.cpp:1254
StationViewWindow::BuildCargoList
void BuildCargoList(CargoDataEntry *entry, const Station *st)
Build up the cargo view for all cargoes.
Definition station_gui.cpp:1653
StationViewWindow::SelectSortOrder
void SelectSortOrder(SortOrder order)
Select a new sort order for the cargo view.
Definition station_gui.cpp:2041
StationViewWindow::expanded_rows
CargoDataEntry expanded_rows
Parent entry of currently expanded rows.
Definition station_gui.cpp:1319
StationViewWindow::OnPaint
void OnPaint() override
The window must be repainted.
Definition station_gui.cpp:1418
StationViewWindow::RATING_LINES
static constexpr uint RATING_LINES
Height in lines of the cargo ratings view.
Definition station_gui.cpp:1283
StationViewWindow::displayed_rows
CargoDataVector displayed_rows
Parent entry of currently displayed rows (including collapsed ones).
Definition station_gui.cpp:1321
StationViewWindow::group_names
static const StringID group_names[]
Names of the grouping options in the dropdown.
Definition station_gui.cpp:1294
StationViewWindow::grouping_index
int grouping_index
Currently selected entry in the grouping drop down.
Definition station_gui.cpp:1315
StationViewWindow::UpdateWidgetSize
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.
Definition station_gui.cpp:1404
StationViewWindow::ACCEPTS_LINES
static constexpr uint ACCEPTS_LINES
Height in lines of the accepted cargo view.
Definition station_gui.cpp:1284
StationViewWindow::OnInvalidateData
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition station_gui.cpp:2150
StationViewWindow::GetEntryString
StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any) const
Select the correct string for an entry referring to the specified station.
Definition station_gui.cpp:1709
StationViewWindow::sortings
std::array< CargoSortType, NUM_COLUMNS > sortings
Sort types of the different 'columns'.
Definition station_gui.cpp:1309
StationViewWindow::SetDisplayedRow
void SetDisplayedRow(const CargoDataEntry &entry)
Mark a specific row, characterized by its CargoDataEntry, as expanded.
Definition station_gui.cpp:1676
StationViewWindow::GetWidgetString
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition station_gui.cpp:1478
StationViewWindow::sort_orders
std::array< SortOrder, NUM_COLUMNS > sort_orders
Sort order (ascending/descending) for the 'columns'.
Definition station_gui.cpp:1312
StationViewWindow::expand_shrink_width
uint expand_shrink_width
The width allocated to the expand/shrink 'button'.
Definition station_gui.cpp:1275
StationViewWindow::HandleCargoWaitingClick
void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
Expand or collapse a specific row.
Definition station_gui.cpp:1924
StationViewWindow::rating_lines
int rating_lines
Number of lines in the cargo ratings view.
Definition station_gui.cpp:1276
StationViewWindow::sort_names
static const StringID sort_names[]
Names of the sorting options in the dropdown.
Definition station_gui.cpp:1287
StationViewWindow::DrawCargoIcons
void DrawCargoIcons(CargoType cargo, uint waiting, const Rect &r) const
Draw icons of waiting cargo.
Definition station_gui.cpp:1773
StationViewWindow::cached_destinations
CargoDataEntry cached_destinations
Cache for the flows passing through this station.
Definition station_gui.cpp:1320
StationViewWindow::scroll_to_row
int scroll_to_row
If set, scroll the main viewport to the station pointed to by this row.
Definition station_gui.cpp:1314
StationViewWindow::current_mode
Mode current_mode
Currently selected display mode of cargo view.
Definition station_gui.cpp:1316
StationViewWindow::accepts_lines
int accepts_lines
Number of lines in the accepted cargo view.
Definition station_gui.cpp:1277
StationViewWindow::BuildFlowList
void BuildFlowList(CargoType cargo, const FlowStatMap &flows, CargoDataEntry *entry)
Build up the cargo view for PLANNED mode and a specific cargo.
Definition station_gui.cpp:1583
StationViewWindow::SelectGroupBy
void SelectGroupBy(int index)
Select a new grouping mode for the cargo view.
Definition station_gui.cpp:2084
StationViewWindow::OnClick
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition station_gui.cpp:1953
StationViewWindow::DrawAcceptedCargo
int DrawAcceptedCargo(const Rect &r) const
Draw accepted cargo in the WID_SV_ACCEPT_RATING_LIST widget.
Definition station_gui.cpp:1874
StationViewWindow::ShowCargo
void ShowCargo(CargoDataEntry *data, CargoType cargo, StationID source, StationID next, StationID dest, uint count)
Show a certain cargo entry characterized by source/next/dest station, cargo type and amount of cargo ...
Definition station_gui.cpp:1368
Station
Station data structure.
Definition station_base.h:520
Station::goods
std::array< GoodsEntry, NUM_CARGO > goods
Goods at this station.
Definition station_base.h:549
Station::airport
Airport airport
Tile area the airport covers.
Definition station_base.h:534
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
TileAndStation
Struct containing TileIndex and StationID.
Definition station_gui.cpp:2180
TileAndStation::tile
TileIndex tile
TileIndex.
Definition station_gui.cpp:2181
TileAndStation::station
StationID station
StationID.
Definition station_gui.cpp:2182
TileHighlightData::drawstyle
HighLightStyle drawstyle
Lower bits 0-3 are reserved for detailed highlight information.
Definition tilehighlight_type.h:64
TileHighlightData::dirty
uint8_t dirty
Whether the build station window needs to redraw due to the changed selection.
Definition tilehighlight_type.h:58
TileHighlightData::size
Point size
Size, in tile "units", of the white/red selection area.
Definition tilehighlight_type.h:48
TileHighlightData::pos
Point pos
Location, in tile "units", of the northern tile of the selected area.
Definition tilehighlight_type.h:47
TileHighlightData::freeze
bool freeze
Freeze highlight in place.
Definition tilehighlight_type.h:53
Town::exclusivity
CompanyID exclusivity
which company has exclusivity
Definition town.h:84
Town::exclusive_counter
uint8_t exclusive_counter
months till the exclusivity expires
Definition town.h:85
VehicleListIdentifier
The information about a vehicle list.
Definition vehiclelist.h:32
Waypoint
Representation of a waypoint.
Definition waypoint_base.h:23
WindowDesc
High level window description.
Definition window_gui.h:168
WindowNumber
Number to differentiate different windows of the same class.
Definition window_type.h:760
Window
Data structure for an opened window.
Definition window_gui.h:274
Window::ReInit
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:980
Window::Close
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1104
Window::SortButtonWidth
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:833
Window::FinishInitNested
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1809
Window::DrawWidgets
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:784
Window::parent
Window * parent
Parent window.
Definition window_gui.h:329
Window::RaiseWidget
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:470
Window::SetWidgetDirty
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:558
Window::GetWidgetString
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:506
Window::DrawSortButtonState
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:816
Window::CloseChildWindows
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1077
Window::resize
ResizeInfo resize
Resize information.
Definition window_gui.h:315
Window::CreateNestedTree
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1799
Window::window_class
WindowClass window_class
Window class.
Definition window_gui.h:302
Window::IsWidgetLowered
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition window_gui.h:492
Window::owner
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
Window::SetWidgetLoweredState
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
Window::IsShaded
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:560
Window::SetTimeout
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:356
Window::LowerWidget
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:461
Window::GetScrollbar
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:315
Window::SetWidgetDisabledState
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
Window::width
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
Window::ToggleWidgetLoweredState
void ToggleWidgetLoweredState(WidgetID widget_index)
Invert the lowered/raised status of a widget.
Definition window_gui.h:451
Window::window_number
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
textbuf_gui.h
Stuff related to the text buffer GUI.
QueryStringFlag::EnableMove
@ EnableMove
enable the 'Move' button
QueryStringFlag::EnableDefault
@ EnableDefault
enable the 'Default' button ("\0" is returned)
QueryStringFlag::LengthIsInChars
@ LengthIsInChars
the length of the string is counted in characters
IsTileType
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
GetTileOwner
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
INVALID_TILE
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
TILE_SIZE
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
MP_STATION
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
tilehighlight_func.h
Functions related to tile highlights.
ResetObjectToPlace
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition viewport.cpp:3573
UpdateTileSelection
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition viewport.cpp:2679
HT_RECT
@ HT_RECT
rectangle (stations, depots, ...)
Definition tilehighlight_type.h:21
town.h
Base of the town class.
vehicle_gui.h
Functions related to the vehicle's GUIs.
VehicleType
VehicleType
Available vehicle types.
Definition vehicle_type.h:22
VEH_ROAD
@ VEH_ROAD
Road vehicle type.
Definition vehicle_type.h:26
VEH_AIRCRAFT
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition vehicle_type.h:28
VEH_SHIP
@ VEH_SHIP
Ship vehicle type.
Definition vehicle_type.h:27
VEH_TRAIN
@ VEH_TRAIN
Train vehicle type.
Definition vehicle_type.h:25
vehiclelist.h
Functions and type for generating vehicle lists.
VL_STATION_LIST
@ VL_STATION_LIST
Index is the station.
Definition vehiclelist.h:25
ScrollMainWindowToTile
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition viewport.cpp:2592
SetViewportStationRect
void SetViewportStationRect(const Station *st, bool sel)
Select or deselect station for rectangle area highlight.
Definition viewport.cpp:3736
SetViewportCatchmentStation
void SetViewportCatchmentStation(const Station *st, bool sel)
Select or deselect station for coverage area highlight.
Definition viewport.cpp:3713
SetViewportWaypointRect
void SetViewportWaypointRect(const Waypoint *wp, bool sel)
Select or deselect waypoint for rectangle area highlight.
Definition viewport.cpp:3782
_viewport_highlight_station
const Station * _viewport_highlight_station
Currently selected station for coverage area highlight.
Definition viewport.cpp:1011
viewport_func.h
Functions related to (drawing on) viewports.
waypoint_base.h
Base of waypoints.
WPF_ROAD
@ WPF_ROAD
This is a road waypoint.
Definition waypoint_base.h:19
ScaleGUITrad
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:49
WWT_PUSHTXTBTN
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition widget_type.h:105
WWT_PUSHIMGBTN
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
Definition widget_type.h:106
NWID_HORIZONTAL
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
WWT_TEXTBTN
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
WWT_PANEL
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
WWT_STICKYBOX
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:57
WWT_SHADEBOX
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:55
WWT_CAPTION
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:52
NWID_VSCROLLBAR
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
NWID_VERTICAL
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
WWT_CLOSEBOX
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:60
WWT_RESIZEBOX
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:59
WWT_DEFSIZEBOX
@ 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
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
NWID_SELECTION
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
SZSP_NONE
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
Definition widget_type.h:509
EqualSize
@ EqualSize
Containers should keep all their (resizing) children equally large.
Definition widget_type.h:544
CloseWindowById
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:1195
FindWindowByClass
Window * FindWindowByClass(WindowClass cls)
Find any window by its class.
Definition window.cpp:1168
FindWindowById
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1153
window_func.h
Window functions not directly related to making/drawing windows.
WindowDefaultFlag::Construction
@ Construction
This window is used for construction; close it whenever changing company.
SBS_DOWN
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:219
SBS_UP
@ SBS_UP
Sort descending.
Definition window_gui.h:220
WDP_AUTO
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
WidgetID
int WidgetID
Widget ID.
Definition window_type.h:20
WC_WAYPOINT_VIEW
@ WC_WAYPOINT_VIEW
Waypoint view; Window numbers:
Definition window_type.h:362
WC_STATION_LIST
@ WC_STATION_LIST
Station list; Window numbers:
Definition window_type.h:307
WC_ROADVEH_LIST
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
Definition window_type.h:319
WC_NONE
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
WC_SELECT_STATION
@ WC_SELECT_STATION
Select station (when joining stations); Window numbers:
Definition window_type.h:247
WC_SHIPS_LIST
@ WC_SHIPS_LIST
Ships list; Window numbers:
Definition window_type.h:325
WC_STATION_VIEW
@ WC_STATION_VIEW
Station view; Window numbers:
Definition window_type.h:350
WC_TRAINS_LIST
@ WC_TRAINS_LIST
Trains list; Window numbers:
Definition window_type.h:313
WC_DROPDOWN_MENU
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
Definition window_type.h:161
WC_QUERY_STRING
@ WC_QUERY_STRING
Query string window; Window numbers:
Definition window_type.h:128
WC_AIRCRAFT_LIST
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Definition window_type.h:331
zoom_func.h
Functions related to zooming.
ScaleSpriteTrad
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition zoom_func.h:107