OpenTTD
station_gui.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "stdafx.h"
13 #include "debug.h"
14 #include "gui.h"
15 #include "textbuf_gui.h"
16 #include "company_func.h"
17 #include "command_func.h"
18 #include "vehicle_gui.h"
19 #include "cargotype.h"
20 #include "station_gui.h"
21 #include "strings_func.h"
22 #include "string_func.h"
23 #include "window_func.h"
24 #include "viewport_func.h"
25 #include "widgets/dropdown_func.h"
26 #include "station_base.h"
27 #include "waypoint_base.h"
28 #include "tilehighlight_func.h"
29 #include "company_base.h"
30 #include "sortlist_type.h"
31 #include "core/geometry_func.hpp"
32 #include "vehiclelist.h"
33 #include "town.h"
34 #include "linkgraph/linkgraph.h"
35 #include "zoom_func.h"
36 
37 #include "widgets/station_widget.h"
38 
39 #include "table/strings.h"
40 
41 #include <set>
42 #include <vector>
43 
44 #include "safeguards.h"
45 
56 int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies)
57 {
58  TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
59  CargoTypes cargo_mask = 0;
60  if (_thd.drawstyle == HT_RECT && tile < MapSize()) {
61  CargoArray cargoes;
62  if (supplies) {
63  cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
64  } else {
65  cargoes = GetAcceptanceAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
66  }
67 
68  /* Convert cargo counts to a set of cargo bits, and draw the result. */
69  for (CargoID i = 0; i < NUM_CARGO; i++) {
70  switch (sct) {
71  case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break;
72  case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break;
73  case SCT_ALL: break;
74  default: NOT_REACHED();
75  }
76  if (cargoes[i] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, i);
77  }
78  }
79  SetDParam(0, cargo_mask);
80  return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO);
81 }
82 
88 {
89  /* With distant join we don't know which station will be selected, so don't show any */
90  if (_ctrl_pressed) {
91  SetViewportCatchmentStation(nullptr, true);
92  return;
93  }
94 
95  /* Tile area for TileHighlightData */
96  TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1);
97 
98  /* Extended area by one tile */
99  uint x = TileX(location.tile);
100  uint y = TileY(location.tile);
101 
102  int max_c = 1;
103  TileArea ta(TileXY(max<int>(0, x - max_c), max<int>(0, y - max_c)), TileXY(min<int>(MapMaxX(), x + location.w + max_c), min<int>(MapMaxY(), y + location.h + max_c)));
104 
105  Station *adjacent = nullptr;
106 
107  /* Direct loop instead of FindStationsAroundTiles as we are not interested in catchment area */
108  TILE_AREA_LOOP(tile, ta) {
109  if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) {
110  Station *st = Station::GetByTile(tile);
111  if (st == nullptr) continue;
112  if (adjacent != nullptr && st != adjacent) {
113  /* Multiple nearby, distant join is required. */
114  adjacent = nullptr;
115  break;
116  }
117  adjacent = st;
118  }
119  }
120  SetViewportCatchmentStation(adjacent, true);
121 }
122 
129 {
130  /* Test if ctrl state changed */
131  static bool _last_ctrl_pressed;
132  if (_ctrl_pressed != _last_ctrl_pressed) {
133  _thd.dirty = 0xff;
134  _last_ctrl_pressed = _ctrl_pressed;
135  }
136 
137  if (_thd.dirty & 1) {
138  _thd.dirty &= ~1;
139  w->SetDirty();
140 
143  }
144  }
145 }
146 
162 static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating)
163 {
164  static const uint units_full = 576;
165  static const uint rating_full = 224;
166 
167  const CargoSpec *cs = CargoSpec::Get(type);
168  if (!cs->IsValid()) return;
169 
170  int colour = cs->rating_colour;
171  TextColour tc = GetContrastColour(colour);
172  uint w = (minu(amount, units_full) + 5) / 36;
173 
174  int height = GetCharacterHeight(FS_SMALL);
175 
176  /* Draw total cargo (limited) on station (fits into 16 pixels) */
177  if (w != 0) GfxFillRect(left, y, left + w - 1, y + height, colour);
178 
179  /* Draw a one pixel-wide bar of additional cargo meter, useful
180  * for stations with only a small amount (<=30) */
181  if (w == 0) {
182  uint rest = amount / 5;
183  if (rest != 0) {
184  w += left;
185  GfxFillRect(w, y + height - rest, w, y + height, colour);
186  }
187  }
188 
189  DrawString(left + 1, right, y, cs->abbrev, tc);
190 
191  /* Draw green/red ratings bar (fits into 14 pixels) */
192  y += height + 2;
193  GfxFillRect(left + 1, y, left + 14, y, PC_RED);
194  rating = minu(rating, rating_full) / 16;
195  if (rating != 0) GfxFillRect(left + 1, y, left + rating, y, PC_GREEN);
196 }
197 
199 
204 {
205 protected:
206  /* Runtime saved values */
207  static Listing last_sorting;
208  static byte facilities; // types of stations of interest
209  static bool include_empty; // whether we should include stations without waiting cargo
210  static const CargoTypes cargo_filter_max;
211  static CargoTypes cargo_filter; // bitmap of cargo types to include
212  static const Station *last_station;
213 
214  /* Constants for sorting stations */
215  static const StringID sorter_names[];
216  static GUIStationList::SortFunction * const sorter_funcs[];
217 
218  GUIStationList stations;
219  Scrollbar *vscroll;
220 
227  {
228  if (!this->stations.NeedRebuild()) return;
229 
230  DEBUG(misc, 3, "Building station list for company %d", owner);
231 
232  this->stations.clear();
233 
234  const Station *st;
235  FOR_ALL_STATIONS(st) {
236  if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
237  if (this->facilities & st->facilities) { // only stations with selected facilities
238  int num_waiting_cargo = 0;
239  for (CargoID j = 0; j < NUM_CARGO; j++) {
240  if (st->goods[j].HasRating()) {
241  num_waiting_cargo++; // count number of waiting cargo
242  if (HasBit(this->cargo_filter, j)) {
243  this->stations.push_back(st);
244  break;
245  }
246  }
247  }
248  /* stations without waiting cargo */
249  if (num_waiting_cargo == 0 && this->include_empty) {
250  this->stations.push_back(st);
251  }
252  }
253  }
254  }
255 
256  this->stations.shrink_to_fit();
257  this->stations.RebuildDone();
258 
259  this->vscroll->SetCount((uint)this->stations.size()); // Update the scrollbar
260  }
261 
263  static bool StationNameSorter(const Station * const &a, const Station * const &b)
264  {
265  static char buf_cache[64];
266  char buf[64];
267 
268  SetDParam(0, a->index);
269  GetString(buf, STR_STATION_NAME, lastof(buf));
270 
271  if (b != last_station) {
272  last_station = b;
273  SetDParam(0, b->index);
274  GetString(buf_cache, STR_STATION_NAME, lastof(buf_cache));
275  }
276 
277  int r = strnatcmp(buf, buf_cache); // Sort by name (natural sorting).
278  if (r == 0) return a->index < b->index;
279  return r < 0;
280  }
281 
283  static bool StationTypeSorter(const Station * const &a, const Station * const &b)
284  {
285  return a->facilities < b->facilities;
286  }
287 
289  static bool StationWaitingTotalSorter(const Station * const &a, const Station * const &b)
290  {
291  int diff = 0;
292 
293  CargoID j;
294  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
295  diff += a->goods[j].cargo.TotalCount() - b->goods[j].cargo.TotalCount();
296  }
297 
298  return diff < 0;
299  }
300 
302  static bool StationWaitingAvailableSorter(const Station * const &a, const Station * const &b)
303  {
304  int diff = 0;
305 
306  CargoID j;
307  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
308  diff += a->goods[j].cargo.AvailableCount() - b->goods[j].cargo.AvailableCount();
309  }
310 
311  return diff < 0;
312  }
313 
315  static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b)
316  {
317  byte maxr1 = 0;
318  byte maxr2 = 0;
319 
320  CargoID j;
321  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
322  if (a->goods[j].HasRating()) maxr1 = max(maxr1, a->goods[j].rating);
323  if (b->goods[j].HasRating()) maxr2 = max(maxr2, b->goods[j].rating);
324  }
325 
326  return maxr1 < maxr2;
327  }
328 
330  static bool StationRatingMinSorter(const Station * const &a, const Station * const &b)
331  {
332  byte minr1 = 255;
333  byte minr2 = 255;
334 
335  for (CargoID j = 0; j < NUM_CARGO; j++) {
336  if (!HasBit(cargo_filter, j)) continue;
337  if (a->goods[j].HasRating()) minr1 = min(minr1, a->goods[j].rating);
338  if (b->goods[j].HasRating()) minr2 = min(minr2, b->goods[j].rating);
339  }
340 
341  return minr1 > minr2;
342  }
343 
346  {
347  if (!this->stations.Sort()) return;
348 
349  /* Reset name sorter sort cache */
350  this->last_station = nullptr;
351 
352  /* Set the modified widget dirty */
354  }
355 
356 public:
358  {
359  this->stations.SetListing(this->last_sorting);
360  this->stations.SetSortFuncs(this->sorter_funcs);
361  this->stations.ForceRebuild();
362  this->stations.NeedResort();
363  this->SortStationsList();
364 
365  this->CreateNestedTree();
366  this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR);
367  this->FinishInitNested(window_number);
368  this->owner = (Owner)this->window_number;
369 
370  const CargoSpec *cs;
372  if (!HasBit(this->cargo_filter, cs->Index())) continue;
373  this->LowerWidget(WID_STL_CARGOSTART + index);
374  }
375 
376  if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask;
377 
378  for (uint i = 0; i < 5; i++) {
379  if (HasBit(this->facilities, i)) this->LowerWidget(i + WID_STL_TRAIN);
380  }
381  this->SetWidgetLoweredState(WID_STL_NOCARGOWAITING, this->include_empty);
382 
383  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
384  }
385 
387  {
388  this->last_sorting = this->stations.GetListing();
389  }
390 
391  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
392  {
393  switch (widget) {
394  case WID_STL_SORTBY: {
395  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
396  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
397  d.height += padding.height;
398  *size = maxdim(*size, d);
399  break;
400  }
401 
402  case WID_STL_SORTDROPBTN: {
403  Dimension d = {0, 0};
404  for (int i = 0; this->sorter_names[i] != INVALID_STRING_ID; i++) {
405  d = maxdim(d, GetStringBoundingBox(this->sorter_names[i]));
406  }
407  d.width += padding.width;
408  d.height += padding.height;
409  *size = maxdim(*size, d);
410  break;
411  }
412 
413  case WID_STL_LIST:
414  resize->height = FONT_HEIGHT_NORMAL;
415  size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM;
416  break;
417 
418  case WID_STL_TRAIN:
419  case WID_STL_TRUCK:
420  case WID_STL_BUS:
421  case WID_STL_AIRPLANE:
422  case WID_STL_SHIP:
423  size->height = max<uint>(FONT_HEIGHT_SMALL, 10) + padding.height;
424  break;
425 
426  case WID_STL_CARGOALL:
427  case WID_STL_FACILALL:
428  case WID_STL_NOCARGOWAITING: {
429  Dimension d = GetStringBoundingBox(widget == WID_STL_NOCARGOWAITING ? STR_ABBREV_NONE : STR_ABBREV_ALL);
430  d.width += padding.width + 2;
431  d.height += padding.height;
432  *size = maxdim(*size, d);
433  break;
434  }
435 
436  default:
437  if (widget >= WID_STL_CARGOSTART) {
439  d.width += padding.width + 2;
440  d.height += padding.height;
441  *size = maxdim(*size, d);
442  }
443  break;
444  }
445  }
446 
447  void OnPaint() override
448  {
449  this->BuildStationsList((Owner)this->window_number);
450  this->SortStationsList();
451 
452  this->DrawWidgets();
453  }
454 
455  void DrawWidget(const Rect &r, int widget) const override
456  {
457  switch (widget) {
458  case WID_STL_SORTBY:
459  /* draw arrow pointing up/down for ascending/descending sorting */
461  break;
462 
463  case WID_STL_LIST: {
464  bool rtl = _current_text_dir == TD_RTL;
465  int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->stations.size());
466  int y = r.top + WD_FRAMERECT_TOP;
467  for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner
468  const Station *st = this->stations[i];
469  assert(st->xy != INVALID_TILE);
470 
471  /* Do not do the complex check HasStationInUse here, it may be even false
472  * when the order had been removed and the station list hasn't been removed yet */
473  assert(st->owner == owner || st->owner == OWNER_NONE);
474 
475  SetDParam(0, st->index);
476  SetDParam(1, st->facilities);
477  int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION);
478  x += rtl ? -5 : 5;
479 
480  /* show cargo waiting and station ratings */
481  for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) {
482  CargoID cid = _sorted_cargo_specs[j]->Index();
483  if (st->goods[cid].cargo.TotalCount() > 0) {
484  /* For RTL we work in exactly the opposite direction. So
485  * decrement the space needed first, then draw to the left
486  * instead of drawing to the left and then incrementing
487  * the space. */
488  if (rtl) {
489  x -= 20;
490  if (x < r.left + WD_FRAMERECT_LEFT) break;
491  }
492  StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating);
493  if (!rtl) {
494  x += 20;
495  if (x > r.right - WD_FRAMERECT_RIGHT) break;
496  }
497  }
498  }
499  y += FONT_HEIGHT_NORMAL;
500  }
501 
502  if (this->vscroll->GetCount() == 0) { // company has no stations
503  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_NONE);
504  return;
505  }
506  break;
507  }
508 
509  case WID_STL_NOCARGOWAITING: {
510  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
511  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER);
512  break;
513  }
514 
515  case WID_STL_CARGOALL: {
516  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
517  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
518  break;
519  }
520 
521  case WID_STL_FACILALL: {
522  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
523  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
524  break;
525  }
526 
527  default:
528  if (widget >= WID_STL_CARGOSTART) {
529  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
530  int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1;
531  GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour);
532  TextColour tc = GetContrastColour(cs->rating_colour);
533  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER);
534  }
535  break;
536  }
537  }
538 
539  void SetStringParameters(int widget) const override
540  {
541  if (widget == WID_STL_CAPTION) {
542  SetDParam(0, this->window_number);
543  SetDParam(1, this->vscroll->GetCount());
544  }
545  }
546 
547  void OnClick(Point pt, int widget, int click_count) override
548  {
549  switch (widget) {
550  case WID_STL_LIST: {
551  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL);
552  if (id_v >= this->stations.size()) return; // click out of list bound
553 
554  const Station *st = this->stations[id_v];
555  /* do not check HasStationInUse - it is slow and may be invalid */
556  assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE);
557 
558  if (_ctrl_pressed) {
560  } else {
562  }
563  break;
564  }
565 
566  case WID_STL_TRAIN:
567  case WID_STL_TRUCK:
568  case WID_STL_BUS:
569  case WID_STL_AIRPLANE:
570  case WID_STL_SHIP:
571  if (_ctrl_pressed) {
572  ToggleBit(this->facilities, widget - WID_STL_TRAIN);
573  this->ToggleWidgetLoweredState(widget);
574  } else {
575  uint i;
576  FOR_EACH_SET_BIT(i, this->facilities) {
577  this->RaiseWidget(i + WID_STL_TRAIN);
578  }
579  this->facilities = 1 << (widget - WID_STL_TRAIN);
580  this->LowerWidget(widget);
581  }
582  this->stations.ForceRebuild();
583  this->SetDirty();
584  break;
585 
586  case WID_STL_FACILALL:
587  for (uint i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) {
588  this->LowerWidget(i);
589  }
590 
592  this->stations.ForceRebuild();
593  this->SetDirty();
594  break;
595 
596  case WID_STL_CARGOALL: {
597  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
598  this->LowerWidget(WID_STL_CARGOSTART + i);
599  }
601 
602  this->cargo_filter = _cargo_mask;
603  this->include_empty = true;
604  this->stations.ForceRebuild();
605  this->SetDirty();
606  break;
607  }
608 
609  case WID_STL_SORTBY: // flip sorting method asc/desc
610  this->stations.ToggleSortOrder();
611  this->SetDirty();
612  break;
613 
614  case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu
615  ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0);
616  break;
617 
619  if (_ctrl_pressed) {
620  this->include_empty = !this->include_empty;
622  } else {
623  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
624  this->RaiseWidget(WID_STL_CARGOSTART + i);
625  }
626 
627  this->cargo_filter = 0;
628  this->include_empty = true;
629 
631  }
632  this->stations.ForceRebuild();
633  this->SetDirty();
634  break;
635 
636  default:
637  if (widget >= WID_STL_CARGOSTART) { // change cargo_filter
638  /* Determine the selected cargo type */
639  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
640 
641  if (_ctrl_pressed) {
642  ToggleBit(this->cargo_filter, cs->Index());
643  this->ToggleWidgetLoweredState(widget);
644  } else {
645  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
646  this->RaiseWidget(WID_STL_CARGOSTART + i);
647  }
649 
650  this->cargo_filter = 0;
651  this->include_empty = false;
652 
653  SetBit(this->cargo_filter, cs->Index());
654  this->LowerWidget(widget);
655  }
656  this->stations.ForceRebuild();
657  this->SetDirty();
658  }
659  break;
660  }
661  }
662 
663  void OnDropdownSelect(int widget, int index) override
664  {
665  if (this->stations.SortType() != index) {
666  this->stations.SetSortType(index);
667 
668  /* Display the current sort variant */
669  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
670 
671  this->SetDirty();
672  }
673  }
674 
675  void OnGameTick() override
676  {
677  if (this->stations.NeedResort()) {
678  DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number);
679  this->SetDirty();
680  }
681  }
682 
683  void OnResize() override
684  {
686  }
687 
693  void OnInvalidateData(int data = 0, bool gui_scope = true) override
694  {
695  if (data == 0) {
696  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
697  this->stations.ForceRebuild();
698  } else {
699  this->stations.ForceResort();
700  }
701  }
702 };
703 
704 Listing CompanyStationsWindow::last_sorting = {false, 0};
705 byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
706 bool CompanyStationsWindow::include_empty = true;
707 const CargoTypes CompanyStationsWindow::cargo_filter_max = ALL_CARGOTYPES;
708 CargoTypes CompanyStationsWindow::cargo_filter = ALL_CARGOTYPES;
709 const Station *CompanyStationsWindow::last_station = nullptr;
710 
711 /* Available station sorting functions */
712 GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
719 };
720 
721 /* Names of the sorting functions */
722 const StringID CompanyStationsWindow::sorter_names[] = {
723  STR_SORT_BY_NAME,
724  STR_SORT_BY_FACILITY,
725  STR_SORT_BY_WAITING_TOTAL,
726  STR_SORT_BY_WAITING_AVAILABLE,
727  STR_SORT_BY_RATING_MAX,
728  STR_SORT_BY_RATING_MIN,
730 };
731 
737 static NWidgetBase *CargoWidgets(int *biggest_index)
738 {
739  NWidgetHorizontal *container = new NWidgetHorizontal();
740 
741  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
742  NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
743  panel->SetMinimalSize(14, 11);
744  panel->SetResize(0, 0);
745  panel->SetFill(0, 1);
746  panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
747  container->Add(panel);
748  }
750  return container;
751 }
752 
753 static const NWidgetPart _nested_company_stations_widgets[] = {
755  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
756  NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
757  NWidget(WWT_SHADEBOX, COLOUR_GREY),
758  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
759  NWidget(WWT_STICKYBOX, COLOUR_GREY),
760  EndContainer(),
762  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 11), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
763  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 11), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
764  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 11), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
765  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 11), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
766  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 11), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
767  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1),
768  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(),
770  NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(),
771  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1),
772  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
773  EndContainer(),
775  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
776  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten.
777  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
778  EndContainer(),
780  NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_LIST), SetMinimalSize(346, 125), SetResize(1, 10), SetDataTip(0x0, STR_STATION_LIST_TOOLTIP), SetScrollbar(WID_STL_SCROLLBAR), EndContainer(),
783  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
784  EndContainer(),
785  EndContainer(),
786 };
787 
788 static WindowDesc _company_stations_desc(
789  WDP_AUTO, "list_stations", 358, 162,
791  0,
792  _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets)
793 );
794 
801 {
802  if (!Company::IsValidID(company)) return;
803 
804  AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
805 }
806 
807 static const NWidgetPart _nested_station_view_widgets[] = {
809  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
810  NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
811  NWidget(WWT_SHADEBOX, COLOUR_GREY),
812  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
813  NWidget(WWT_STICKYBOX, COLOUR_GREY),
814  EndContainer(),
816  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
817  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
818  EndContainer(),
820  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0),
821  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
822  EndContainer(),
826  EndContainer(),
830  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
831  SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
832  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1),
833  SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
834  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
835  SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
836  EndContainer(),
837  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
838  SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
839  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CATCHMENT), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
840  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
841  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
842  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
843  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
844  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
845  EndContainer(),
846 };
847 
857 static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
858 {
859  int width = ScaleGUITrad(10);
860  uint num = min((waiting + (width / 2)) / width, (right - left) / width); // maximum is width / 10 icons so it won't overflow
861  if (num == 0) return;
862 
863  SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon();
864 
865  int x = _current_text_dir == TD_RTL ? left : right - num * width;
866  do {
867  DrawSprite(sprite, PAL_NONE, x, y);
868  x += width;
869  } while (--num);
870 }
871 
872 enum SortOrder {
873  SO_DESCENDING,
874  SO_ASCENDING
875 };
876 
877 class CargoDataEntry;
878 
885 };
886 
887 class CargoSorter {
888 public:
889  CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {}
890  CargoSortType GetSortType() {return this->type;}
891  bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
892 
893 private:
894  CargoSortType type;
895  SortOrder order;
896 
897  template<class Tid>
898  bool SortId(Tid st1, Tid st2) const;
899  bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
900  bool SortStation (StationID st1, StationID st2) const;
901 };
902 
903 typedef std::set<CargoDataEntry *, CargoSorter> CargoDataSet;
904 
911 public:
912  CargoDataEntry();
913  ~CargoDataEntry();
914 
920  CargoDataEntry *InsertOrRetrieve(StationID station)
921  {
922  return this->InsertOrRetrieve<StationID>(station);
923  }
924 
931  {
932  return this->InsertOrRetrieve<CargoID>(cargo);
933  }
934 
935  void Update(uint count);
936 
941  void Remove(StationID station)
942  {
943  CargoDataEntry t(station);
944  this->Remove(&t);
945  }
946 
951  void Remove(CargoID cargo)
952  {
953  CargoDataEntry t(cargo);
954  this->Remove(&t);
955  }
956 
962  CargoDataEntry *Retrieve(StationID station) const
963  {
964  CargoDataEntry t(station);
965  return this->Retrieve(this->children->find(&t));
966  }
967 
974  {
975  CargoDataEntry t(cargo);
976  return this->Retrieve(this->children->find(&t));
977  }
978 
979  void Resort(CargoSortType type, SortOrder order);
980 
984  StationID GetStation() const { return this->station; }
985 
989  CargoID GetCargo() const { return this->cargo; }
990 
994  uint GetCount() const { return this->count; }
995 
999  CargoDataEntry *GetParent() const { return this->parent; }
1000 
1004  uint GetNumChildren() const { return this->num_children; }
1005 
1009  CargoDataSet::iterator Begin() const { return this->children->begin(); }
1010 
1014  CargoDataSet::iterator End() const { return this->children->end(); }
1015 
1019  bool HasTransfers() const { return this->transfers; }
1020 
1024  void SetTransfers(bool value) { this->transfers = value; }
1025 
1026  void Clear();
1027 private:
1028 
1029  CargoDataEntry(StationID st, uint c, CargoDataEntry *p);
1030  CargoDataEntry(CargoID car, uint c, CargoDataEntry *p);
1031  CargoDataEntry(StationID st);
1032  CargoDataEntry(CargoID car);
1033 
1034  CargoDataEntry *Retrieve(CargoDataSet::iterator i) const;
1035 
1036  template<class Tid>
1037  CargoDataEntry *InsertOrRetrieve(Tid s);
1038 
1039  void Remove(CargoDataEntry *comp);
1040  void IncrementSize();
1041 
1043  const union {
1044  StationID station;
1045  struct {
1047  bool transfers;
1048  };
1049  };
1051  uint count;
1052  CargoDataSet *children;
1053 };
1054 
1055 CargoDataEntry::CargoDataEntry() :
1056  parent(nullptr),
1057  station(INVALID_STATION),
1058  num_children(0),
1059  count(0),
1060  children(new CargoDataSet(CargoSorter(ST_CARGO_ID)))
1061 {}
1062 
1063 CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) :
1064  parent(parent),
1065  cargo(cargo),
1066  num_children(0),
1067  count(count),
1068  children(new CargoDataSet)
1069 {}
1070 
1071 CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) :
1072  parent(parent),
1073  station(station),
1074  num_children(0),
1075  count(count),
1076  children(new CargoDataSet)
1077 {}
1078 
1079 CargoDataEntry::CargoDataEntry(StationID station) :
1080  parent(nullptr),
1081  station(station),
1082  num_children(0),
1083  count(0),
1084  children(nullptr)
1085 {}
1086 
1087 CargoDataEntry::CargoDataEntry(CargoID cargo) :
1088  parent(nullptr),
1089  cargo(cargo),
1090  num_children(0),
1091  count(0),
1092  children(nullptr)
1093 {}
1094 
1095 CargoDataEntry::~CargoDataEntry()
1096 {
1097  this->Clear();
1098  delete this->children;
1099 }
1100 
1105 {
1106  if (this->children != nullptr) {
1107  for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) {
1108  assert(*i != this);
1109  delete *i;
1110  }
1111  this->children->clear();
1112  }
1113  if (this->parent != nullptr) this->parent->count -= this->count;
1114  this->count = 0;
1115  this->num_children = 0;
1116 }
1117 
1125 {
1126  CargoDataSet::iterator i = this->children->find(child);
1127  if (i != this->children->end()) {
1128  delete *i;
1129  this->children->erase(i);
1130  }
1131 }
1132 
1139 template<class Tid>
1141 {
1142  CargoDataEntry tmp(child_id);
1143  CargoDataSet::iterator i = this->children->find(&tmp);
1144  if (i == this->children->end()) {
1145  IncrementSize();
1146  return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first);
1147  } else {
1148  CargoDataEntry *ret = *i;
1149  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1150  return ret;
1151  }
1152 }
1153 
1160 {
1161  this->count += count;
1162  if (this->parent != nullptr) this->parent->Update(count);
1163 }
1164 
1169 {
1170  ++this->num_children;
1171  if (this->parent != nullptr) this->parent->IncrementSize();
1172 }
1173 
1174 void CargoDataEntry::Resort(CargoSortType type, SortOrder order)
1175 {
1176  CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order));
1177  delete this->children;
1178  this->children = new_subs;
1179 }
1180 
1181 CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const
1182 {
1183  if (i == this->children->end()) {
1184  return nullptr;
1185  } else {
1186  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1187  return *i;
1188  }
1189 }
1190 
1191 bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1192 {
1193  switch (this->type) {
1194  case ST_STATION_ID:
1195  return this->SortId<StationID>(cd1->GetStation(), cd2->GetStation());
1196  case ST_CARGO_ID:
1197  return this->SortId<CargoID>(cd1->GetCargo(), cd2->GetCargo());
1198  case ST_COUNT:
1199  return this->SortCount(cd1, cd2);
1200  case ST_STATION_STRING:
1201  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1202  default:
1203  NOT_REACHED();
1204  }
1205 }
1206 
1207 template<class Tid>
1208 bool CargoSorter::SortId(Tid st1, Tid st2) const
1209 {
1210  return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1;
1211 }
1212 
1213 bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1214 {
1215  uint c1 = cd1->GetCount();
1216  uint c2 = cd2->GetCount();
1217  if (c1 == c2) {
1218  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1219  } else if (this->order == SO_ASCENDING) {
1220  return c1 < c2;
1221  } else {
1222  return c2 < c1;
1223  }
1224 }
1225 
1226 bool CargoSorter::SortStation(StationID st1, StationID st2) const
1227 {
1228  static char buf1[MAX_LENGTH_STATION_NAME_CHARS];
1229  static char buf2[MAX_LENGTH_STATION_NAME_CHARS];
1230 
1231  if (!Station::IsValidID(st1)) {
1232  return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2);
1233  } else if (!Station::IsValidID(st2)) {
1234  return order == SO_DESCENDING;
1235  }
1236 
1237  SetDParam(0, st1);
1238  GetString(buf1, STR_STATION_NAME, lastof(buf1));
1239  SetDParam(0, st2);
1240  GetString(buf2, STR_STATION_NAME, lastof(buf2));
1241 
1242  int res = strnatcmp(buf1, buf2); // Sort by name (natural sorting).
1243  if (res == 0) {
1244  return this->SortId(st1, st2);
1245  } else {
1246  return (this->order == SO_ASCENDING) ? res < 0 : res > 0;
1247  }
1248 }
1249 
1253 struct StationViewWindow : public Window {
1257  struct RowDisplay {
1258  RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {}
1259  RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {}
1260 
1265  union {
1269  StationID next_station;
1270 
1275  };
1276  };
1277 
1278  typedef std::vector<RowDisplay> CargoDataVector;
1279 
1280  static const int NUM_COLUMNS = 4;
1281 
1286  INV_FLOWS = 0x100,
1287  INV_CARGO = 0x200
1288  };
1289 
1293  enum Grouping {
1298  };
1299 
1303  enum Mode {
1305  MODE_PLANNED
1306  };
1307 
1311  Scrollbar *vscroll;
1312 
1315  ALH_RATING = 13,
1316  ALH_ACCEPTS = 3,
1317  };
1318 
1319  static const StringID _sort_names[];
1320  static const StringID _group_names[];
1321 
1328  CargoSortType sortings[NUM_COLUMNS];
1329 
1331  SortOrder sort_orders[NUM_COLUMNS];
1332 
1336  Grouping groupings[NUM_COLUMNS];
1337 
1340  CargoDataVector displayed_rows;
1341 
1342  StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc),
1343  scroll_to_row(INT_MAX), grouping_index(0)
1344  {
1345  this->rating_lines = ALH_RATING;
1346  this->accepts_lines = ALH_ACCEPTS;
1347 
1348  this->CreateNestedTree();
1349  this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
1350  /* Nested widget tree creation is done in two steps to ensure that this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */
1351  this->FinishInitNested(window_number);
1352 
1353  this->groupings[0] = GR_CARGO;
1354  this->sortings[0] = ST_AS_GROUPING;
1355  this->SelectGroupBy(_settings_client.gui.station_gui_group_order);
1356  this->SelectSortBy(_settings_client.gui.station_gui_sort_by);
1357  this->sort_orders[0] = SO_ASCENDING;
1358  this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order);
1359  this->owner = Station::Get(window_number)->owner;
1360  }
1361 
1363  {
1364  DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->window_number).Pack(), false);
1365  DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).Pack(), false);
1366  DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).Pack(), false);
1367  DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).Pack(), false);
1368 
1369  SetViewportCatchmentStation(Station::Get(this->window_number), false);
1370  }
1371 
1382  void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count)
1383  {
1384  if (count == 0) return;
1385  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1386  const CargoDataEntry *expand = &this->expanded_rows;
1387  for (int i = 0; i < NUM_COLUMNS && expand != nullptr; ++i) {
1388  switch (groupings[i]) {
1389  case GR_CARGO:
1390  assert(i == 0);
1391  data = data->InsertOrRetrieve(cargo);
1392  data->SetTransfers(source != this->window_number);
1393  expand = expand->Retrieve(cargo);
1394  break;
1395  case GR_SOURCE:
1396  if (auto_distributed || source != this->window_number) {
1397  data = data->InsertOrRetrieve(source);
1398  expand = expand->Retrieve(source);
1399  }
1400  break;
1401  case GR_NEXT:
1402  if (auto_distributed) {
1403  data = data->InsertOrRetrieve(next);
1404  expand = expand->Retrieve(next);
1405  }
1406  break;
1407  case GR_DESTINATION:
1408  if (auto_distributed) {
1409  data = data->InsertOrRetrieve(dest);
1410  expand = expand->Retrieve(dest);
1411  }
1412  break;
1413  }
1414  }
1415  data->Update(count);
1416  }
1417 
1418  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1419  {
1420  switch (widget) {
1421  case WID_SV_WAITING:
1422  resize->height = FONT_HEIGHT_NORMAL;
1423  size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM;
1424  this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
1425  break;
1426 
1428  size->height = WD_FRAMERECT_TOP + ((this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) ? this->accepts_lines : this->rating_lines) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
1429  break;
1430 
1431  case WID_SV_CLOSE_AIRPORT:
1432  if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) {
1433  /* Hide 'Close Airport' button if no airport present. */
1434  size->width = 0;
1435  resize->width = 0;
1436  fill->width = 0;
1437  }
1438  break;
1439  }
1440  }
1441 
1442  void OnPaint() override
1443  {
1444  const Station *st = Station::Get(this->window_number);
1446  BuildCargoList(&cargo, st);
1447 
1448  this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar
1449 
1450  /* disable some buttons */
1451  this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company);
1452  this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN));
1453  this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
1454  this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK));
1455  this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT));
1456  this->SetWidgetDisabledState(WID_SV_CLOSE_AIRPORT, !(st->facilities & FACIL_AIRPORT) || st->owner != _local_company || st->owner == OWNER_NONE); // Also consider SE, where _local_company == OWNER_NONE
1457  this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0);
1458 
1459  extern const Station *_viewport_highlight_station;
1460  this->SetWidgetDisabledState(WID_SV_CATCHMENT, st->facilities == FACIL_NONE);
1461  this->SetWidgetLoweredState(WID_SV_CATCHMENT, _viewport_highlight_station == st);
1462 
1463  this->DrawWidgets();
1464 
1465  if (!this->IsShaded()) {
1466  /* Draw 'accepted cargo' or 'cargo ratings'. */
1467  const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SV_ACCEPT_RATING_LIST);
1468  const Rect r = {(int)wid->pos_x, (int)wid->pos_y, (int)(wid->pos_x + wid->current_x - 1), (int)(wid->pos_y + wid->current_y - 1)};
1469  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1470  int lines = this->DrawAcceptedCargo(r);
1471  if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window.
1472  this->accepts_lines = lines;
1473  this->ReInit();
1474  return;
1475  }
1476  } else {
1477  int lines = this->DrawCargoRatings(r);
1478  if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window.
1479  this->rating_lines = lines;
1480  this->ReInit();
1481  return;
1482  }
1483  }
1484 
1485  /* Draw arrow pointing up/down for ascending/descending sorting */
1486  this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN);
1487 
1488  int pos = this->vscroll->GetPosition();
1489 
1490  int maxrows = this->vscroll->GetCapacity();
1491 
1492  displayed_rows.clear();
1493 
1494  /* Draw waiting cargo. */
1495  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SV_WAITING);
1496  Rect waiting_rect = { (int)nwi->pos_x, (int)nwi->pos_y, (int)(nwi->pos_x + nwi->current_x - 1), (int)(nwi->pos_y + nwi->current_y - 1)};
1497  this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0);
1498  scroll_to_row = INT_MAX;
1499  }
1500  }
1501 
1502  void SetStringParameters(int widget) const override
1503  {
1504  const Station *st = Station::Get(this->window_number);
1505  SetDParam(0, st->index);
1506  SetDParam(1, st->facilities);
1507  }
1508 
1515  {
1516  const Station *st = Station::Get(this->window_number);
1517  CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i);
1518  cargo_entry->Clear();
1519 
1520  const FlowStatMap &flows = st->goods[i].flows;
1521  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1522  StationID from = it->first;
1523  CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from);
1524  const FlowStat::SharesMap *shares = it->second.GetShares();
1525  uint32 prev_count = 0;
1526  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1527  StationID via = flow_it->second;
1528  CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via);
1529  if (via == this->window_number) {
1530  via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count);
1531  } else {
1532  EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry);
1533  }
1534  prev_count = flow_it->first;
1535  }
1536  }
1537  }
1538 
1548  void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest)
1549  {
1550  if (Station::IsValidID(next) && Station::IsValidID(source)) {
1551  CargoDataEntry tmp;
1552  const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows;
1553  FlowStatMap::const_iterator map_it = flowmap.find(source);
1554  if (map_it != flowmap.end()) {
1555  const FlowStat::SharesMap *shares = map_it->second.GetShares();
1556  uint32 prev_count = 0;
1557  for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) {
1558  tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
1559  prev_count = i->first;
1560  }
1561  }
1562 
1563  if (tmp.GetCount() == 0) {
1564  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1565  } else {
1566  uint sum_estimated = 0;
1567  while (sum_estimated < count) {
1568  for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) {
1569  CargoDataEntry *child = *i;
1570  uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount());
1571  if (estimate == 0) estimate = 1;
1572 
1573  sum_estimated += estimate;
1574  if (sum_estimated > count) {
1575  estimate -= sum_estimated - count;
1576  sum_estimated = count;
1577  }
1578 
1579  if (estimate > 0) {
1580  if (child->GetStation() == next) {
1581  dest->InsertOrRetrieve(next)->Update(estimate);
1582  } else {
1583  EstimateDestinations(cargo, source, child->GetStation(), estimate, dest);
1584  }
1585  }
1586  }
1587 
1588  }
1589  }
1590  } else {
1591  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1592  }
1593  }
1594 
1602  {
1603  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1604  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1605  StationID from = it->first;
1606  const CargoDataEntry *source_entry = source_dest->Retrieve(from);
1607  const FlowStat::SharesMap *shares = it->second.GetShares();
1608  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1609  const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second);
1610  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1611  CargoDataEntry *dest_entry = *dest_it;
1612  ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount());
1613  }
1614  }
1615  }
1616  }
1617 
1625  {
1626  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1627  for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) {
1628  const CargoPacket *cp = *it;
1629  StationID next = it.GetKey();
1630 
1631  const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation());
1632  if (source_entry == nullptr) {
1633  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1634  continue;
1635  }
1636 
1637  const CargoDataEntry *via_entry = source_entry->Retrieve(next);
1638  if (via_entry == nullptr) {
1639  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1640  continue;
1641  }
1642 
1643  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1644  CargoDataEntry *dest_entry = *dest_it;
1645  uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount());
1646  this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val);
1647  }
1648  }
1649  this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount());
1650  }
1651 
1658  {
1659  for (CargoID i = 0; i < NUM_CARGO; i++) {
1660 
1661  if (this->cached_destinations.Retrieve(i) == nullptr) {
1662  this->RecalcDestinations(i);
1663  }
1664 
1665  if (this->current_mode == MODE_WAITING) {
1666  this->BuildCargoList(i, st->goods[i].cargo, cargo);
1667  } else {
1668  this->BuildFlowList(i, st->goods[i].flows, cargo);
1669  }
1670  }
1671  }
1672 
1678  {
1679  std::list<StationID> stations;
1680  const CargoDataEntry *parent = data->GetParent();
1681  if (parent->GetParent() == nullptr) {
1682  this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo()));
1683  return;
1684  }
1685 
1686  StationID next = data->GetStation();
1687  while (parent->GetParent()->GetParent() != nullptr) {
1688  stations.push_back(parent->GetStation());
1689  parent = parent->GetParent();
1690  }
1691 
1692  CargoID cargo = parent->GetCargo();
1693  CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo);
1694  while (!stations.empty()) {
1695  filter = filter->Retrieve(stations.back());
1696  stations.pop_back();
1697  }
1698 
1699  this->displayed_rows.push_back(RowDisplay(filter, next));
1700  }
1701 
1710  StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any)
1711  {
1712  if (station == this->window_number) {
1713  return here;
1714  } else if (station == INVALID_STATION) {
1715  return any;
1716  } else if (station == NEW_STATION) {
1717  return STR_STATION_VIEW_RESERVED;
1718  } else {
1719  SetDParam(2, station);
1720  return other_station;
1721  }
1722  }
1723 
1731  StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column)
1732  {
1733  CargoDataEntry *parent = cd->GetParent();
1734  for (int i = column - 1; i > 0; --i) {
1735  if (this->groupings[i] == GR_DESTINATION) {
1736  if (parent->GetStation() == station) {
1737  return STR_STATION_VIEW_NONSTOP;
1738  } else {
1739  return STR_STATION_VIEW_VIA;
1740  }
1741  }
1742  parent = parent->GetParent();
1743  }
1744 
1745  if (this->groupings[column + 1] == GR_DESTINATION) {
1746  CargoDataSet::iterator begin = cd->Begin();
1747  CargoDataSet::iterator end = cd->End();
1748  if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) {
1749  return STR_STATION_VIEW_NONSTOP;
1750  } else {
1751  return STR_STATION_VIEW_VIA;
1752  }
1753  }
1754 
1755  return STR_STATION_VIEW_VIA;
1756  }
1757 
1768  int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID)
1769  {
1770  if (this->sortings[column] == ST_AS_GROUPING) {
1771  if (this->groupings[column] != GR_CARGO) {
1772  entry->Resort(ST_STATION_STRING, this->sort_orders[column]);
1773  }
1774  } else {
1775  entry->Resort(ST_COUNT, this->sort_orders[column]);
1776  }
1777  for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) {
1778  CargoDataEntry *cd = *i;
1779 
1780  Grouping grouping = this->groupings[column];
1781  if (grouping == GR_CARGO) cargo = cd->GetCargo();
1782  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1783 
1784  if (pos > -maxrows && pos <= 0) {
1785  StringID str = STR_EMPTY;
1786  int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL;
1787  SetDParam(0, cargo);
1788  SetDParam(1, cd->GetCount());
1789 
1790  if (this->groupings[column] == GR_CARGO) {
1791  str = STR_STATION_VIEW_WAITING_CARGO;
1792  DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y);
1793  } else {
1794  if (!auto_distributed) grouping = GR_SOURCE;
1795  StationID station = cd->GetStation();
1796 
1797  switch (grouping) {
1798  case GR_SOURCE:
1799  str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY);
1800  break;
1801  case GR_NEXT:
1802  str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY);
1803  if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column);
1804  break;
1805  case GR_DESTINATION:
1806  str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY);
1807  break;
1808  default:
1809  NOT_REACHED();
1810  }
1811  if (pos == -this->scroll_to_row && Station::IsValidID(station)) {
1812  ScrollMainWindowToTile(Station::Get(station)->xy);
1813  }
1814  }
1815 
1816  bool rtl = _current_text_dir == TD_RTL;
1817  int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width;
1818  int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width;
1819  int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT;
1820  int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT;
1821 
1822  DrawString(text_left, text_right, y, str);
1823 
1824  if (column < NUM_COLUMNS - 1) {
1825  const char *sym = nullptr;
1826  if (cd->GetNumChildren() > 0) {
1827  sym = "-";
1828  } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) {
1829  sym = "+";
1830  } else {
1831  /* Only draw '+' if there is something to be shown. */
1832  const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo;
1833  if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) {
1834  sym = "+";
1835  }
1836  }
1837  if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW);
1838  }
1839  this->SetDisplayedRow(cd);
1840  }
1841  --pos;
1842  if (auto_distributed || column == 0) {
1843  pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo);
1844  }
1845  }
1846  return pos;
1847  }
1848 
1854  int DrawAcceptedCargo(const Rect &r) const
1855  {
1856  const Station *st = Station::Get(this->window_number);
1857 
1858  CargoTypes cargo_mask = 0;
1859  for (CargoID i = 0; i < NUM_CARGO; i++) {
1860  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i);
1861  }
1862  SetDParam(0, cargo_mask);
1863  int bottom = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INT32_MAX, STR_STATION_VIEW_ACCEPTS_CARGO);
1864  return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1865  }
1866 
1872  int DrawCargoRatings(const Rect &r) const
1873  {
1874  const Station *st = Station::Get(this->window_number);
1875  int y = r.top + WD_FRAMERECT_TOP;
1876 
1877  if (st->town->exclusive_counter > 0) {
1878  SetDParam(0, st->town->exclusivity);
1879  y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, st->town->exclusivity == st->owner ? STR_STATION_VIEW_EXCLUSIVE_RIGHTS_SELF : STR_STATION_VIEW_EXCLUSIVE_RIGHTS_COMPANY);
1880  y += WD_PAR_VSEP_WIDE;
1881  }
1882 
1883  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE);
1884  y += FONT_HEIGHT_NORMAL;
1885 
1886  const CargoSpec *cs;
1888  const GoodsEntry *ge = &st->goods[cs->Index()];
1889  if (!ge->HasRating()) continue;
1890 
1891  const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph);
1892  SetDParam(0, cs->name);
1893  SetDParam(1, lg != nullptr ? lg->Monthly((*lg)[ge->node].Supply()) : 0);
1894  SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5));
1895  SetDParam(3, ToPercent8(ge->rating));
1896  DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING);
1897  y += FONT_HEIGHT_NORMAL;
1898  }
1899  return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1900  }
1901 
1907  template<class Tid>
1908  void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
1909  {
1910  if (filter->Retrieve(next) != nullptr) {
1911  filter->Remove(next);
1912  } else {
1913  filter->InsertOrRetrieve(next);
1914  }
1915  }
1916 
1922  {
1923  if (row < 0 || (uint)row >= this->displayed_rows.size()) return;
1924  if (_ctrl_pressed) {
1925  this->scroll_to_row = row;
1926  } else {
1927  RowDisplay &display = this->displayed_rows[row];
1928  if (display.filter == &this->expanded_rows) {
1929  this->HandleCargoWaitingClick<CargoID>(display.filter, display.next_cargo);
1930  } else {
1931  this->HandleCargoWaitingClick<StationID>(display.filter, display.next_station);
1932  }
1933  }
1934  this->SetWidgetDirty(WID_SV_WAITING);
1935  }
1936 
1937  void OnClick(Point pt, int widget, int click_count) override
1938  {
1939  switch (widget) {
1940  case WID_SV_WAITING:
1941  this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition());
1942  break;
1943 
1944  case WID_SV_CATCHMENT:
1945  SetViewportCatchmentStation(Station::Get(this->window_number), !this->IsWidgetLowered(WID_SV_CATCHMENT));
1946  break;
1947 
1948  case WID_SV_LOCATION:
1949  if (_ctrl_pressed) {
1950  ShowExtraViewPortWindow(Station::Get(this->window_number)->xy);
1951  } else {
1952  ScrollMainWindowToTile(Station::Get(this->window_number)->xy);
1953  }
1954  break;
1955 
1956  case WID_SV_ACCEPTS_RATINGS: {
1957  /* Swap between 'accepts' and 'ratings' view. */
1958  int height_change;
1959  NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS);
1960  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1961  nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view.
1962  height_change = this->rating_lines - this->accepts_lines;
1963  } else {
1964  nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view.
1965  height_change = this->accepts_lines - this->rating_lines;
1966  }
1967  this->ReInit(0, height_change * FONT_HEIGHT_NORMAL);
1968  break;
1969  }
1970 
1971  case WID_SV_RENAME:
1972  SetDParam(0, this->window_number);
1973  ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
1975  break;
1976 
1977  case WID_SV_CLOSE_AIRPORT:
1978  DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT);
1979  break;
1980 
1981  case WID_SV_TRAINS: // Show list of scheduled trains to this station
1982  case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station
1983  case WID_SV_SHIPS: // Show list of scheduled ships to this station
1984  case WID_SV_PLANES: { // Show list of scheduled aircraft to this station
1985  Owner owner = Station::Get(this->window_number)->owner;
1986  ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number);
1987  break;
1988  }
1989 
1990  case WID_SV_SORT_BY: {
1991  /* The initial selection is composed of current mode and
1992  * sorting criteria for columns 1, 2, and 3. Column 0 is always
1993  * sorted by cargo ID. The others can theoretically be sorted
1994  * by different things but there is no UI for that. */
1995  ShowDropDownMenu(this, _sort_names,
1996  this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0),
1997  WID_SV_SORT_BY, 0, 0);
1998  break;
1999  }
2000 
2001  case WID_SV_GROUP_BY: {
2002  ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
2003  break;
2004  }
2005 
2006  case WID_SV_SORT_ORDER: { // flip sorting method asc/desc
2007  this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING);
2008  this->SetTimeout();
2009  this->LowerWidget(WID_SV_SORT_ORDER);
2010  break;
2011  }
2012  }
2013  }
2014 
2019  void SelectSortOrder(SortOrder order)
2020  {
2021  this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order;
2022  _settings_client.gui.station_gui_sort_order = this->sort_orders[1];
2023  this->SetDirty();
2024  }
2025 
2030  void SelectSortBy(int index)
2031  {
2033  switch (_sort_names[index]) {
2034  case STR_STATION_VIEW_WAITING_STATION:
2035  this->current_mode = MODE_WAITING;
2036  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
2037  break;
2038  case STR_STATION_VIEW_WAITING_AMOUNT:
2039  this->current_mode = MODE_WAITING;
2040  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
2041  break;
2042  case STR_STATION_VIEW_PLANNED_STATION:
2043  this->current_mode = MODE_PLANNED;
2044  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
2045  break;
2046  case STR_STATION_VIEW_PLANNED_AMOUNT:
2047  this->current_mode = MODE_PLANNED;
2048  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
2049  break;
2050  default:
2051  NOT_REACHED();
2052  }
2053  /* Display the current sort variant */
2054  this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->widget_data = _sort_names[index];
2055  this->SetDirty();
2056  }
2057 
2062  void SelectGroupBy(int index)
2063  {
2064  this->grouping_index = index;
2066  this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->widget_data = _group_names[index];
2067  switch (_group_names[index]) {
2068  case STR_STATION_VIEW_GROUP_S_V_D:
2069  this->groupings[1] = GR_SOURCE;
2070  this->groupings[2] = GR_NEXT;
2071  this->groupings[3] = GR_DESTINATION;
2072  break;
2073  case STR_STATION_VIEW_GROUP_S_D_V:
2074  this->groupings[1] = GR_SOURCE;
2075  this->groupings[2] = GR_DESTINATION;
2076  this->groupings[3] = GR_NEXT;
2077  break;
2078  case STR_STATION_VIEW_GROUP_V_S_D:
2079  this->groupings[1] = GR_NEXT;
2080  this->groupings[2] = GR_SOURCE;
2081  this->groupings[3] = GR_DESTINATION;
2082  break;
2083  case STR_STATION_VIEW_GROUP_V_D_S:
2084  this->groupings[1] = GR_NEXT;
2085  this->groupings[2] = GR_DESTINATION;
2086  this->groupings[3] = GR_SOURCE;
2087  break;
2088  case STR_STATION_VIEW_GROUP_D_S_V:
2089  this->groupings[1] = GR_DESTINATION;
2090  this->groupings[2] = GR_SOURCE;
2091  this->groupings[3] = GR_NEXT;
2092  break;
2093  case STR_STATION_VIEW_GROUP_D_V_S:
2094  this->groupings[1] = GR_DESTINATION;
2095  this->groupings[2] = GR_NEXT;
2096  this->groupings[3] = GR_SOURCE;
2097  break;
2098  }
2099  this->SetDirty();
2100  }
2101 
2102  void OnDropdownSelect(int widget, int index) override
2103  {
2104  if (widget == WID_SV_SORT_BY) {
2105  this->SelectSortBy(index);
2106  } else {
2107  this->SelectGroupBy(index);
2108  }
2109  }
2110 
2111  void OnQueryTextFinished(char *str) override
2112  {
2113  if (str == nullptr) return;
2114 
2115  DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), nullptr, str);
2116  }
2117 
2118  void OnResize() override
2119  {
2121  }
2122 
2128  void OnInvalidateData(int data = 0, bool gui_scope = true) override
2129  {
2130  if (gui_scope) {
2131  if (data >= 0 && data < NUM_CARGO) {
2132  this->cached_destinations.Remove((CargoID)data);
2133  } else {
2134  this->ReInit();
2135  }
2136  }
2137  }
2138 };
2139 
2141  STR_STATION_VIEW_WAITING_STATION,
2142  STR_STATION_VIEW_WAITING_AMOUNT,
2143  STR_STATION_VIEW_PLANNED_STATION,
2144  STR_STATION_VIEW_PLANNED_AMOUNT,
2146 };
2147 
2149  STR_STATION_VIEW_GROUP_S_V_D,
2150  STR_STATION_VIEW_GROUP_S_D_V,
2151  STR_STATION_VIEW_GROUP_V_S_D,
2152  STR_STATION_VIEW_GROUP_V_D_S,
2153  STR_STATION_VIEW_GROUP_D_S_V,
2154  STR_STATION_VIEW_GROUP_D_V_S,
2156 };
2157 
2158 static WindowDesc _station_view_desc(
2159  WDP_AUTO, "view_station", 249, 117,
2161  0,
2162  _nested_station_view_widgets, lengthof(_nested_station_view_widgets)
2163 );
2164 
2171 {
2172  AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
2173 }
2174 
2178  StationID station;
2179 };
2180 
2181 static std::vector<TileAndStation> _deleted_stations_nearby;
2182 static std::vector<StationID> _stations_nearby_list;
2183 
2191 template <class T>
2192 static bool AddNearbyStation(TileIndex tile, void *user_data)
2193 {
2194  TileArea *ctx = (TileArea *)user_data;
2195 
2196  /* First check if there were deleted stations here */
2197  for (uint i = 0; i < _deleted_stations_nearby.size(); i++) {
2198  auto ts = _deleted_stations_nearby.begin() + i;
2199  if (ts->tile == tile) {
2200  _stations_nearby_list.push_back(_deleted_stations_nearby[i].station);
2201  _deleted_stations_nearby.erase(ts);
2202  i--;
2203  }
2204  }
2205 
2206  /* Check if own station and if we stay within station spread */
2207  if (!IsTileType(tile, MP_STATION)) return false;
2208 
2209  StationID sid = GetStationIndex(tile);
2210 
2211  /* This station is (likely) a waypoint */
2212  if (!T::IsValidID(sid)) return false;
2213 
2214  T *st = T::Get(sid);
2215  if (st->owner != _local_company || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false;
2216 
2217  if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
2218  _stations_nearby_list.push_back(sid);
2219  }
2220 
2221  return false; // We want to include *all* nearby stations
2222 }
2223 
2233 template <class T>
2234 static const T *FindStationsNearby(TileArea ta, bool distant_join)
2235 {
2236  TileArea ctx = ta;
2237 
2238  _stations_nearby_list.clear();
2239  _deleted_stations_nearby.clear();
2240 
2241  /* Check the inside, to return, if we sit on another station */
2242  TILE_AREA_LOOP(t, ta) {
2243  if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
2244  }
2245 
2246  /* Look for deleted stations */
2247  const BaseStation *st;
2248  FOR_ALL_BASE_STATIONS(st) {
2249  if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
2250  /* Include only within station spread (yes, it is strictly less than) */
2251  if (max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) {
2252  _deleted_stations_nearby.push_back({st->xy, st->index});
2253 
2254  /* Add the station when it's within where we're going to build */
2255  if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
2256  IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
2257  AddNearbyStation<T>(st->xy, &ctx);
2258  }
2259  }
2260  }
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 && min(ta.w, ta.h) >= _settings_game.station.station_spread) return nullptr;
2267  uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1;
2268 
2269  TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
2270  CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
2271 
2272  return nullptr;
2273 }
2274 
2275 static const NWidgetPart _nested_select_station_widgets[] = {
2277  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
2278  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2279  NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
2280  EndContainer(),
2282  NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(),
2284  NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR),
2285  NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
2286  EndContainer(),
2287  EndContainer(),
2288 };
2289 
2294 template <class T>
2298  Scrollbar *vscroll;
2299 
2300  SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) :
2301  Window(desc),
2302  select_station_cmd(cmd),
2303  area(ta)
2304  {
2305  this->CreateNestedTree();
2306  this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
2307  this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
2308  this->FinishInitNested(0);
2309  this->OnInvalidateData(0);
2310 
2311  _thd.freeze = true;
2312  }
2313 
2315  {
2317 
2318  _thd.freeze = false;
2319  }
2320 
2321  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2322  {
2323  if (widget != WID_JS_PANEL) return;
2324 
2325  /* Determine the widest string */
2326  Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
2327  for (uint i = 0; i < _stations_nearby_list.size(); i++) {
2328  const T *st = T::Get(_stations_nearby_list[i]);
2329  SetDParam(0, st->index);
2330  SetDParam(1, st->facilities);
2331  d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION));
2332  }
2333 
2334  resize->height = d.height;
2335  d.height *= 5;
2337  d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2338  *size = d;
2339  }
2340 
2341  void DrawWidget(const Rect &r, int widget) const override
2342  {
2343  if (widget != WID_JS_PANEL) return;
2344 
2345  uint y = r.top + WD_FRAMERECT_TOP;
2346  if (this->vscroll->GetPosition() == 0) {
2347  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
2348  y += this->resize.step_height;
2349  }
2350 
2351  for (uint i = max<uint>(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.size(); ++i, y += this->resize.step_height) {
2352  /* Don't draw anything if it extends past the end of the window. */
2353  if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break;
2354 
2355  const T *st = T::Get(_stations_nearby_list[i - 1]);
2356  SetDParam(0, st->index);
2357  SetDParam(1, st->facilities);
2358  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION);
2359  }
2360  }
2361 
2362  void OnClick(Point pt, int widget, int click_count) override
2363  {
2364  if (widget != WID_JS_PANEL) return;
2365 
2366  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2367  bool distant_join = (st_index > 0);
2368  if (distant_join) st_index--;
2369 
2370  if (distant_join && st_index >= _stations_nearby_list.size()) return;
2371 
2372  /* Insert station to be joined into stored command */
2373  SB(this->select_station_cmd.p2, 16, 16,
2374  (distant_join ? _stations_nearby_list[st_index] : NEW_STATION));
2375 
2376  /* Execute stored Command */
2377  DoCommandP(&this->select_station_cmd);
2378 
2379  /* Close Window; this might cause double frees! */
2381  }
2382 
2383  void OnRealtimeTick(uint delta_ms) override
2384  {
2385  if (_thd.dirty & 2) {
2386  _thd.dirty &= ~2;
2387  this->SetDirty();
2388  }
2389  }
2390 
2391  void OnResize() override
2392  {
2393  this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
2394  }
2395 
2401  void OnInvalidateData(int data = 0, bool gui_scope = true) override
2402  {
2403  if (!gui_scope) return;
2404  FindStationsNearby<T>(this->area, true);
2405  this->vscroll->SetCount((uint)_stations_nearby_list.size() + 1);
2406  this->SetDirty();
2407  }
2408 
2409  void OnMouseOver(Point pt, int widget) override
2410  {
2411  if (widget != WID_JS_PANEL || T::EXPECTED_FACIL == FACIL_WAYPOINT) {
2412  SetViewportCatchmentStation(nullptr, true);
2413  return;
2414  }
2415 
2416  /* Show coverage area of station under cursor */
2417  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2418  if (st_index == 0 || st_index > _stations_nearby_list.size()) {
2419  SetViewportCatchmentStation(nullptr, true);
2420  } else {
2421  st_index--;
2422  SetViewportCatchmentStation(Station::Get(_stations_nearby_list[st_index]), true);
2423  }
2424  }
2425 };
2426 
2427 static WindowDesc _select_station_desc(
2428  WDP_AUTO, "build_station_join", 200, 180,
2431  _nested_select_station_widgets, lengthof(_nested_select_station_widgets)
2432 );
2433 
2434 
2442 template <class T>
2443 static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta)
2444 {
2445  /* Only show selection if distant join is enabled in the settings */
2446  if (!_settings_game.station.distant_join_stations) return false;
2447 
2448  /* If a window is already opened and we didn't ctrl-click,
2449  * return true (i.e. just flash the old window) */
2450  Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
2451  if (selection_window != nullptr) {
2452  /* Abort current distant-join and start new one */
2453  delete selection_window;
2455  }
2456 
2457  /* only show the popup, if we press ctrl */
2458  if (!_ctrl_pressed) return false;
2459 
2460  /* Now check if we could build there */
2461  if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false;
2462 
2463  /* Test for adjacent station or station below selection.
2464  * If adjacent-stations is disabled and we are building next to a station, do not show the selection window.
2465  * but join the other station immediately. */
2466  const T *st = FindStationsNearby<T>(ta, false);
2467  return st == nullptr && (_settings_game.station.adjacent_stations || _stations_nearby_list.size() == 0);
2468 }
2469 
2476 template <class T>
2478 {
2479  if (StationJoinerNeeded<T>(cmd, ta)) {
2481  new SelectStationWindow<T>(&_select_station_desc, cmd, ta);
2482  } else {
2483  DoCommandP(&cmd);
2484  }
2485 }
2486 
2493 {
2494  ShowSelectBaseStationIfNeeded<Station>(cmd, ta);
2495 }
2496 
2503 {
2504  ShowSelectBaseStationIfNeeded<Waypoint>(cmd, ta);
2505 }
&#39;Location&#39; button.
Functions related to OTTD&#39;s strings.
Owner
Enum for all companies/owners.
Definition: company_type.h:20
void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
Expand or collapse a specific row.
List of scheduled road vehs button.
Base types for having sorted lists in GUIs.
Draw all cargoes.
Definition: station_gui.h:24
StationFacility facilities
The facilities that this station has.
void RebuildDone()
Notify the sortlist that the rebuild is done.
CargoDataSet::iterator Begin() const
Get an iterator pointing to the begin of the set of children.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:81
Definition of stuff that is very close to a company, like the company struct itself.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:257
int DrawAcceptedCargo(const Rect &r) const
Draw accepted cargo in the WID_SV_ACCEPT_RATING_LIST widget.
static uint minu(const uint a, const uint b)
Returns the minimum of two unsigned integers.
Definition: math_func.hpp:70
Select station (when joining stations); Window numbers:
Definition: window_type.h:237
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating)
Draw small boxes of cargo amount and ratings data at the given coordinates.
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Definition: cargotype.cpp:135
Horizontally center the text.
Definition: gfx_func.h:97
The information about a vehicle list.
Definition: vehiclelist.h:31
ResizeInfo resize
Resize information.
Definition: window_gui.h:324
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition: cargotype.cpp:31
CargoID next_cargo
ID of the cargo belonging to the entry actually displayed if it&#39;s cargo.
static NWidgetPart SetResize(int16 dx, int16 dy)
Widget part function for setting the resize step.
Definition: widget_type.h:930
Window(WindowDesc *desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1851
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen...
Definition: gfx.cpp:112
void Update(uint count)
Update the count for this entry and propagate the change to the parent entry if there is one...
void CheckRedrawStationCoverage(const Window *w)
Check whether we need to redraw the station coverage text.
Point pos
Location, in tile "units", of the northern tile of the selected area.
static NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
Definition: widget_type.h:1146
&#39;TRAIN&#39; button - list only facilities where is a railroad station.
void SetWidgetLoweredState(byte widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition: window_gui.h:455
open/close an airport to incoming aircraft
Definition: command_type.h:334
Window * parent
Parent window.
Definition: window_gui.h:339
High level window description.
Definition: window_gui.h:168
void SetMinimalSize(uint min_x, uint min_y)
Set minimal size of the widget.
Definition: widget.cpp:817
StationID next_station
ID of the station belonging to the entry actually displayed if it&#39;s to/from/via.
Functions and type for generating vehicle lists.
static bool StationNameSorter(const Station *const &a, const Station *const &b)
Sort stations by their name.
uint8 station_gui_group_order
the order of grouping cargo entries in the station gui
int left
x position of left edge of the window
Definition: window_gui.h:319
Train vehicle type.
Definition: vehicle_type.h:26
CargoList that is used for stations.
Definition: cargopacket.h:463
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:604
bool station_show_coverage
whether to highlight coverage area
Group by estimated final destination ("to").
CommandContainer select_station_cmd
Command to build new station.
static T ToggleBit(T &x, const uint8 y)
Toggles a bit in a variable.
Scrollbar data structure.
Definition: widget_type.h:589
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:64
void ShowSelectStationIfNeeded(const CommandContainer &cmd, TileArea ta)
Show the station selection window when needed.
label for "group by"
Contains enums and function declarations connected with stations GUI.
void SetWidgetDirty(byte widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:581
CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted)
Get the acceptance of cargoes around the tile in 1/8.
Offset at top to draw the frame rectangular area.
Definition: window_gui.h:64
Functions related to debugging.
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
Draw only passenger class cargoes.
Definition: station_gui.h:22
Horizontal container.
Definition: widget_type.h:75
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1114
void Remove(StationID station)
Remove a child associated with the given station.
void SetSortFuncs(SortFunction *const *n_funcs)
Hand the array of sort function pointers to the sort list.
void ShowQueryString(StringID 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:1121
bool distant_join_stations
allow to join non-adjacent stations
static int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:78
Ship vehicle type.
Definition: vehicle_type.h:28
int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo=CT_INVALID)
Draw the given cargo entries in the station GUI.
Maximal number of cargo types in a game.
Definition: cargo_type.h:66
void RecalcDestinations(CargoID i)
Rebuild the cache for estimated destinations which is used to quickly show the "destination" entries ...
static bool StationTypeSorter(const Station *const &a, const Station *const &b)
Sort stations by their type.
The main panel, list of stations.
Specification of a cargo type.
Definition: cargotype.h:57
VehicleType
Available vehicle types.
Definition: vehicle_type.h:23
bool IsInUse() const
Check whether the base station currently is in use; in use means that it is not scheduled for deletio...
&#39;Group by&#39; button
Point size
Size, in tile "units", of the white/red selection area.
static const StringID _group_names[]
Names of the grouping options in the dropdown.
void OnDropdownSelect(int widget, int index) override
A dropdown option associated to this window has been selected.
void SelectGroupBy(int index)
Select a new grouping mode for the cargo view.
CargoDataEntry cached_destinations
Cache for the flows passing through this station.
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
uint32 p2
parameter p2.
Definition: command_type.h:480
The station has no facilities at all.
Definition: station_type.h:53
uint TotalCount() const
Returns total count of cargo at the station, including cargo which is already reserved for loading...
Definition: cargopacket.h:541
void OnRealtimeTick(uint delta_ms) override
Called periodically.
void ShowCompanyStations(CompanyID company)
Opens window with list of company&#39;s stations.
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:207
void SelectSortBy(int index)
Select a new sort criterium for the cargo view.
int DivideApprox(int a, int b)
Deterministic approximate division.
Definition: math_func.cpp:59
int scroll_to_row
If set, scroll the main viewport to the station pointed to by this row.
uint num_children
the number of subentries belonging to this entry.
CargoDataSet::iterator End() const
Get an iterator pointing to the end of the set of children.
byte station_spread
amount a station may spread
by station id
void ToggleWidgetLoweredState(byte widget_index)
Invert the lowered/raised status of a widget.
Definition: window_gui.h:465
List of scheduled planes button.
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
Stores station stats for a single cargo.
Definition: station_base.h:172
TileIndex tile
TileIndex.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:147
void BuildCargoList(CargoDataEntry *cargo, const Station *st)
Build up the cargo view for all cargoes.
Normal push-button (no toggle button) with custom drawing.
Definition: widget_type.h:103
Manual distribution. No link graph calculations are run.
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition: viewport.cpp:2504
Close box (at top-left of a window)
Definition: widget_type.h:69
void SelectSortOrder(SortOrder order)
Select a new sort order for the cargo view.
TileArea area
Location of new station.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0...
void OnQueryTextFinished(char *str) override
The query window opened from this window has closed.
&#39;Sort by&#39; button - reverse sort direction.
void ShowSelectWaypointIfNeeded(const CommandContainer &cmd, TileArea ta)
Show the waypoint selection window when needed.
StringID abbrev
Two letter abbreviation for this cargo type.
Definition: cargotype.h:76
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
Invalidation
Type of data invalidation.
CargoDataEntry * parent
the parent of this entry.
A row being displayed in the cargo view (as opposed to being "hidden" behind a plus sign)...
Stuff related to the text buffer GUI.
static bool StationRatingMinSorter(const Station *const &a, const Station *const &b)
Sort stations by their rating.
A cargo data entry representing one possible row in the station view window&#39;s top part...
#define FOR_EACH_SET_BIT(bitpos_var, bitset_value)
Do an operation for each set set bit in a value.
bool persistent_buildingtools
keep the building tools active after usage
void SetTransfers(bool value)
Set the transfers state.
Group by cargo type.
CommandFlags GetCommandFlags(uint32 cmd)
Definition: command.cpp:386
StationCargoList cargo
The cargo packets of cargo waiting in this station.
Definition: station_base.h:257
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:26
The list of stations per company.
Town * town
The town this station is associated with.
bool HasRating() const
Does this cargo have a rating at this station?
Definition: station_base.h:275
void RaiseWidget(byte widget_index)
Marks a widget as raised.
Definition: window_gui.h:485
uint16 w
The width of the area.
Definition: tilearea_type.h:20
AcceptListHeight
Height of the WID_SV_ACCEPT_RATING_LIST widget for different views.
void CreateNestedTree(bool fill_nested=true)
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1812
Functions related to the vehicle&#39;s GUIs.
void SetListing(Listing l)
Import sort conditions.
Large amount of vertical space between two paragraphs of text.
Definition: window_gui.h:140
CargoDataVector displayed_rows
Parent entry of currently displayed rows (including collapsed ones).
StationSettings station
settings related to station management
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Definition: station_base.h:481
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
StringID name
Name of this type of cargo.
Definition: cargotype.h:72
static T SB(T &x, const uint8 s, const uint8 n, const U d)
Set n bits in x starting at bit s to d.
static bool AddNearbyStation(TileIndex tile, void *user_data)
Add station on this tile to _stations_nearby_list if it&#39;s fully within the station spread...
bool NeedRebuild() const
Check if a rebuild is needed.
North.
List of waiting cargo.
&#39;Sort by&#39; button
static 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:250
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:670
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:910
Functions related to (drawing on) viewports.
void ForceRebuild()
Force that a rebuild is needed.
A connected component of a link graph.
Definition: linkgraph.h:40
Group by source of cargo ("from").
CargoDataEntry * InsertOrRetrieve(CargoID cargo)
Insert a new child or retrieve an existing child using a cargo ID as ID.
Data structure for an opened window.
Definition: window_gui.h:278
Invalid cargo type.
Definition: cargo_type.h:70
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:37
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1828
CargoDataSet * children
the children of this entry.
static const uint8 PC_GREEN
Green palette colour.
Definition: gfx_func.h:222
static bool StationWaitingTotalSorter(const Station *const &a, const Station *const &b)
Sort stations by their waiting cargo.
enable the &#39;Default&#39; button ("\0" is returned)
Definition: textbuf_gui.h:23
void Add(NWidgetBase *wid)
Append widget wid to container.
Definition: widget.cpp:944
Functions related to low-level strings.
StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any)
Select the correct string for an entry referring to the specified station.
byte rating
Station rating for this cargo.
Definition: station_base.h:237
The tile has no ownership.
Definition: company_type.h:27
bool transfers
If there are transfers for this cargo.
void SortStationsList()
Sort the stations list.
void HandleCargoWaitingClick(int row)
Handle a click on a specific row in the cargo view.
Toggle catchment area highlight.
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:152
void OnResize() override
Called after the window got resized.
int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies)
Calculates and draws the accepted or supplied cargo around the selected tile(s)
Definition: station_gui.cpp:56
Scrollbar next to the main panel.
#define FONT_HEIGHT_SMALL
Height of characters in the small (FS_SMALL) font.
Definition: gfx_func.h:175
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:443
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) ...
Definition: widget_type.h:65
int GetScrolledRowFromWidget(int clickpos, const Window *const w, int widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:1959
LinkGraphID link_graph
Link graph this station belongs to.
Definition: station_base.h:259
Group by next station ("via").
This window is used for construction; close it whenever changing company.
Definition: window_gui.h:210
bool IsWidgetLowered(byte widget_index) const
Gets the lowered state of a widget.
Definition: window_gui.h:495
void SetDataTip(uint32 widget_data, StringID tool_tip)
Set data and tool tip of the nested widget.
Definition: widget.cpp:894
void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count)
Show a certain cargo entry characterized by source/next/dest station, cargo ID and amount of cargo at...
Listing GetListing() const
Export current sort conditions.
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
uint current_y
Current vertical size (after resizing).
Definition: widget_type.h:175
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition: map.cpp:191
Sort descending.
Definition: window_gui.h:227
void OnPaint() override
The window must be repainted.
List of accepted cargoes / rating of cargoes.
static Owner GetTileOwner(TileIndex tile)
Returns the owner of a tile.
Definition: tile_map.h:180
Structure for buffering the build command when selecting a station to join.
Definition: command_type.h:477
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:178
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1014
void SetFill(uint fill_x, uint fill_y)
Set the filling of the widget from initial size.
Definition: widget.cpp:839
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
CargoID GetCargo() const
Get the cargo ID for this entry.
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:80
byte status
Status of this cargo, see GoodsEntryStatus.
Definition: station_base.h:228
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:947
&#39;Close airport&#39; button.
Container for cargo from the same location and time.
Definition: cargopacket.h:44
StationCoverageType
Types of cargo to display for station coverage.
Definition: station_gui.h:21
#define TILE_AREA_LOOP(var, ta)
A loop which iterates over the tiles of a TileArea.
Definition of base types and functions in a cross-platform compatible way.
StationID SourceStation() const
Gets the ID of the station where the cargo was loaded for the first time.
Definition: cargopacket.h:160
the length of the string is counted in characters
Definition: textbuf_gui.h:24
by cargo id
&#39;AIRPLANE&#39; button - list only facilities where is an airport.
int accepts_lines
Number of lines in the accepted cargo view.
#define TILE_ADDXY(tile, x, y)
Adds a given offset to a tile.
Definition: map_func.h:260
A number of safeguards to prevent using unsafe methods.
uint Monthly(uint base) const
Scale a value to its monthly equivalent, based on last compression.
Definition: linkgraph.h:518
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:247
bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data)
Function performing a search around a center tile and going outward, thus in circle.
Definition: map.cpp:260
static const uint64 AIRPORT_CLOSED_block
Dummy block for indicating a closed airport.
Definition: airport.h:130
bool HasTransfers() const
Has this entry transfers.
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:104
Base of waypoints.
Geometry functions.
rectangle (stations, depots, ...)
Simple depressed panel.
Definition: widget_type.h:50
static uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition: math_func.hpp:316
bool HasStationInUse(StationID station, bool include_company, CompanyID company)
Tests whether the company&#39;s vehicles have this station in orders.
NodeID node
ID of node in link graph referring to this goods entry.
Definition: station_base.h:260
void DrawSortButtonState(int widget, SortButtonState state) const
Draw a sort button&#39;s up or down arrow symbol.
Definition: widget.cpp:638
const Scrollbar * GetScrollbar(uint widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:311
Represents the covered area of e.g.
Definition: tilearea_type.h:18
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:177
void LowerWidget(byte widget_index)
Marks a widget as lowered.
Definition: window_gui.h:476
HighLightStyle drawstyle
Lower bits 0-3 are reserved for detailed highlight information.
void SetViewportCatchmentStation(const Station *st, bool sel)
Select or deselect station for coverage area highlight.
Definition: viewport.cpp:3475
static void FindStationsAroundSelection()
Find stations adjacent to the current tile highlight area, so that existing coverage area can be draw...
Definition: station_gui.cpp:87
CargoDataEntry expanded_rows
Parent entry of currently expanded rows.
uint GetNumChildren() const
Get the number of children for this entry.
void BuildFlowList(CargoID i, const FlowStatMap &flows, CargoDataEntry *cargo)
Build up the cargo view for PLANNED mode and a specific cargo.
Road vehicle list; Window numbers:
Definition: window_type.h:309
Caption of the window.
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new &#39;real&#39; widget.
Definition: widget_type.h:1114
void Clear()
Delete all subentries, reset count and num_children and adapt parent&#39;s count.
Offset at bottom to draw the frame rectangular area.
Definition: window_gui.h:65
by amount of cargo
static DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags)
Extracts the DC flags needed for DoCommand from the flags returned by GetCommandFlags.
Definition: command_func.h:60
Baseclass for nested widgets.
Definition: widget_type.h:126
void EstimateDestinations(CargoID 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...
Station view; Window numbers:
Definition: window_type.h:340
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:499
CargoDataEntry * filter
Parent of the cargo entry belonging to the row.
uint64 flags
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
Definition: station_base.h:310
bool DoCommandP(const CommandContainer *container, bool my_cmd)
Shortcut for the long DoCommandP when having a container with the data.
Definition: command.cpp:534
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
void BuildCargoList(CargoID i, const StationCargoList &packets, CargoDataEntry *cargo)
Build up the cargo view for WAITING mode and a specific cargo.
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:42
Types related to the station widgets.
int DrawCargoRatings(const Rect &r) const
Draw cargo ratings in the WID_SV_ACCEPT_RATING_LIST widget.
#define FOR_ALL_SORTED_STANDARD_CARGOSPECS(var)
Loop header for iterating over &#39;real&#39; cargoes, sorted by name.
Definition: cargotype.h:173
static bool IsCargoInClass(CargoID c, CargoClass cc)
Does cargo c have cargo class cc?
Definition: cargotype.h:150
Horizontal container.
Definition: widget_type.h:454
void OnResize() override
Called after the window got resized.
void SetSortType(uint8 n_type)
Set the sorttype of the list.
bool Sort(SortFunction *compare)
Sort the list.
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:658
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:18
bool Failed() const
Did this command fail?
Definition: command_type.h:161
StationID station
StationID.
&#39;BUS&#39; button - list only facilities where is a bus stop.
uint ReservedCount() const
Returns sum of cargo reserved for loading onto vehicles.
Definition: cargopacket.h:531
by station name
Station list; Window numbers:
Definition: window_type.h:297
by the same principle the entries are being grouped
FlowStatMap flows
Planned flows through this station.
Definition: station_base.h:261
&#39;TRUCK&#39; button - list only facilities where is a truck stop.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:968
void ShowExtraViewPortWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:37
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:698
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:19
uint16 GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:613
void OnGameTick() override
Called once per (game) tick.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
The StationView window.
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:40
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1146
CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
Get the cargo types being produced around the tile (in a rectangle).
Station with an airport.
Definition: station_type.h:57
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
CargoSortType
void SetResize(uint resize_x, uint resize_y)
Set resize step of the widget.
Definition: widget.cpp:850
Functions related to companies.
static bool StationRatingMaxSorter(const Station *const &a, const Station *const &b)
Sort stations by their rating.
uint8 _sorted_standard_cargo_specs_size
Number of standard cargo specifications stored in the _sorted_cargo_specs array.
Definition: cargotype.cpp:136
Station with a dock.
Definition: station_type.h:58
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:30
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:196
StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column)
Determine if we need to show the special "non-stop" string.
&#39;SHIP&#39; button - list only facilities where is a dock.
&#39;Rename&#39; button.
List of scheduled ships button.
static uint MapSize()
Get the size of the map.
Definition: map_func.h:94
Mode current_mode
Currently selected display mode of cargo view.
Class for storing amounts of cargo.
Definition: cargo_type.h:83
Show cargo waiting at the station.
static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
Draws icons of waiting cargo in the StationView window.
&#39;ALL&#39; button - list all facilities.
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:29
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition: cargotype.cpp:122
GUISettings gui
settings related to the GUI
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:580
static const T * FindStationsNearby(TileArea ta, bool distant_join)
Circulate around the to-be-built station to find stations we could join.
uint32 SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:19
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:119
StationCargoPacketMap ::const_iterator ConstIterator
The const iterator for our container.
Definition: cargopacket.h:222
Ships list; Window numbers:
Definition: window_type.h:315
TextColour GetContrastColour(uint8 background, uint8 threshold)
Determine a contrasty text colour for a coloured background.
Definition: gfx.cpp:1116
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:80
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Draw all non-passenger class cargoes.
Definition: station_gui.h:23
static uint ToPercent8(uint i)
Converts a "fract" value 0..255 to "percent" value 0..100.
Definition: math_func.hpp:289
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:50
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here...
void OnDropdownSelect(int widget, int index) override
A dropdown option associated to this window has been selected.
Sort ascending.
Definition: window_gui.h:226
void OnResize() override
Called after the window got resized.
static NWidgetBase * CargoWidgets(int *biggest_index)
Make a horizontal row of cargo buttons, starting at widget WID_STL_CARGOSTART.
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:217
CargoDataEntry * Retrieve(CargoID cargo) const
Retrieve a child for the given cargo.
Station is a waypoint.
Definition: station_type.h:59
Vertical container.
Definition: widget_type.h:77
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
CargoDataEntry * Retrieve(StationID station) const
Retrieve a child for the given station.
const Station * _viewport_highlight_station
Currently selected station for coverage area highlight.
Definition: viewport.cpp:990
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
TileIndex xy
Base tile of the station.
void SetDisplayedRow(const CargoDataEntry *data)
Mark a specific row, characterized by its CargoDataEntry, as expanded.
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL).
Definition: widget_type.h:999
static const uint8 PC_RED
Red palette colour.
Definition: gfx_func.h:212
Trains list; Window numbers:
Definition: window_type.h:303
Functions related to zooming.
void Remove(CargoID cargo)
Remove a child associated with the given cargo.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
uint8 station_gui_sort_by
sort cargo entries in the station gui by station name or amount
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:174
A tile of a station.
Definition: tile_type.h:48
Widget numbers used for list of cargo types (not present in _company_stations_widgets).
static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta)
Check whether we need to show the station selection window.
static uint MapMaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition: map_func.h:113
static Station * GetByTile(TileIndex tile)
Get the station belonging to a specific tile.
List of scheduled trains button.
uint8 exclusive_counter
months till the exclusivity expires
Definition: town.h:76
StationID GetStation() const
Get the station ID for this entry.
Aircraft list; Window numbers:
Definition: window_type.h:321
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2417
&#39;NO&#39; button - list stations where no cargo is waiting.
Mode
Display mode of the cargo view.
Functions related to commands.
Types/functions related to cargoes.
static bool IsValidID(size_t index)
Tests whether given index is a valid index for station of this type.
Coordinates of a point in 2D.
CargoID Index() const
Determines index of this cargospec.
Definition: cargotype.h:90
Owner owner
The owner of this station.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:235
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:33
Drop down list.
Definition: widget_type.h:70
bool freeze
Freeze highlight in place.
rename a station
Definition: command_type.h:248
uint16 GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:622
Index of the small font in the font tables.
Definition: gfx_type.h:205
bool adjacent_stations
allow stations to be built directly adjacent to other stations
Flow descriptions by origin stations.
Definition: station_base.h:154
Station with bus stops.
Definition: station_type.h:56
Declaration of link graph classes used for cargo distribution.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:19
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable...
Definition: window_gui.h:326
Grouping
Type of grouping used in each of the "columns".
static TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition: map_func.h:372
Aircraft vehicle type.
Definition: vehicle_type.h:29
static const StringID _sort_names[]
Names of the sorting options in the dropdown.
Airport airport
Tile area the airport covers.
Definition: station_base.h:466
void OnPaint() override
The window must be repainted.
void ShowSelectBaseStationIfNeeded(const CommandContainer &cmd, TileArea ta)
Show the station selection window when needed.
Offset at right to draw the frame rectangular area.
Definition: window_gui.h:63
Dropdown button.
static const uint MAX_LENGTH_STATION_NAME_CHARS
The maximum length of a station name in characters including &#39;\0&#39;.
Definition: station_type.h:89
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:321
StationID station
ID of the station this entry is associated with.
Passengers.
Definition: cargotype.h:41
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Definition: cargopacket.h:261
void OnMouseOver(Point pt, int widget) override
The mouse is currently moving over the window or has just moved outside of the window.
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:983
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
bool IsValid() const
Tests for validity of this cargospec.
Definition: cargotype.h:100
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:85
Window for selecting stations/waypoints to (distant) join to.
int rating_lines
Number of lines in the cargo ratings view.
Base of the town class.
bool IsDescSortOrder() const
Check if the sort order is descending.
Station with truck stops.
Definition: station_type.h:55
Caption of the window.
#define CMD_MSG(x)
Used to combine a StringID with the command.
Definition: command_type.h:370
uint count
sum of counts of all children or amount of cargo for this entry.
uint16 Count() const
Gets the number of &#39;items&#39; in this packet.
Definition: cargopacket.h:101
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:707
&#39;Accepts&#39; / &#39;Ratings&#39; button.
uint AvailableCount() const
Returns sum of cargo still available for loading at the sation.
Definition: cargopacket.h:522
void SetCapacityFromWidget(Window *w, int widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget. ...
Definition: widget.cpp:1973
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows)...
Definition: viewport.cpp:3374
Specification of a rectangle with absolute coordinates of all edges.
Vertical scrollbar.
Definition: widget_type.h:84
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
Text is written right-to-left by default.
Definition: strings_type.h:26
static uint MapMaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition: map_func.h:104
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:314
Functions related to tile highlights.
Window functions not directly related to making/drawing windows.
void IncrementSize()
Increment.
void BuildStationsList(const Owner owner)
(Re)Build station list
Station with train station.
Definition: station_type.h:54
Find a place automatically.
Definition: window_gui.h:156
&#39;ALL&#39; button - list all stations.
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
&#39;Sort order&#39; button
uint expand_shrink_width
The width allocated to the expand/shrink &#39;button&#39;.
GUI functions that shouldn&#39;t be here.
bool SortFunction(const T &, const T &)
Signature of sort function.
Definition: sortlist_type.h:51
Base classes/functions for stations.
static Station * Get(size_t index)
Gets station with given index.
uint16 h
The height of the area.
Definition: tilearea_type.h:21
uint GetCount() const
Get the cargo count for this entry.
uint8 station_gui_sort_order
the sort order of entries in the station gui - ascending or descending
CompanyID exclusivity
which company has exclusivity
Definition: town.h:75
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1095
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:46
CargoDataEntry * GetParent() const
Get the parent entry for this entry.
Dimensions (a width and height) of a rectangle in 2D.
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:429
int grouping_index
Currently selected entry in the grouping drop down.
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:62
Struct containing TileIndex and StationID.
Base class for all station-ish types.
Station data structure.
Definition: station_base.h:452
Nested widget with a child.
Definition: widget_type.h:545
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
uint32 cmd
command being executed.
Definition: command_type.h:481
LinkGraphSettings linkgraph
settings for link graph calculations
Road vehicle type.
Definition: vehicle_type.h:27
Set when the station accepts the cargo currently for final deliveries.
Definition: station_base.h:179
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
byte dirty
Whether the build station window needs to redraw due to the changed selection.
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition: map_func.h:165
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:832
int pos_y
Vertical position of top-left corner of the widget in the window.
Definition: widget_type.h:178
CargoID cargo
ID of the cargo this entry is associated with.
CargoDataEntry * InsertOrRetrieve(StationID station)
Insert a new child or retrieve an existing child using a station ID as ID.
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:620
(Toggle) Button with text
Definition: widget_type.h:55
static bool StationWaitingAvailableSorter(const Station *const &a, const Station *const &b)
Sort stations by their available waiting cargo.
uint16 GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:631
uint8 SortType() const
Get the sorttype of the list.
Definition: sortlist_type.h:96
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:201
Base class for a &#39;real&#39; widget.
Definition: widget_type.h:284