OpenTTD
station_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "gui.h"
13 #include "textbuf_gui.h"
14 #include "company_func.h"
15 #include "command_func.h"
16 #include "vehicle_gui.h"
17 #include "cargotype.h"
18 #include "station_gui.h"
19 #include "strings_func.h"
20 #include "string_func.h"
21 #include "window_func.h"
22 #include "viewport_func.h"
23 #include "widgets/dropdown_func.h"
24 #include "station_base.h"
25 #include "waypoint_base.h"
26 #include "tilehighlight_func.h"
27 #include "company_base.h"
28 #include "sortlist_type.h"
29 #include "core/geometry_func.hpp"
30 #include "vehiclelist.h"
31 #include "town.h"
32 #include "linkgraph/linkgraph.h"
33 #include "zoom_func.h"
34 
35 #include "widgets/station_widget.h"
36 
37 #include "table/strings.h"
38 
39 #include <set>
40 #include <vector>
41 
42 #include "safeguards.h"
43 
54 int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies)
55 {
56  TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
57  CargoTypes cargo_mask = 0;
58  if (_thd.drawstyle == HT_RECT && tile < MapSize()) {
59  CargoArray cargoes;
60  if (supplies) {
61  cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
62  } else {
63  cargoes = GetAcceptanceAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
64  }
65 
66  /* Convert cargo counts to a set of cargo bits, and draw the result. */
67  for (CargoID i = 0; i < NUM_CARGO; i++) {
68  switch (sct) {
69  case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break;
70  case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break;
71  case SCT_ALL: break;
72  default: NOT_REACHED();
73  }
74  if (cargoes[i] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, i);
75  }
76  }
77  SetDParam(0, cargo_mask);
78  return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO);
79 }
80 
86 {
87  /* With distant join we don't know which station will be selected, so don't show any */
88  if (_ctrl_pressed) {
89  SetViewportCatchmentStation(nullptr, true);
90  return;
91  }
92 
93  /* Tile area for TileHighlightData */
94  TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1);
95 
96  /* Extended area by one tile */
97  uint x = TileX(location.tile);
98  uint y = TileY(location.tile);
99 
100  int max_c = 1;
101  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)));
102 
103  Station *adjacent = nullptr;
104 
105  /* Direct loop instead of FindStationsAroundTiles as we are not interested in catchment area */
106  TILE_AREA_LOOP(tile, ta) {
107  if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) {
108  Station *st = Station::GetByTile(tile);
109  if (st == nullptr) continue;
110  if (adjacent != nullptr && st != adjacent) {
111  /* Multiple nearby, distant join is required. */
112  adjacent = nullptr;
113  break;
114  }
115  adjacent = st;
116  }
117  }
118  SetViewportCatchmentStation(adjacent, true);
119 }
120 
127 {
128  /* Test if ctrl state changed */
129  static bool _last_ctrl_pressed;
130  if (_ctrl_pressed != _last_ctrl_pressed) {
131  _thd.dirty = 0xff;
132  _last_ctrl_pressed = _ctrl_pressed;
133  }
134 
135  if (_thd.dirty & 1) {
136  _thd.dirty &= ~1;
137  w->SetDirty();
138 
141  }
142  }
143 }
144 
160 static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating)
161 {
162  static const uint units_full = 576;
163  static const uint rating_full = 224;
164 
165  const CargoSpec *cs = CargoSpec::Get(type);
166  if (!cs->IsValid()) return;
167 
168  int colour = cs->rating_colour;
169  TextColour tc = GetContrastColour(colour);
170  uint w = (minu(amount, units_full) + 5) / 36;
171 
172  int height = GetCharacterHeight(FS_SMALL);
173 
174  /* Draw total cargo (limited) on station (fits into 16 pixels) */
175  if (w != 0) GfxFillRect(left, y, left + w - 1, y + height, colour);
176 
177  /* Draw a one pixel-wide bar of additional cargo meter, useful
178  * for stations with only a small amount (<=30) */
179  if (w == 0) {
180  uint rest = amount / 5;
181  if (rest != 0) {
182  w += left;
183  GfxFillRect(w, y + height - rest, w, y + height, colour);
184  }
185  }
186 
187  DrawString(left + 1, right, y, cs->abbrev, tc);
188 
189  /* Draw green/red ratings bar (fits into 14 pixels) */
190  y += height + 2;
191  GfxFillRect(left + 1, y, left + 14, y, PC_RED);
192  rating = minu(rating, rating_full) / 16;
193  if (rating != 0) GfxFillRect(left + 1, y, left + rating, y, PC_GREEN);
194 }
195 
197 
202 {
203 protected:
204  /* Runtime saved values */
205  static Listing last_sorting;
206  static byte facilities; // types of stations of interest
207  static bool include_empty; // whether we should include stations without waiting cargo
208  static const CargoTypes cargo_filter_max;
209  static CargoTypes cargo_filter; // bitmap of cargo types to include
210  static const Station *last_station;
211 
212  /* Constants for sorting stations */
213  static const StringID sorter_names[];
214  static GUIStationList::SortFunction * const sorter_funcs[];
215 
216  GUIStationList stations;
217  Scrollbar *vscroll;
218 
225  {
226  if (!this->stations.NeedRebuild()) return;
227 
228  DEBUG(misc, 3, "Building station list for company %d", owner);
229 
230  this->stations.clear();
231 
232  for (const Station *st : Station::Iterate()) {
233  if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
234  if (this->facilities & st->facilities) { // only stations with selected facilities
235  int num_waiting_cargo = 0;
236  for (CargoID j = 0; j < NUM_CARGO; j++) {
237  if (st->goods[j].HasRating()) {
238  num_waiting_cargo++; // count number of waiting cargo
239  if (HasBit(this->cargo_filter, j)) {
240  this->stations.push_back(st);
241  break;
242  }
243  }
244  }
245  /* stations without waiting cargo */
246  if (num_waiting_cargo == 0 && this->include_empty) {
247  this->stations.push_back(st);
248  }
249  }
250  }
251  }
252 
253  this->stations.shrink_to_fit();
254  this->stations.RebuildDone();
255 
256  this->vscroll->SetCount((uint)this->stations.size()); // Update the scrollbar
257  }
258 
260  static bool StationNameSorter(const Station * const &a, const Station * const &b)
261  {
262  static char buf_cache[64];
263  char buf[64];
264 
265  SetDParam(0, a->index);
266  GetString(buf, STR_STATION_NAME, lastof(buf));
267 
268  if (b != last_station) {
269  last_station = b;
270  SetDParam(0, b->index);
271  GetString(buf_cache, STR_STATION_NAME, lastof(buf_cache));
272  }
273 
274  int r = strnatcmp(buf, buf_cache); // Sort by name (natural sorting).
275  if (r == 0) return a->index < b->index;
276  return r < 0;
277  }
278 
280  static bool StationTypeSorter(const Station * const &a, const Station * const &b)
281  {
282  return a->facilities < b->facilities;
283  }
284 
286  static bool StationWaitingTotalSorter(const Station * const &a, const Station * const &b)
287  {
288  int diff = 0;
289 
290  CargoID j;
291  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
292  diff += a->goods[j].cargo.TotalCount() - b->goods[j].cargo.TotalCount();
293  }
294 
295  return diff < 0;
296  }
297 
299  static bool StationWaitingAvailableSorter(const Station * const &a, const Station * const &b)
300  {
301  int diff = 0;
302 
303  CargoID j;
304  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
305  diff += a->goods[j].cargo.AvailableCount() - b->goods[j].cargo.AvailableCount();
306  }
307 
308  return diff < 0;
309  }
310 
312  static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b)
313  {
314  byte maxr1 = 0;
315  byte maxr2 = 0;
316 
317  CargoID j;
318  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
319  if (a->goods[j].HasRating()) maxr1 = max(maxr1, a->goods[j].rating);
320  if (b->goods[j].HasRating()) maxr2 = max(maxr2, b->goods[j].rating);
321  }
322 
323  return maxr1 < maxr2;
324  }
325 
327  static bool StationRatingMinSorter(const Station * const &a, const Station * const &b)
328  {
329  byte minr1 = 255;
330  byte minr2 = 255;
331 
332  for (CargoID j = 0; j < NUM_CARGO; j++) {
333  if (!HasBit(cargo_filter, j)) continue;
334  if (a->goods[j].HasRating()) minr1 = min(minr1, a->goods[j].rating);
335  if (b->goods[j].HasRating()) minr2 = min(minr2, b->goods[j].rating);
336  }
337 
338  return minr1 > minr2;
339  }
340 
343  {
344  if (!this->stations.Sort()) return;
345 
346  /* Reset name sorter sort cache */
347  this->last_station = nullptr;
348 
349  /* Set the modified widget dirty */
351  }
352 
353 public:
355  {
356  this->stations.SetListing(this->last_sorting);
357  this->stations.SetSortFuncs(this->sorter_funcs);
358  this->stations.ForceRebuild();
359  this->stations.NeedResort();
360  this->SortStationsList();
361 
362  this->CreateNestedTree();
363  this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR);
364  this->FinishInitNested(window_number);
365  this->owner = (Owner)this->window_number;
366 
367  const CargoSpec *cs;
369  if (!HasBit(this->cargo_filter, cs->Index())) continue;
370  this->LowerWidget(WID_STL_CARGOSTART + index);
371  }
372 
373  if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask;
374 
375  for (uint i = 0; i < 5; i++) {
376  if (HasBit(this->facilities, i)) this->LowerWidget(i + WID_STL_TRAIN);
377  }
378  this->SetWidgetLoweredState(WID_STL_NOCARGOWAITING, this->include_empty);
379 
380  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
381  }
382 
384  {
385  this->last_sorting = this->stations.GetListing();
386  }
387 
388  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
389  {
390  switch (widget) {
391  case WID_STL_SORTBY: {
392  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
393  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
394  d.height += padding.height;
395  *size = maxdim(*size, d);
396  break;
397  }
398 
399  case WID_STL_SORTDROPBTN: {
400  Dimension d = {0, 0};
401  for (int i = 0; this->sorter_names[i] != INVALID_STRING_ID; i++) {
402  d = maxdim(d, GetStringBoundingBox(this->sorter_names[i]));
403  }
404  d.width += padding.width;
405  d.height += padding.height;
406  *size = maxdim(*size, d);
407  break;
408  }
409 
410  case WID_STL_LIST:
411  resize->height = FONT_HEIGHT_NORMAL;
412  size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM;
413  break;
414 
415  case WID_STL_TRAIN:
416  case WID_STL_TRUCK:
417  case WID_STL_BUS:
418  case WID_STL_AIRPLANE:
419  case WID_STL_SHIP:
420  size->height = max<uint>(FONT_HEIGHT_SMALL, 10) + padding.height;
421  break;
422 
423  case WID_STL_CARGOALL:
424  case WID_STL_FACILALL:
425  case WID_STL_NOCARGOWAITING: {
426  Dimension d = GetStringBoundingBox(widget == WID_STL_NOCARGOWAITING ? STR_ABBREV_NONE : STR_ABBREV_ALL);
427  d.width += padding.width + 2;
428  d.height += padding.height;
429  *size = maxdim(*size, d);
430  break;
431  }
432 
433  default:
434  if (widget >= WID_STL_CARGOSTART) {
436  d.width += padding.width + 2;
437  d.height += padding.height;
438  *size = maxdim(*size, d);
439  }
440  break;
441  }
442  }
443 
444  void OnPaint() override
445  {
446  this->BuildStationsList((Owner)this->window_number);
447  this->SortStationsList();
448 
449  this->DrawWidgets();
450  }
451 
452  void DrawWidget(const Rect &r, int widget) const override
453  {
454  switch (widget) {
455  case WID_STL_SORTBY:
456  /* draw arrow pointing up/down for ascending/descending sorting */
458  break;
459 
460  case WID_STL_LIST: {
461  bool rtl = _current_text_dir == TD_RTL;
462  int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->stations.size());
463  int y = r.top + WD_FRAMERECT_TOP;
464  for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner
465  const Station *st = this->stations[i];
466  assert(st->xy != INVALID_TILE);
467 
468  /* Do not do the complex check HasStationInUse here, it may be even false
469  * when the order had been removed and the station list hasn't been removed yet */
470  assert(st->owner == owner || st->owner == OWNER_NONE);
471 
472  SetDParam(0, st->index);
473  SetDParam(1, st->facilities);
474  int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION);
475  x += rtl ? -5 : 5;
476 
477  /* show cargo waiting and station ratings */
478  for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) {
479  CargoID cid = _sorted_cargo_specs[j]->Index();
480  if (st->goods[cid].cargo.TotalCount() > 0) {
481  /* For RTL we work in exactly the opposite direction. So
482  * decrement the space needed first, then draw to the left
483  * instead of drawing to the left and then incrementing
484  * the space. */
485  if (rtl) {
486  x -= 20;
487  if (x < r.left + WD_FRAMERECT_LEFT) break;
488  }
489  StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating);
490  if (!rtl) {
491  x += 20;
492  if (x > r.right - WD_FRAMERECT_RIGHT) break;
493  }
494  }
495  }
496  y += FONT_HEIGHT_NORMAL;
497  }
498 
499  if (this->vscroll->GetCount() == 0) { // company has no stations
500  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_NONE);
501  return;
502  }
503  break;
504  }
505 
506  case WID_STL_NOCARGOWAITING: {
507  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
508  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER);
509  break;
510  }
511 
512  case WID_STL_CARGOALL: {
513  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
514  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
515  break;
516  }
517 
518  case WID_STL_FACILALL: {
519  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
520  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
521  break;
522  }
523 
524  default:
525  if (widget >= WID_STL_CARGOSTART) {
526  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
527  int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1;
528  GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour);
529  TextColour tc = GetContrastColour(cs->rating_colour);
530  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER);
531  }
532  break;
533  }
534  }
535 
536  void SetStringParameters(int widget) const override
537  {
538  if (widget == WID_STL_CAPTION) {
539  SetDParam(0, this->window_number);
540  SetDParam(1, this->vscroll->GetCount());
541  }
542  }
543 
544  void OnClick(Point pt, int widget, int click_count) override
545  {
546  switch (widget) {
547  case WID_STL_LIST: {
548  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL);
549  if (id_v >= this->stations.size()) return; // click out of list bound
550 
551  const Station *st = this->stations[id_v];
552  /* do not check HasStationInUse - it is slow and may be invalid */
553  assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE);
554 
555  if (_ctrl_pressed) {
557  } else {
559  }
560  break;
561  }
562 
563  case WID_STL_TRAIN:
564  case WID_STL_TRUCK:
565  case WID_STL_BUS:
566  case WID_STL_AIRPLANE:
567  case WID_STL_SHIP:
568  if (_ctrl_pressed) {
569  ToggleBit(this->facilities, widget - WID_STL_TRAIN);
570  this->ToggleWidgetLoweredState(widget);
571  } else {
572  uint i;
573  FOR_EACH_SET_BIT(i, this->facilities) {
574  this->RaiseWidget(i + WID_STL_TRAIN);
575  }
576  this->facilities = 1 << (widget - WID_STL_TRAIN);
577  this->LowerWidget(widget);
578  }
579  this->stations.ForceRebuild();
580  this->SetDirty();
581  break;
582 
583  case WID_STL_FACILALL:
584  for (uint i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) {
585  this->LowerWidget(i);
586  }
587 
589  this->stations.ForceRebuild();
590  this->SetDirty();
591  break;
592 
593  case WID_STL_CARGOALL: {
594  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
595  this->LowerWidget(WID_STL_CARGOSTART + i);
596  }
598 
599  this->cargo_filter = _cargo_mask;
600  this->include_empty = true;
601  this->stations.ForceRebuild();
602  this->SetDirty();
603  break;
604  }
605 
606  case WID_STL_SORTBY: // flip sorting method asc/desc
607  this->stations.ToggleSortOrder();
608  this->SetDirty();
609  break;
610 
611  case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu
612  ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0);
613  break;
614 
616  if (_ctrl_pressed) {
617  this->include_empty = !this->include_empty;
619  } else {
620  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
621  this->RaiseWidget(WID_STL_CARGOSTART + i);
622  }
623 
624  this->cargo_filter = 0;
625  this->include_empty = true;
626 
628  }
629  this->stations.ForceRebuild();
630  this->SetDirty();
631  break;
632 
633  default:
634  if (widget >= WID_STL_CARGOSTART) { // change cargo_filter
635  /* Determine the selected cargo type */
636  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
637 
638  if (_ctrl_pressed) {
639  ToggleBit(this->cargo_filter, cs->Index());
640  this->ToggleWidgetLoweredState(widget);
641  } else {
642  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
643  this->RaiseWidget(WID_STL_CARGOSTART + i);
644  }
646 
647  this->cargo_filter = 0;
648  this->include_empty = false;
649 
650  SetBit(this->cargo_filter, cs->Index());
651  this->LowerWidget(widget);
652  }
653  this->stations.ForceRebuild();
654  this->SetDirty();
655  }
656  break;
657  }
658  }
659 
660  void OnDropdownSelect(int widget, int index) override
661  {
662  if (this->stations.SortType() != index) {
663  this->stations.SetSortType(index);
664 
665  /* Display the current sort variant */
666  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
667 
668  this->SetDirty();
669  }
670  }
671 
672  void OnGameTick() override
673  {
674  if (this->stations.NeedResort()) {
675  DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number);
676  this->SetDirty();
677  }
678  }
679 
680  void OnResize() override
681  {
683  }
684 
690  void OnInvalidateData(int data = 0, bool gui_scope = true) override
691  {
692  if (data == 0) {
693  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
694  this->stations.ForceRebuild();
695  } else {
696  this->stations.ForceResort();
697  }
698  }
699 };
700 
701 Listing CompanyStationsWindow::last_sorting = {false, 0};
702 byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
703 bool CompanyStationsWindow::include_empty = true;
704 const CargoTypes CompanyStationsWindow::cargo_filter_max = ALL_CARGOTYPES;
705 CargoTypes CompanyStationsWindow::cargo_filter = ALL_CARGOTYPES;
706 const Station *CompanyStationsWindow::last_station = nullptr;
707 
708 /* Available station sorting functions */
709 GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
716 };
717 
718 /* Names of the sorting functions */
719 const StringID CompanyStationsWindow::sorter_names[] = {
720  STR_SORT_BY_NAME,
721  STR_SORT_BY_FACILITY,
722  STR_SORT_BY_WAITING_TOTAL,
723  STR_SORT_BY_WAITING_AVAILABLE,
724  STR_SORT_BY_RATING_MAX,
725  STR_SORT_BY_RATING_MIN,
727 };
728 
734 static NWidgetBase *CargoWidgets(int *biggest_index)
735 {
736  NWidgetHorizontal *container = new NWidgetHorizontal();
737 
738  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
739  NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
740  panel->SetMinimalSize(14, 11);
741  panel->SetResize(0, 0);
742  panel->SetFill(0, 1);
743  panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
744  container->Add(panel);
745  }
747  return container;
748 }
749 
750 static const NWidgetPart _nested_company_stations_widgets[] = {
752  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
753  NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
754  NWidget(WWT_SHADEBOX, COLOUR_GREY),
755  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
756  NWidget(WWT_STICKYBOX, COLOUR_GREY),
757  EndContainer(),
759  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),
760  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),
761  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),
762  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),
763  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),
764  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1),
765  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(),
767  NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(),
768  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1),
769  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
770  EndContainer(),
772  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
773  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten.
774  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
775  EndContainer(),
777  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(),
780  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
781  EndContainer(),
782  EndContainer(),
783 };
784 
785 static WindowDesc _company_stations_desc(
786  WDP_AUTO, "list_stations", 358, 162,
788  0,
789  _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets)
790 );
791 
798 {
799  if (!Company::IsValidID(company)) return;
800 
801  AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
802 }
803 
804 static const NWidgetPart _nested_station_view_widgets[] = {
806  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
807  NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
808  NWidget(WWT_SHADEBOX, COLOUR_GREY),
809  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
810  NWidget(WWT_STICKYBOX, COLOUR_GREY),
811  EndContainer(),
813  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
814  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
815  EndContainer(),
817  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0),
818  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
819  EndContainer(),
823  EndContainer(),
827  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
828  SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
829  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1),
830  SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
831  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
832  SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
833  EndContainer(),
834  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
835  SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
836  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CATCHMENT), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
837  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
838  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
839  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
840  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
841  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
842  EndContainer(),
843 };
844 
854 static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
855 {
856  int width = ScaleGUITrad(10);
857  uint num = min((waiting + (width / 2)) / width, (right - left) / width); // maximum is width / 10 icons so it won't overflow
858  if (num == 0) return;
859 
860  SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon();
861 
862  int x = _current_text_dir == TD_RTL ? left : right - num * width;
863  do {
864  DrawSprite(sprite, PAL_NONE, x, y);
865  x += width;
866  } while (--num);
867 }
868 
869 enum SortOrder {
870  SO_DESCENDING,
871  SO_ASCENDING
872 };
873 
874 class CargoDataEntry;
875 
882 };
883 
884 class CargoSorter {
885 public:
886  CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {}
887  CargoSortType GetSortType() {return this->type;}
888  bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
889 
890 private:
891  CargoSortType type;
892  SortOrder order;
893 
894  template<class Tid>
895  bool SortId(Tid st1, Tid st2) const;
896  bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
897  bool SortStation (StationID st1, StationID st2) const;
898 };
899 
900 typedef std::set<CargoDataEntry *, CargoSorter> CargoDataSet;
901 
908 public:
909  CargoDataEntry();
910  ~CargoDataEntry();
911 
917  CargoDataEntry *InsertOrRetrieve(StationID station)
918  {
919  return this->InsertOrRetrieve<StationID>(station);
920  }
921 
928  {
929  return this->InsertOrRetrieve<CargoID>(cargo);
930  }
931 
932  void Update(uint count);
933 
938  void Remove(StationID station)
939  {
940  CargoDataEntry t(station);
941  this->Remove(&t);
942  }
943 
948  void Remove(CargoID cargo)
949  {
950  CargoDataEntry t(cargo);
951  this->Remove(&t);
952  }
953 
959  CargoDataEntry *Retrieve(StationID station) const
960  {
961  CargoDataEntry t(station);
962  return this->Retrieve(this->children->find(&t));
963  }
964 
971  {
972  CargoDataEntry t(cargo);
973  return this->Retrieve(this->children->find(&t));
974  }
975 
976  void Resort(CargoSortType type, SortOrder order);
977 
981  StationID GetStation() const { return this->station; }
982 
986  CargoID GetCargo() const { return this->cargo; }
987 
991  uint GetCount() const { return this->count; }
992 
996  CargoDataEntry *GetParent() const { return this->parent; }
997 
1001  uint GetNumChildren() const { return this->num_children; }
1002 
1006  CargoDataSet::iterator Begin() const { return this->children->begin(); }
1007 
1011  CargoDataSet::iterator End() const { return this->children->end(); }
1012 
1016  bool HasTransfers() const { return this->transfers; }
1017 
1021  void SetTransfers(bool value) { this->transfers = value; }
1022 
1023  void Clear();
1024 private:
1025 
1026  CargoDataEntry(StationID st, uint c, CargoDataEntry *p);
1027  CargoDataEntry(CargoID car, uint c, CargoDataEntry *p);
1028  CargoDataEntry(StationID st);
1029  CargoDataEntry(CargoID car);
1030 
1031  CargoDataEntry *Retrieve(CargoDataSet::iterator i) const;
1032 
1033  template<class Tid>
1034  CargoDataEntry *InsertOrRetrieve(Tid s);
1035 
1036  void Remove(CargoDataEntry *comp);
1037  void IncrementSize();
1038 
1040  const union {
1041  StationID station;
1042  struct {
1044  bool transfers;
1045  };
1046  };
1048  uint count;
1049  CargoDataSet *children;
1050 };
1051 
1052 CargoDataEntry::CargoDataEntry() :
1053  parent(nullptr),
1054  station(INVALID_STATION),
1055  num_children(0),
1056  count(0),
1057  children(new CargoDataSet(CargoSorter(ST_CARGO_ID)))
1058 {}
1059 
1060 CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) :
1061  parent(parent),
1062  cargo(cargo),
1063  num_children(0),
1064  count(count),
1065  children(new CargoDataSet)
1066 {}
1067 
1068 CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) :
1069  parent(parent),
1070  station(station),
1071  num_children(0),
1072  count(count),
1073  children(new CargoDataSet)
1074 {}
1075 
1076 CargoDataEntry::CargoDataEntry(StationID station) :
1077  parent(nullptr),
1078  station(station),
1079  num_children(0),
1080  count(0),
1081  children(nullptr)
1082 {}
1083 
1084 CargoDataEntry::CargoDataEntry(CargoID cargo) :
1085  parent(nullptr),
1086  cargo(cargo),
1087  num_children(0),
1088  count(0),
1089  children(nullptr)
1090 {}
1091 
1092 CargoDataEntry::~CargoDataEntry()
1093 {
1094  this->Clear();
1095  delete this->children;
1096 }
1097 
1102 {
1103  if (this->children != nullptr) {
1104  for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) {
1105  assert(*i != this);
1106  delete *i;
1107  }
1108  this->children->clear();
1109  }
1110  if (this->parent != nullptr) this->parent->count -= this->count;
1111  this->count = 0;
1112  this->num_children = 0;
1113 }
1114 
1122 {
1123  CargoDataSet::iterator i = this->children->find(child);
1124  if (i != this->children->end()) {
1125  delete *i;
1126  this->children->erase(i);
1127  }
1128 }
1129 
1136 template<class Tid>
1138 {
1139  CargoDataEntry tmp(child_id);
1140  CargoDataSet::iterator i = this->children->find(&tmp);
1141  if (i == this->children->end()) {
1142  IncrementSize();
1143  return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first);
1144  } else {
1145  CargoDataEntry *ret = *i;
1146  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1147  return ret;
1148  }
1149 }
1150 
1157 {
1158  this->count += count;
1159  if (this->parent != nullptr) this->parent->Update(count);
1160 }
1161 
1166 {
1167  ++this->num_children;
1168  if (this->parent != nullptr) this->parent->IncrementSize();
1169 }
1170 
1171 void CargoDataEntry::Resort(CargoSortType type, SortOrder order)
1172 {
1173  CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order));
1174  delete this->children;
1175  this->children = new_subs;
1176 }
1177 
1178 CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const
1179 {
1180  if (i == this->children->end()) {
1181  return nullptr;
1182  } else {
1183  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1184  return *i;
1185  }
1186 }
1187 
1188 bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1189 {
1190  switch (this->type) {
1191  case ST_STATION_ID:
1192  return this->SortId<StationID>(cd1->GetStation(), cd2->GetStation());
1193  case ST_CARGO_ID:
1194  return this->SortId<CargoID>(cd1->GetCargo(), cd2->GetCargo());
1195  case ST_COUNT:
1196  return this->SortCount(cd1, cd2);
1197  case ST_STATION_STRING:
1198  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1199  default:
1200  NOT_REACHED();
1201  }
1202 }
1203 
1204 template<class Tid>
1205 bool CargoSorter::SortId(Tid st1, Tid st2) const
1206 {
1207  return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1;
1208 }
1209 
1210 bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1211 {
1212  uint c1 = cd1->GetCount();
1213  uint c2 = cd2->GetCount();
1214  if (c1 == c2) {
1215  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1216  } else if (this->order == SO_ASCENDING) {
1217  return c1 < c2;
1218  } else {
1219  return c2 < c1;
1220  }
1221 }
1222 
1223 bool CargoSorter::SortStation(StationID st1, StationID st2) const
1224 {
1225  static char buf1[MAX_LENGTH_STATION_NAME_CHARS];
1226  static char buf2[MAX_LENGTH_STATION_NAME_CHARS];
1227 
1228  if (!Station::IsValidID(st1)) {
1229  return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2);
1230  } else if (!Station::IsValidID(st2)) {
1231  return order == SO_DESCENDING;
1232  }
1233 
1234  SetDParam(0, st1);
1235  GetString(buf1, STR_STATION_NAME, lastof(buf1));
1236  SetDParam(0, st2);
1237  GetString(buf2, STR_STATION_NAME, lastof(buf2));
1238 
1239  int res = strnatcmp(buf1, buf2); // Sort by name (natural sorting).
1240  if (res == 0) {
1241  return this->SortId(st1, st2);
1242  } else {
1243  return (this->order == SO_ASCENDING) ? res < 0 : res > 0;
1244  }
1245 }
1246 
1250 struct StationViewWindow : public Window {
1254  struct RowDisplay {
1255  RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {}
1256  RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {}
1257 
1262  union {
1266  StationID next_station;
1267 
1272  };
1273  };
1274 
1275  typedef std::vector<RowDisplay> CargoDataVector;
1276 
1277  static const int NUM_COLUMNS = 4;
1278 
1283  INV_FLOWS = 0x100,
1284  INV_CARGO = 0x200
1285  };
1286 
1290  enum Grouping {
1295  };
1296 
1300  enum Mode {
1302  MODE_PLANNED
1303  };
1304 
1308  Scrollbar *vscroll;
1309 
1312  ALH_RATING = 13,
1313  ALH_ACCEPTS = 3,
1314  };
1315 
1316  static const StringID _sort_names[];
1317  static const StringID _group_names[];
1318 
1325  CargoSortType sortings[NUM_COLUMNS];
1326 
1328  SortOrder sort_orders[NUM_COLUMNS];
1329 
1333  Grouping groupings[NUM_COLUMNS];
1334 
1337  CargoDataVector displayed_rows;
1338 
1339  StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc),
1340  scroll_to_row(INT_MAX), grouping_index(0)
1341  {
1342  this->rating_lines = ALH_RATING;
1343  this->accepts_lines = ALH_ACCEPTS;
1344 
1345  this->CreateNestedTree();
1346  this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
1347  /* Nested widget tree creation is done in two steps to ensure that this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */
1348  this->FinishInitNested(window_number);
1349 
1350  this->groupings[0] = GR_CARGO;
1351  this->sortings[0] = ST_AS_GROUPING;
1352  this->SelectGroupBy(_settings_client.gui.station_gui_group_order);
1353  this->SelectSortBy(_settings_client.gui.station_gui_sort_by);
1354  this->sort_orders[0] = SO_ASCENDING;
1355  this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order);
1356  this->owner = Station::Get(window_number)->owner;
1357  }
1358 
1360  {
1361  DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->window_number).Pack(), false);
1362  DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).Pack(), false);
1363  DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).Pack(), false);
1364  DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).Pack(), false);
1365 
1366  SetViewportCatchmentStation(Station::Get(this->window_number), false);
1367  }
1368 
1379  void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count)
1380  {
1381  if (count == 0) return;
1382  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1383  const CargoDataEntry *expand = &this->expanded_rows;
1384  for (int i = 0; i < NUM_COLUMNS && expand != nullptr; ++i) {
1385  switch (groupings[i]) {
1386  case GR_CARGO:
1387  assert(i == 0);
1388  data = data->InsertOrRetrieve(cargo);
1389  data->SetTransfers(source != this->window_number);
1390  expand = expand->Retrieve(cargo);
1391  break;
1392  case GR_SOURCE:
1393  if (auto_distributed || source != this->window_number) {
1394  data = data->InsertOrRetrieve(source);
1395  expand = expand->Retrieve(source);
1396  }
1397  break;
1398  case GR_NEXT:
1399  if (auto_distributed) {
1400  data = data->InsertOrRetrieve(next);
1401  expand = expand->Retrieve(next);
1402  }
1403  break;
1404  case GR_DESTINATION:
1405  if (auto_distributed) {
1406  data = data->InsertOrRetrieve(dest);
1407  expand = expand->Retrieve(dest);
1408  }
1409  break;
1410  }
1411  }
1412  data->Update(count);
1413  }
1414 
1415  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1416  {
1417  switch (widget) {
1418  case WID_SV_WAITING:
1419  resize->height = FONT_HEIGHT_NORMAL;
1420  size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM;
1421  this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
1422  break;
1423 
1425  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;
1426  break;
1427 
1428  case WID_SV_CLOSE_AIRPORT:
1429  if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) {
1430  /* Hide 'Close Airport' button if no airport present. */
1431  size->width = 0;
1432  resize->width = 0;
1433  fill->width = 0;
1434  }
1435  break;
1436  }
1437  }
1438 
1439  void OnPaint() override
1440  {
1441  const Station *st = Station::Get(this->window_number);
1443  BuildCargoList(&cargo, st);
1444 
1445  this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar
1446 
1447  /* disable some buttons */
1448  this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company);
1449  this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN));
1450  this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
1451  this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK));
1452  this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT));
1453  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
1454  this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0);
1455 
1456  extern const Station *_viewport_highlight_station;
1457  this->SetWidgetDisabledState(WID_SV_CATCHMENT, st->facilities == FACIL_NONE);
1458  this->SetWidgetLoweredState(WID_SV_CATCHMENT, _viewport_highlight_station == st);
1459 
1460  this->DrawWidgets();
1461 
1462  if (!this->IsShaded()) {
1463  /* Draw 'accepted cargo' or 'cargo ratings'. */
1464  const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SV_ACCEPT_RATING_LIST);
1465  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)};
1466  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1467  int lines = this->DrawAcceptedCargo(r);
1468  if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window.
1469  this->accepts_lines = lines;
1470  this->ReInit();
1471  return;
1472  }
1473  } else {
1474  int lines = this->DrawCargoRatings(r);
1475  if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window.
1476  this->rating_lines = lines;
1477  this->ReInit();
1478  return;
1479  }
1480  }
1481 
1482  /* Draw arrow pointing up/down for ascending/descending sorting */
1483  this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN);
1484 
1485  int pos = this->vscroll->GetPosition();
1486 
1487  int maxrows = this->vscroll->GetCapacity();
1488 
1489  displayed_rows.clear();
1490 
1491  /* Draw waiting cargo. */
1492  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SV_WAITING);
1493  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)};
1494  this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0);
1495  scroll_to_row = INT_MAX;
1496  }
1497  }
1498 
1499  void SetStringParameters(int widget) const override
1500  {
1501  const Station *st = Station::Get(this->window_number);
1502  SetDParam(0, st->index);
1503  SetDParam(1, st->facilities);
1504  }
1505 
1512  {
1513  const Station *st = Station::Get(this->window_number);
1514  CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i);
1515  cargo_entry->Clear();
1516 
1517  const FlowStatMap &flows = st->goods[i].flows;
1518  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1519  StationID from = it->first;
1520  CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from);
1521  const FlowStat::SharesMap *shares = it->second.GetShares();
1522  uint32 prev_count = 0;
1523  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1524  StationID via = flow_it->second;
1525  CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via);
1526  if (via == this->window_number) {
1527  via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count);
1528  } else {
1529  EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry);
1530  }
1531  prev_count = flow_it->first;
1532  }
1533  }
1534  }
1535 
1545  void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest)
1546  {
1547  if (Station::IsValidID(next) && Station::IsValidID(source)) {
1548  CargoDataEntry tmp;
1549  const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows;
1550  FlowStatMap::const_iterator map_it = flowmap.find(source);
1551  if (map_it != flowmap.end()) {
1552  const FlowStat::SharesMap *shares = map_it->second.GetShares();
1553  uint32 prev_count = 0;
1554  for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) {
1555  tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
1556  prev_count = i->first;
1557  }
1558  }
1559 
1560  if (tmp.GetCount() == 0) {
1561  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1562  } else {
1563  uint sum_estimated = 0;
1564  while (sum_estimated < count) {
1565  for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) {
1566  CargoDataEntry *child = *i;
1567  uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount());
1568  if (estimate == 0) estimate = 1;
1569 
1570  sum_estimated += estimate;
1571  if (sum_estimated > count) {
1572  estimate -= sum_estimated - count;
1573  sum_estimated = count;
1574  }
1575 
1576  if (estimate > 0) {
1577  if (child->GetStation() == next) {
1578  dest->InsertOrRetrieve(next)->Update(estimate);
1579  } else {
1580  EstimateDestinations(cargo, source, child->GetStation(), estimate, dest);
1581  }
1582  }
1583  }
1584 
1585  }
1586  }
1587  } else {
1588  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1589  }
1590  }
1591 
1599  {
1600  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1601  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1602  StationID from = it->first;
1603  const CargoDataEntry *source_entry = source_dest->Retrieve(from);
1604  const FlowStat::SharesMap *shares = it->second.GetShares();
1605  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1606  const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second);
1607  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1608  CargoDataEntry *dest_entry = *dest_it;
1609  ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount());
1610  }
1611  }
1612  }
1613  }
1614 
1622  {
1623  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1624  for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) {
1625  const CargoPacket *cp = *it;
1626  StationID next = it.GetKey();
1627 
1628  const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation());
1629  if (source_entry == nullptr) {
1630  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1631  continue;
1632  }
1633 
1634  const CargoDataEntry *via_entry = source_entry->Retrieve(next);
1635  if (via_entry == nullptr) {
1636  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1637  continue;
1638  }
1639 
1640  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1641  CargoDataEntry *dest_entry = *dest_it;
1642  uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount());
1643  this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val);
1644  }
1645  }
1646  this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount());
1647  }
1648 
1655  {
1656  for (CargoID i = 0; i < NUM_CARGO; i++) {
1657 
1658  if (this->cached_destinations.Retrieve(i) == nullptr) {
1659  this->RecalcDestinations(i);
1660  }
1661 
1662  if (this->current_mode == MODE_WAITING) {
1663  this->BuildCargoList(i, st->goods[i].cargo, cargo);
1664  } else {
1665  this->BuildFlowList(i, st->goods[i].flows, cargo);
1666  }
1667  }
1668  }
1669 
1675  {
1676  std::list<StationID> stations;
1677  const CargoDataEntry *parent = data->GetParent();
1678  if (parent->GetParent() == nullptr) {
1679  this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo()));
1680  return;
1681  }
1682 
1683  StationID next = data->GetStation();
1684  while (parent->GetParent()->GetParent() != nullptr) {
1685  stations.push_back(parent->GetStation());
1686  parent = parent->GetParent();
1687  }
1688 
1689  CargoID cargo = parent->GetCargo();
1690  CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo);
1691  while (!stations.empty()) {
1692  filter = filter->Retrieve(stations.back());
1693  stations.pop_back();
1694  }
1695 
1696  this->displayed_rows.push_back(RowDisplay(filter, next));
1697  }
1698 
1707  StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any)
1708  {
1709  if (station == this->window_number) {
1710  return here;
1711  } else if (station == INVALID_STATION) {
1712  return any;
1713  } else if (station == NEW_STATION) {
1714  return STR_STATION_VIEW_RESERVED;
1715  } else {
1716  SetDParam(2, station);
1717  return other_station;
1718  }
1719  }
1720 
1728  StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column)
1729  {
1730  CargoDataEntry *parent = cd->GetParent();
1731  for (int i = column - 1; i > 0; --i) {
1732  if (this->groupings[i] == GR_DESTINATION) {
1733  if (parent->GetStation() == station) {
1734  return STR_STATION_VIEW_NONSTOP;
1735  } else {
1736  return STR_STATION_VIEW_VIA;
1737  }
1738  }
1739  parent = parent->GetParent();
1740  }
1741 
1742  if (this->groupings[column + 1] == GR_DESTINATION) {
1743  CargoDataSet::iterator begin = cd->Begin();
1744  CargoDataSet::iterator end = cd->End();
1745  if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) {
1746  return STR_STATION_VIEW_NONSTOP;
1747  } else {
1748  return STR_STATION_VIEW_VIA;
1749  }
1750  }
1751 
1752  return STR_STATION_VIEW_VIA;
1753  }
1754 
1765  int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID)
1766  {
1767  if (this->sortings[column] == ST_AS_GROUPING) {
1768  if (this->groupings[column] != GR_CARGO) {
1769  entry->Resort(ST_STATION_STRING, this->sort_orders[column]);
1770  }
1771  } else {
1772  entry->Resort(ST_COUNT, this->sort_orders[column]);
1773  }
1774  for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) {
1775  CargoDataEntry *cd = *i;
1776 
1777  Grouping grouping = this->groupings[column];
1778  if (grouping == GR_CARGO) cargo = cd->GetCargo();
1779  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1780 
1781  if (pos > -maxrows && pos <= 0) {
1782  StringID str = STR_EMPTY;
1783  int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL;
1784  SetDParam(0, cargo);
1785  SetDParam(1, cd->GetCount());
1786 
1787  if (this->groupings[column] == GR_CARGO) {
1788  str = STR_STATION_VIEW_WAITING_CARGO;
1789  DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y);
1790  } else {
1791  if (!auto_distributed) grouping = GR_SOURCE;
1792  StationID station = cd->GetStation();
1793 
1794  switch (grouping) {
1795  case GR_SOURCE:
1796  str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY);
1797  break;
1798  case GR_NEXT:
1799  str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY);
1800  if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column);
1801  break;
1802  case GR_DESTINATION:
1803  str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY);
1804  break;
1805  default:
1806  NOT_REACHED();
1807  }
1808  if (pos == -this->scroll_to_row && Station::IsValidID(station)) {
1809  ScrollMainWindowToTile(Station::Get(station)->xy);
1810  }
1811  }
1812 
1813  bool rtl = _current_text_dir == TD_RTL;
1814  int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width;
1815  int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width;
1816  int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT;
1817  int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT;
1818 
1819  DrawString(text_left, text_right, y, str);
1820 
1821  if (column < NUM_COLUMNS - 1) {
1822  const char *sym = nullptr;
1823  if (cd->GetNumChildren() > 0) {
1824  sym = "-";
1825  } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) {
1826  sym = "+";
1827  } else {
1828  /* Only draw '+' if there is something to be shown. */
1829  const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo;
1830  if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) {
1831  sym = "+";
1832  }
1833  }
1834  if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW);
1835  }
1836  this->SetDisplayedRow(cd);
1837  }
1838  --pos;
1839  if (auto_distributed || column == 0) {
1840  pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo);
1841  }
1842  }
1843  return pos;
1844  }
1845 
1851  int DrawAcceptedCargo(const Rect &r) const
1852  {
1853  const Station *st = Station::Get(this->window_number);
1854 
1855  CargoTypes cargo_mask = 0;
1856  for (CargoID i = 0; i < NUM_CARGO; i++) {
1857  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i);
1858  }
1859  SetDParam(0, cargo_mask);
1860  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);
1861  return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1862  }
1863 
1869  int DrawCargoRatings(const Rect &r) const
1870  {
1871  const Station *st = Station::Get(this->window_number);
1872  int y = r.top + WD_FRAMERECT_TOP;
1873 
1874  if (st->town->exclusive_counter > 0) {
1875  SetDParam(0, st->town->exclusivity);
1876  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);
1877  y += WD_PAR_VSEP_WIDE;
1878  }
1879 
1880  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE);
1881  y += FONT_HEIGHT_NORMAL;
1882 
1883  const CargoSpec *cs;
1885  const GoodsEntry *ge = &st->goods[cs->Index()];
1886  if (!ge->HasRating()) continue;
1887 
1888  const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph);
1889  SetDParam(0, cs->name);
1890  SetDParam(1, lg != nullptr ? lg->Monthly((*lg)[ge->node].Supply()) : 0);
1891  SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5));
1892  SetDParam(3, ToPercent8(ge->rating));
1893  DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING);
1894  y += FONT_HEIGHT_NORMAL;
1895  }
1896  return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1897  }
1898 
1904  template<class Tid>
1905  void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
1906  {
1907  if (filter->Retrieve(next) != nullptr) {
1908  filter->Remove(next);
1909  } else {
1910  filter->InsertOrRetrieve(next);
1911  }
1912  }
1913 
1919  {
1920  if (row < 0 || (uint)row >= this->displayed_rows.size()) return;
1921  if (_ctrl_pressed) {
1922  this->scroll_to_row = row;
1923  } else {
1924  RowDisplay &display = this->displayed_rows[row];
1925  if (display.filter == &this->expanded_rows) {
1926  this->HandleCargoWaitingClick<CargoID>(display.filter, display.next_cargo);
1927  } else {
1928  this->HandleCargoWaitingClick<StationID>(display.filter, display.next_station);
1929  }
1930  }
1931  this->SetWidgetDirty(WID_SV_WAITING);
1932  }
1933 
1934  void OnClick(Point pt, int widget, int click_count) override
1935  {
1936  switch (widget) {
1937  case WID_SV_WAITING:
1938  this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition());
1939  break;
1940 
1941  case WID_SV_CATCHMENT:
1942  SetViewportCatchmentStation(Station::Get(this->window_number), !this->IsWidgetLowered(WID_SV_CATCHMENT));
1943  break;
1944 
1945  case WID_SV_LOCATION:
1946  if (_ctrl_pressed) {
1947  ShowExtraViewPortWindow(Station::Get(this->window_number)->xy);
1948  } else {
1949  ScrollMainWindowToTile(Station::Get(this->window_number)->xy);
1950  }
1951  break;
1952 
1953  case WID_SV_ACCEPTS_RATINGS: {
1954  /* Swap between 'accepts' and 'ratings' view. */
1955  int height_change;
1956  NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS);
1957  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1958  nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view.
1959  height_change = this->rating_lines - this->accepts_lines;
1960  } else {
1961  nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view.
1962  height_change = this->accepts_lines - this->rating_lines;
1963  }
1964  this->ReInit(0, height_change * FONT_HEIGHT_NORMAL);
1965  break;
1966  }
1967 
1968  case WID_SV_RENAME:
1969  SetDParam(0, this->window_number);
1970  ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
1972  break;
1973 
1974  case WID_SV_CLOSE_AIRPORT:
1975  DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT);
1976  break;
1977 
1978  case WID_SV_TRAINS: // Show list of scheduled trains to this station
1979  case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station
1980  case WID_SV_SHIPS: // Show list of scheduled ships to this station
1981  case WID_SV_PLANES: { // Show list of scheduled aircraft to this station
1982  Owner owner = Station::Get(this->window_number)->owner;
1983  ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number);
1984  break;
1985  }
1986 
1987  case WID_SV_SORT_BY: {
1988  /* The initial selection is composed of current mode and
1989  * sorting criteria for columns 1, 2, and 3. Column 0 is always
1990  * sorted by cargo ID. The others can theoretically be sorted
1991  * by different things but there is no UI for that. */
1992  ShowDropDownMenu(this, _sort_names,
1993  this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0),
1994  WID_SV_SORT_BY, 0, 0);
1995  break;
1996  }
1997 
1998  case WID_SV_GROUP_BY: {
1999  ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
2000  break;
2001  }
2002 
2003  case WID_SV_SORT_ORDER: { // flip sorting method asc/desc
2004  this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING);
2005  this->SetTimeout();
2006  this->LowerWidget(WID_SV_SORT_ORDER);
2007  break;
2008  }
2009  }
2010  }
2011 
2016  void SelectSortOrder(SortOrder order)
2017  {
2018  this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order;
2019  _settings_client.gui.station_gui_sort_order = this->sort_orders[1];
2020  this->SetDirty();
2021  }
2022 
2027  void SelectSortBy(int index)
2028  {
2030  switch (_sort_names[index]) {
2031  case STR_STATION_VIEW_WAITING_STATION:
2032  this->current_mode = MODE_WAITING;
2033  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
2034  break;
2035  case STR_STATION_VIEW_WAITING_AMOUNT:
2036  this->current_mode = MODE_WAITING;
2037  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
2038  break;
2039  case STR_STATION_VIEW_PLANNED_STATION:
2040  this->current_mode = MODE_PLANNED;
2041  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
2042  break;
2043  case STR_STATION_VIEW_PLANNED_AMOUNT:
2044  this->current_mode = MODE_PLANNED;
2045  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
2046  break;
2047  default:
2048  NOT_REACHED();
2049  }
2050  /* Display the current sort variant */
2051  this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->widget_data = _sort_names[index];
2052  this->SetDirty();
2053  }
2054 
2059  void SelectGroupBy(int index)
2060  {
2061  this->grouping_index = index;
2063  this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->widget_data = _group_names[index];
2064  switch (_group_names[index]) {
2065  case STR_STATION_VIEW_GROUP_S_V_D:
2066  this->groupings[1] = GR_SOURCE;
2067  this->groupings[2] = GR_NEXT;
2068  this->groupings[3] = GR_DESTINATION;
2069  break;
2070  case STR_STATION_VIEW_GROUP_S_D_V:
2071  this->groupings[1] = GR_SOURCE;
2072  this->groupings[2] = GR_DESTINATION;
2073  this->groupings[3] = GR_NEXT;
2074  break;
2075  case STR_STATION_VIEW_GROUP_V_S_D:
2076  this->groupings[1] = GR_NEXT;
2077  this->groupings[2] = GR_SOURCE;
2078  this->groupings[3] = GR_DESTINATION;
2079  break;
2080  case STR_STATION_VIEW_GROUP_V_D_S:
2081  this->groupings[1] = GR_NEXT;
2082  this->groupings[2] = GR_DESTINATION;
2083  this->groupings[3] = GR_SOURCE;
2084  break;
2085  case STR_STATION_VIEW_GROUP_D_S_V:
2086  this->groupings[1] = GR_DESTINATION;
2087  this->groupings[2] = GR_SOURCE;
2088  this->groupings[3] = GR_NEXT;
2089  break;
2090  case STR_STATION_VIEW_GROUP_D_V_S:
2091  this->groupings[1] = GR_DESTINATION;
2092  this->groupings[2] = GR_NEXT;
2093  this->groupings[3] = GR_SOURCE;
2094  break;
2095  }
2096  this->SetDirty();
2097  }
2098 
2099  void OnDropdownSelect(int widget, int index) override
2100  {
2101  if (widget == WID_SV_SORT_BY) {
2102  this->SelectSortBy(index);
2103  } else {
2104  this->SelectGroupBy(index);
2105  }
2106  }
2107 
2108  void OnQueryTextFinished(char *str) override
2109  {
2110  if (str == nullptr) return;
2111 
2112  DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), nullptr, str);
2113  }
2114 
2115  void OnResize() override
2116  {
2118  }
2119 
2125  void OnInvalidateData(int data = 0, bool gui_scope = true) override
2126  {
2127  if (gui_scope) {
2128  if (data >= 0 && data < NUM_CARGO) {
2129  this->cached_destinations.Remove((CargoID)data);
2130  } else {
2131  this->ReInit();
2132  }
2133  }
2134  }
2135 };
2136 
2138  STR_STATION_VIEW_WAITING_STATION,
2139  STR_STATION_VIEW_WAITING_AMOUNT,
2140  STR_STATION_VIEW_PLANNED_STATION,
2141  STR_STATION_VIEW_PLANNED_AMOUNT,
2143 };
2144 
2146  STR_STATION_VIEW_GROUP_S_V_D,
2147  STR_STATION_VIEW_GROUP_S_D_V,
2148  STR_STATION_VIEW_GROUP_V_S_D,
2149  STR_STATION_VIEW_GROUP_V_D_S,
2150  STR_STATION_VIEW_GROUP_D_S_V,
2151  STR_STATION_VIEW_GROUP_D_V_S,
2153 };
2154 
2155 static WindowDesc _station_view_desc(
2156  WDP_AUTO, "view_station", 249, 117,
2158  0,
2159  _nested_station_view_widgets, lengthof(_nested_station_view_widgets)
2160 );
2161 
2168 {
2169  AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
2170 }
2171 
2175  StationID station;
2176 };
2177 
2178 static std::vector<TileAndStation> _deleted_stations_nearby;
2179 static std::vector<StationID> _stations_nearby_list;
2180 
2188 template <class T>
2189 static bool AddNearbyStation(TileIndex tile, void *user_data)
2190 {
2191  TileArea *ctx = (TileArea *)user_data;
2192 
2193  /* First check if there were deleted stations here */
2194  for (uint i = 0; i < _deleted_stations_nearby.size(); i++) {
2195  auto ts = _deleted_stations_nearby.begin() + i;
2196  if (ts->tile == tile) {
2197  _stations_nearby_list.push_back(_deleted_stations_nearby[i].station);
2198  _deleted_stations_nearby.erase(ts);
2199  i--;
2200  }
2201  }
2202 
2203  /* Check if own station and if we stay within station spread */
2204  if (!IsTileType(tile, MP_STATION)) return false;
2205 
2206  StationID sid = GetStationIndex(tile);
2207 
2208  /* This station is (likely) a waypoint */
2209  if (!T::IsValidID(sid)) return false;
2210 
2211  T *st = T::Get(sid);
2212  if (st->owner != _local_company || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false;
2213 
2214  if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
2215  _stations_nearby_list.push_back(sid);
2216  }
2217 
2218  return false; // We want to include *all* nearby stations
2219 }
2220 
2230 template <class T>
2231 static const T *FindStationsNearby(TileArea ta, bool distant_join)
2232 {
2233  TileArea ctx = ta;
2234 
2235  _stations_nearby_list.clear();
2236  _deleted_stations_nearby.clear();
2237 
2238  /* Check the inside, to return, if we sit on another station */
2239  TILE_AREA_LOOP(t, ta) {
2240  if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
2241  }
2242 
2243  /* Look for deleted stations */
2244  for (const BaseStation *st : BaseStation::Iterate()) {
2245  if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
2246  /* Include only within station spread (yes, it is strictly less than) */
2247  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) {
2248  _deleted_stations_nearby.push_back({st->xy, st->index});
2249 
2250  /* Add the station when it's within where we're going to build */
2251  if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
2252  IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
2253  AddNearbyStation<T>(st->xy, &ctx);
2254  }
2255  }
2256  }
2257  }
2258 
2259  /* Only search tiles where we have a chance to stay within the station spread.
2260  * The complete check needs to be done in the callback as we don't know the
2261  * extent of the found station, yet. */
2262  if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return nullptr;
2263  uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1;
2264 
2265  TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
2266  CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
2267 
2268  return nullptr;
2269 }
2270 
2271 static const NWidgetPart _nested_select_station_widgets[] = {
2273  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
2274  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2275  NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
2276  EndContainer(),
2278  NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(),
2280  NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR),
2281  NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
2282  EndContainer(),
2283  EndContainer(),
2284 };
2285 
2290 template <class T>
2294  Scrollbar *vscroll;
2295 
2296  SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) :
2297  Window(desc),
2298  select_station_cmd(cmd),
2299  area(ta)
2300  {
2301  this->CreateNestedTree();
2302  this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
2303  this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
2304  this->FinishInitNested(0);
2305  this->OnInvalidateData(0);
2306 
2307  _thd.freeze = true;
2308  }
2309 
2311  {
2313 
2314  _thd.freeze = false;
2315  }
2316 
2317  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2318  {
2319  if (widget != WID_JS_PANEL) return;
2320 
2321  /* Determine the widest string */
2322  Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
2323  for (uint i = 0; i < _stations_nearby_list.size(); i++) {
2324  const T *st = T::Get(_stations_nearby_list[i]);
2325  SetDParam(0, st->index);
2326  SetDParam(1, st->facilities);
2327  d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION));
2328  }
2329 
2330  resize->height = d.height;
2331  d.height *= 5;
2333  d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2334  *size = d;
2335  }
2336 
2337  void DrawWidget(const Rect &r, int widget) const override
2338  {
2339  if (widget != WID_JS_PANEL) return;
2340 
2341  uint y = r.top + WD_FRAMERECT_TOP;
2342  if (this->vscroll->GetPosition() == 0) {
2343  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);
2344  y += this->resize.step_height;
2345  }
2346 
2347  for (uint i = max<uint>(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.size(); ++i, y += this->resize.step_height) {
2348  /* Don't draw anything if it extends past the end of the window. */
2349  if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break;
2350 
2351  const T *st = T::Get(_stations_nearby_list[i - 1]);
2352  SetDParam(0, st->index);
2353  SetDParam(1, st->facilities);
2354  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);
2355  }
2356  }
2357 
2358  void OnClick(Point pt, int widget, int click_count) override
2359  {
2360  if (widget != WID_JS_PANEL) return;
2361 
2362  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2363  bool distant_join = (st_index > 0);
2364  if (distant_join) st_index--;
2365 
2366  if (distant_join && st_index >= _stations_nearby_list.size()) return;
2367 
2368  /* Insert station to be joined into stored command */
2369  SB(this->select_station_cmd.p2, 16, 16,
2370  (distant_join ? _stations_nearby_list[st_index] : NEW_STATION));
2371 
2372  /* Execute stored Command */
2373  DoCommandP(&this->select_station_cmd);
2374 
2375  /* Close Window; this might cause double frees! */
2377  }
2378 
2379  void OnRealtimeTick(uint delta_ms) override
2380  {
2381  if (_thd.dirty & 2) {
2382  _thd.dirty &= ~2;
2383  this->SetDirty();
2384  }
2385  }
2386 
2387  void OnResize() override
2388  {
2389  this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
2390  }
2391 
2397  void OnInvalidateData(int data = 0, bool gui_scope = true) override
2398  {
2399  if (!gui_scope) return;
2400  FindStationsNearby<T>(this->area, true);
2401  this->vscroll->SetCount((uint)_stations_nearby_list.size() + 1);
2402  this->SetDirty();
2403  }
2404 
2405  void OnMouseOver(Point pt, int widget) override
2406  {
2407  if (widget != WID_JS_PANEL || T::EXPECTED_FACIL == FACIL_WAYPOINT) {
2408  SetViewportCatchmentStation(nullptr, true);
2409  return;
2410  }
2411 
2412  /* Show coverage area of station under cursor */
2413  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2414  if (st_index == 0 || st_index > _stations_nearby_list.size()) {
2415  SetViewportCatchmentStation(nullptr, true);
2416  } else {
2417  st_index--;
2418  SetViewportCatchmentStation(Station::Get(_stations_nearby_list[st_index]), true);
2419  }
2420  }
2421 };
2422 
2423 static WindowDesc _select_station_desc(
2424  WDP_AUTO, "build_station_join", 200, 180,
2427  _nested_select_station_widgets, lengthof(_nested_select_station_widgets)
2428 );
2429 
2430 
2438 template <class T>
2439 static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta)
2440 {
2441  /* Only show selection if distant join is enabled in the settings */
2442  if (!_settings_game.station.distant_join_stations) return false;
2443 
2444  /* If a window is already opened and we didn't ctrl-click,
2445  * return true (i.e. just flash the old window) */
2446  Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
2447  if (selection_window != nullptr) {
2448  /* Abort current distant-join and start new one */
2449  delete selection_window;
2451  }
2452 
2453  /* only show the popup, if we press ctrl */
2454  if (!_ctrl_pressed) return false;
2455 
2456  /* Now check if we could build there */
2457  if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false;
2458 
2459  /* Test for adjacent station or station below selection.
2460  * If adjacent-stations is disabled and we are building next to a station, do not show the selection window.
2461  * but join the other station immediately. */
2462  const T *st = FindStationsNearby<T>(ta, false);
2463  return st == nullptr && (_settings_game.station.adjacent_stations || _stations_nearby_list.size() == 0);
2464 }
2465 
2472 template <class T>
2474 {
2475  if (StationJoinerNeeded<T>(cmd, ta)) {
2477  new SelectStationWindow<T>(&_select_station_desc, cmd, ta);
2478  } else {
2479  DoCommandP(&cmd);
2480  }
2481 }
2482 
2489 {
2490  ShowSelectBaseStationIfNeeded<Station>(cmd, ta);
2491 }
2492 
2499 {
2500  ShowSelectBaseStationIfNeeded<Waypoint>(cmd, ta);
2501 }
&#39;Location&#39; button.
Functions related to OTTD&#39;s strings.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
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:22
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:79
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:302
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:68
Select station (when joining stations); Window numbers:
Definition: window_type.h:235
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:133
Horizontally center the text.
Definition: gfx_func.h:95
The information about a vehicle list.
Definition: vehiclelist.h:29
ResizeInfo resize
Resize information.
Definition: window_gui.h:322
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition: cargotype.cpp:29
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:928
Window(WindowDesc *desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1867
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:110
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:1144
&#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:453
open/close an airport to incoming aircraft
Definition: command_type.h:332
Window * parent
Parent window.
Definition: window_gui.h:337
High level window description.
Definition: window_gui.h:166
void SetMinimalSize(uint min_x, uint min_y)
Set minimal size of the widget.
Definition: widget.cpp:815
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:317
Train vehicle type.
Definition: vehicle_type.h:24
CargoList that is used for stations.
Definition: cargopacket.h:448
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:602
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:587
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:62
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:597
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:62
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:20
Horizontal container.
Definition: widget_type.h:73
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:1130
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:1119
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:76
Ship vehicle type.
Definition: vehicle_type.h:26
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:64
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:55
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
&#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:66
uint32 p2
parameter p2.
Definition: command_type.h:478
The station has no facilities at all.
Definition: station_type.h:51
uint TotalCount() const
Returns total count of cargo at the station, including cargo which is already reserved for loading...
Definition: cargopacket.h:526
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:205
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:57
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:463
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:170
TileIndex tile
TileIndex.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:189
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:101
Manual distribution. No link graph calculations are run.
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition: viewport.cpp:2483
Close box (at top-left of a window)
Definition: widget_type.h:67
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:74
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:48
Invalidation
Type of data invalidation.
CargoDataEntry * parent
the parent of this entry.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
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:384
StationCargoList cargo
The cargo packets of cargo waiting in this station.
Definition: station_base.h:255
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
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:273
void RaiseWidget(byte widget_index)
Marks a widget as raised.
Definition: window_gui.h:483
uint16 w
The width of the area.
Definition: tilearea_type.h:18
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:1828
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:138
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:479
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:13
StringID name
Name of this type of cargo.
Definition: cargotype.h:70
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:248
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:668
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:908
Functions related to (drawing on) viewports.
void ForceRebuild()
Force that a rebuild is needed.
A connected component of a link graph.
Definition: linkgraph.h:38
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:276
Invalid cargo type.
Definition: cargo_type.h:68
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:35
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1844
CargoDataSet * children
the children of this entry.
static const uint8 PC_GREEN
Green palette colour.
Definition: gfx_func.h:220
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:21
void Add(NWidgetBase *wid)
Append widget wid to container.
Definition: widget.cpp:942
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:235
The tile has no ownership.
Definition: company_type.h:25
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:150
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:54
Scrollbar next to the main panel.
#define FONT_HEIGHT_SMALL
Height of characters in the small (FS_SMALL) font.
Definition: gfx_func.h:173
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:441
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) ...
Definition: widget_type.h:63
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:1957
LinkGraphID link_graph
Link graph this station belongs to.
Definition: station_base.h:257
Group by next station ("via").
This window is used for construction; close it whenever changing company.
Definition: window_gui.h:208
bool IsWidgetLowered(byte widget_index) const
Gets the lowered state of a widget.
Definition: window_gui.h:493
void SetDataTip(uint32 widget_data, StringID tool_tip)
Set data and tool tip of the nested widget.
Definition: widget.cpp:892
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:173
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:189
Sort descending.
Definition: window_gui.h:225
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:178
Structure for buffering the build command when selecting a station to join.
Definition: command_type.h:475
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:176
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1012
void SetFill(uint fill_x, uint fill_y)
Set the filling of the widget from initial size.
Definition: widget.cpp:837
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:78
byte status
Status of this cargo, see GoodsEntryStatus.
Definition: station_base.h:226
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:945
&#39;Close airport&#39; button.
Container for cargo from the same location and time.
Definition: cargopacket.h:42
StationCoverageType
Types of cargo to display for station coverage.
Definition: station_gui.h:19
#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:158
the length of the string is counted in characters
Definition: textbuf_gui.h:22
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:258
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:516
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:245
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:258
static const uint64 AIRPORT_CLOSED_block
Dummy block for indicating a closed airport.
Definition: airport.h:128
bool HasTransfers() const
Has this entry transfers.
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:102
Base of waypoints.
Geometry functions.
rectangle (stations, depots, ...)
Simple depressed panel.
Definition: widget_type.h:48
static uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition: math_func.hpp:314
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:258
void DrawSortButtonState(int widget, SortButtonState state) const
Draw a sort button&#39;s up or down arrow symbol.
Definition: widget.cpp:636
const Scrollbar * GetScrollbar(uint widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:309
Represents the covered area of e.g.
Definition: tilearea_type.h:16
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:175
void LowerWidget(byte widget_index)
Marks a widget as lowered.
Definition: window_gui.h:474
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:3454
static void FindStationsAroundSelection()
Find stations adjacent to the current tile highlight area, so that existing coverage area can be draw...
Definition: station_gui.cpp:85
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:307
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:1112
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:63
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:58
Baseclass for nested widgets.
Definition: widget_type.h:124
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:338
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:498
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:308
bool DoCommandP(const CommandContainer *container, bool my_cmd)
Shortcut for the long DoCommandP when having a container with the data.
Definition: command.cpp:532
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:40
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:40
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:171
static bool IsCargoInClass(CargoID c, CargoClass cc)
Does cargo c have cargo class cc?
Definition: cargotype.h:148
Horizontal container.
Definition: widget_type.h:452
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:656
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
bool Failed() const
Did this command fail?
Definition: command_type.h:159
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:516
by station name
Station list; Window numbers:
Definition: window_type.h:295
by the same principle the entries are being grouped
FlowStatMap flows
Planned flows through this station.
Definition: station_base.h:259
&#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:984
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:35
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:700
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:17
uint16 GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:611
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:38
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1162
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:55
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:848
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:134
Station with a dock.
Definition: station_type.h:56
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:28
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:194
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:92
Mode current_mode
Currently selected display mode of cargo view.
Class for storing amounts of cargo.
Definition: cargo_type.h:81
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:27
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition: cargotype.cpp:120
GUISettings gui
settings related to the GUI
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:340
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:59
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:578
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:17
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:117
StationCargoPacketMap ::const_iterator ConstIterator
The const iterator for our container.
Definition: cargopacket.h:207
Ships list; Window numbers:
Definition: window_type.h:313
TextColour GetContrastColour(uint8 background, uint8 threshold)
Determine a contrasty text colour for a coloured background.
Definition: gfx.cpp:1119
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:78
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Draw all non-passenger class cargoes.
Definition: station_gui.h:21
static uint ToPercent8(uint i)
Converts a "fract" value 0..255 to "percent" value 0..100.
Definition: math_func.hpp:287
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:48
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:224
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:215
CargoDataEntry * Retrieve(CargoID cargo) const
Retrieve a child for the given cargo.
Station is a waypoint.
Definition: station_type.h:57
Vertical container.
Definition: widget_type.h:75
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:988
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:997
static const uint8 PC_RED
Red palette colour.
Definition: gfx_func.h:210
Trains list; Window numbers:
Definition: window_type.h:301
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:172
A tile of a station.
Definition: tile_type.h:46
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:111
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:74
StationID GetStation() const
Get the station ID for this entry.
Aircraft list; Window numbers:
Definition: window_type.h:319
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2396
&#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:88
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:280
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:31
Drop down list.
Definition: widget_type.h:68
bool freeze
Freeze highlight in place.
rename a station
Definition: command_type.h:246
uint16 GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:620
Index of the small font in the font tables.
Definition: gfx_type.h:203
bool adjacent_stations
allow stations to be built directly adjacent to other stations
Flow descriptions by origin stations.
Definition: station_base.h:152
Station with bus stops.
Definition: station_type.h:54
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:17
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable...
Definition: window_gui.h:324
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:370
Aircraft vehicle type.
Definition: vehicle_type.h:27
static const StringID _sort_names[]
Names of the sorting options in the dropdown.
Airport airport
Tile area the airport covers.
Definition: station_base.h:464
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:61
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:87
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:64
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:319
StationID station
ID of the station this entry is associated with.
Passengers.
Definition: cargotype.h:39
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Definition: cargopacket.h:246
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:981
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:98
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:83
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:53
Caption of the window.
#define CMD_MSG(x)
Used to combine a StringID with the command.
Definition: command_type.h:368
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:99
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:705
&#39;Accepts&#39; / &#39;Ratings&#39; button.
uint AvailableCount() const
Returns sum of cargo still available for loading at the sation.
Definition: cargopacket.h:507
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:1971
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows)...
Definition: viewport.cpp:3353
Specification of a rectangle with absolute coordinates of all edges.
Vertical scrollbar.
Definition: widget_type.h:82
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:20
Text is written right-to-left by default.
Definition: strings_type.h:24
static uint MapMaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition: map_func.h:102
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:312
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:52
Find a place automatically.
Definition: window_gui.h:154
&#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:49
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:19
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:73
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1093
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
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:427
int grouping_index
Currently selected entry in the grouping drop down.
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:60
Struct containing TileIndex and StationID.
Base class for all station-ish types.
Station data structure.
Definition: station_base.h:450
Nested widget with a child.
Definition: widget_type.h:543
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:62
uint32 cmd
command being executed.
Definition: command_type.h:479
LinkGraphSettings linkgraph
settings for link graph calculations
Road vehicle type.
Definition: vehicle_type.h:25
Set when the station accepts the cargo currently for final deliveries.
Definition: station_base.h:177
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:163
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:835
int pos_y
Vertical position of top-left corner of the widget in the window.
Definition: widget_type.h:176
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:621
(Toggle) Button with text
Definition: widget_type.h:53
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:629
uint8 SortType() const
Get the sorttype of the list.
Definition: sortlist_type.h:94
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:199
Base class for a &#39;real&#39; widget.
Definition: widget_type.h:282