OpenTTD Source  1.10.0-RC1
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 
211  /* Constants for sorting stations */
212  static const StringID sorter_names[];
213  static GUIStationList::SortFunction * const sorter_funcs[];
214 
215  GUIStationList stations;
216  Scrollbar *vscroll;
217 
224  {
225  if (!this->stations.NeedRebuild()) return;
226 
227  DEBUG(misc, 3, "Building station list for company %d", owner);
228 
229  this->stations.clear();
230 
231  for (const Station *st : Station::Iterate()) {
232  if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
233  if (this->facilities & st->facilities) { // only stations with selected facilities
234  int num_waiting_cargo = 0;
235  for (CargoID j = 0; j < NUM_CARGO; j++) {
236  if (st->goods[j].HasRating()) {
237  num_waiting_cargo++; // count number of waiting cargo
238  if (HasBit(this->cargo_filter, j)) {
239  this->stations.push_back(st);
240  break;
241  }
242  }
243  }
244  /* stations without waiting cargo */
245  if (num_waiting_cargo == 0 && this->include_empty) {
246  this->stations.push_back(st);
247  }
248  }
249  }
250  }
251 
252  this->stations.shrink_to_fit();
253  this->stations.RebuildDone();
254 
255  this->vscroll->SetCount((uint)this->stations.size()); // Update the scrollbar
256  }
257 
259  static bool StationNameSorter(const Station * const &a, const Station * const &b)
260  {
261  int r = strnatcmp(a->GetCachedName(), b->GetCachedName()); // Sort by name (natural sorting).
262  if (r == 0) return a->index < b->index;
263  return r < 0;
264  }
265 
267  static bool StationTypeSorter(const Station * const &a, const Station * const &b)
268  {
269  return a->facilities < b->facilities;
270  }
271 
273  static bool StationWaitingTotalSorter(const Station * const &a, const Station * const &b)
274  {
275  int diff = 0;
276 
277  CargoID j;
278  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
279  diff += a->goods[j].cargo.TotalCount() - b->goods[j].cargo.TotalCount();
280  }
281 
282  return diff < 0;
283  }
284 
286  static bool StationWaitingAvailableSorter(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.AvailableCount() - b->goods[j].cargo.AvailableCount();
293  }
294 
295  return diff < 0;
296  }
297 
299  static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b)
300  {
301  byte maxr1 = 0;
302  byte maxr2 = 0;
303 
304  CargoID j;
305  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
306  if (a->goods[j].HasRating()) maxr1 = max(maxr1, a->goods[j].rating);
307  if (b->goods[j].HasRating()) maxr2 = max(maxr2, b->goods[j].rating);
308  }
309 
310  return maxr1 < maxr2;
311  }
312 
314  static bool StationRatingMinSorter(const Station * const &a, const Station * const &b)
315  {
316  byte minr1 = 255;
317  byte minr2 = 255;
318 
319  for (CargoID j = 0; j < NUM_CARGO; j++) {
320  if (!HasBit(cargo_filter, j)) continue;
321  if (a->goods[j].HasRating()) minr1 = min(minr1, a->goods[j].rating);
322  if (b->goods[j].HasRating()) minr2 = min(minr2, b->goods[j].rating);
323  }
324 
325  return minr1 > minr2;
326  }
327 
330  {
331  if (!this->stations.Sort()) return;
332 
333  /* Set the modified widget dirty */
335  }
336 
337 public:
339  {
340  this->stations.SetListing(this->last_sorting);
341  this->stations.SetSortFuncs(this->sorter_funcs);
342  this->stations.ForceRebuild();
343  this->stations.NeedResort();
344  this->SortStationsList();
345 
346  this->CreateNestedTree();
347  this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR);
348  this->FinishInitNested(window_number);
349  this->owner = (Owner)this->window_number;
350 
351  const CargoSpec *cs;
353  if (!HasBit(this->cargo_filter, cs->Index())) continue;
354  this->LowerWidget(WID_STL_CARGOSTART + index);
355  }
356 
357  if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask;
358 
359  for (uint i = 0; i < 5; i++) {
360  if (HasBit(this->facilities, i)) this->LowerWidget(i + WID_STL_TRAIN);
361  }
362  this->SetWidgetLoweredState(WID_STL_NOCARGOWAITING, this->include_empty);
363 
364  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
365  }
366 
368  {
369  this->last_sorting = this->stations.GetListing();
370  }
371 
372  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
373  {
374  switch (widget) {
375  case WID_STL_SORTBY: {
376  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
377  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
378  d.height += padding.height;
379  *size = maxdim(*size, d);
380  break;
381  }
382 
383  case WID_STL_SORTDROPBTN: {
384  Dimension d = {0, 0};
385  for (int i = 0; this->sorter_names[i] != INVALID_STRING_ID; i++) {
386  d = maxdim(d, GetStringBoundingBox(this->sorter_names[i]));
387  }
388  d.width += padding.width;
389  d.height += padding.height;
390  *size = maxdim(*size, d);
391  break;
392  }
393 
394  case WID_STL_LIST:
395  resize->height = FONT_HEIGHT_NORMAL;
396  size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM;
397  break;
398 
399  case WID_STL_TRAIN:
400  case WID_STL_TRUCK:
401  case WID_STL_BUS:
402  case WID_STL_AIRPLANE:
403  case WID_STL_SHIP:
404  size->height = max<uint>(FONT_HEIGHT_SMALL, 10) + padding.height;
405  break;
406 
407  case WID_STL_CARGOALL:
408  case WID_STL_FACILALL:
409  case WID_STL_NOCARGOWAITING: {
410  Dimension d = GetStringBoundingBox(widget == WID_STL_NOCARGOWAITING ? STR_ABBREV_NONE : STR_ABBREV_ALL);
411  d.width += padding.width + 2;
412  d.height += padding.height;
413  *size = maxdim(*size, d);
414  break;
415  }
416 
417  default:
418  if (widget >= WID_STL_CARGOSTART) {
420  d.width += padding.width + 2;
421  d.height += padding.height;
422  *size = maxdim(*size, d);
423  }
424  break;
425  }
426  }
427 
428  void OnPaint() override
429  {
430  this->BuildStationsList((Owner)this->window_number);
431  this->SortStationsList();
432 
433  this->DrawWidgets();
434  }
435 
436  void DrawWidget(const Rect &r, int widget) const override
437  {
438  switch (widget) {
439  case WID_STL_SORTBY:
440  /* draw arrow pointing up/down for ascending/descending sorting */
442  break;
443 
444  case WID_STL_LIST: {
445  bool rtl = _current_text_dir == TD_RTL;
446  int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->stations.size());
447  int y = r.top + WD_FRAMERECT_TOP;
448  for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner
449  const Station *st = this->stations[i];
450  assert(st->xy != INVALID_TILE);
451 
452  /* Do not do the complex check HasStationInUse here, it may be even false
453  * when the order had been removed and the station list hasn't been removed yet */
454  assert(st->owner == owner || st->owner == OWNER_NONE);
455 
456  SetDParam(0, st->index);
457  SetDParam(1, st->facilities);
458  int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION);
459  x += rtl ? -5 : 5;
460 
461  /* show cargo waiting and station ratings */
462  for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) {
463  CargoID cid = _sorted_cargo_specs[j]->Index();
464  if (st->goods[cid].cargo.TotalCount() > 0) {
465  /* For RTL we work in exactly the opposite direction. So
466  * decrement the space needed first, then draw to the left
467  * instead of drawing to the left and then incrementing
468  * the space. */
469  if (rtl) {
470  x -= 20;
471  if (x < r.left + WD_FRAMERECT_LEFT) break;
472  }
473  StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating);
474  if (!rtl) {
475  x += 20;
476  if (x > r.right - WD_FRAMERECT_RIGHT) break;
477  }
478  }
479  }
480  y += FONT_HEIGHT_NORMAL;
481  }
482 
483  if (this->vscroll->GetCount() == 0) { // company has no stations
484  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_NONE);
485  return;
486  }
487  break;
488  }
489 
490  case WID_STL_NOCARGOWAITING: {
491  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
492  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER);
493  break;
494  }
495 
496  case WID_STL_CARGOALL: {
497  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
498  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
499  break;
500  }
501 
502  case WID_STL_FACILALL: {
503  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
504  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
505  break;
506  }
507 
508  default:
509  if (widget >= WID_STL_CARGOSTART) {
510  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
511  int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1;
512  GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour);
513  TextColour tc = GetContrastColour(cs->rating_colour);
514  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER);
515  }
516  break;
517  }
518  }
519 
520  void SetStringParameters(int widget) const override
521  {
522  if (widget == WID_STL_CAPTION) {
523  SetDParam(0, this->window_number);
524  SetDParam(1, this->vscroll->GetCount());
525  }
526  }
527 
528  void OnClick(Point pt, int widget, int click_count) override
529  {
530  switch (widget) {
531  case WID_STL_LIST: {
532  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL);
533  if (id_v >= this->stations.size()) return; // click out of list bound
534 
535  const Station *st = this->stations[id_v];
536  /* do not check HasStationInUse - it is slow and may be invalid */
537  assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE);
538 
539  if (_ctrl_pressed) {
541  } else {
543  }
544  break;
545  }
546 
547  case WID_STL_TRAIN:
548  case WID_STL_TRUCK:
549  case WID_STL_BUS:
550  case WID_STL_AIRPLANE:
551  case WID_STL_SHIP:
552  if (_ctrl_pressed) {
553  ToggleBit(this->facilities, widget - WID_STL_TRAIN);
554  this->ToggleWidgetLoweredState(widget);
555  } else {
556  uint i;
557  FOR_EACH_SET_BIT(i, this->facilities) {
558  this->RaiseWidget(i + WID_STL_TRAIN);
559  }
560  this->facilities = 1 << (widget - WID_STL_TRAIN);
561  this->LowerWidget(widget);
562  }
563  this->stations.ForceRebuild();
564  this->SetDirty();
565  break;
566 
567  case WID_STL_FACILALL:
568  for (uint i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) {
569  this->LowerWidget(i);
570  }
571 
573  this->stations.ForceRebuild();
574  this->SetDirty();
575  break;
576 
577  case WID_STL_CARGOALL: {
578  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
579  this->LowerWidget(WID_STL_CARGOSTART + i);
580  }
582 
583  this->cargo_filter = _cargo_mask;
584  this->include_empty = true;
585  this->stations.ForceRebuild();
586  this->SetDirty();
587  break;
588  }
589 
590  case WID_STL_SORTBY: // flip sorting method asc/desc
591  this->stations.ToggleSortOrder();
592  this->SetDirty();
593  break;
594 
595  case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu
596  ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0);
597  break;
598 
600  if (_ctrl_pressed) {
601  this->include_empty = !this->include_empty;
603  } else {
604  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
605  this->RaiseWidget(WID_STL_CARGOSTART + i);
606  }
607 
608  this->cargo_filter = 0;
609  this->include_empty = true;
610 
612  }
613  this->stations.ForceRebuild();
614  this->SetDirty();
615  break;
616 
617  default:
618  if (widget >= WID_STL_CARGOSTART) { // change cargo_filter
619  /* Determine the selected cargo type */
620  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
621 
622  if (_ctrl_pressed) {
623  ToggleBit(this->cargo_filter, cs->Index());
624  this->ToggleWidgetLoweredState(widget);
625  } else {
626  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
627  this->RaiseWidget(WID_STL_CARGOSTART + i);
628  }
630 
631  this->cargo_filter = 0;
632  this->include_empty = false;
633 
634  SetBit(this->cargo_filter, cs->Index());
635  this->LowerWidget(widget);
636  }
637  this->stations.ForceRebuild();
638  this->SetDirty();
639  }
640  break;
641  }
642  }
643 
644  void OnDropdownSelect(int widget, int index) override
645  {
646  if (this->stations.SortType() != index) {
647  this->stations.SetSortType(index);
648 
649  /* Display the current sort variant */
650  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
651 
652  this->SetDirty();
653  }
654  }
655 
656  void OnGameTick() override
657  {
658  if (this->stations.NeedResort()) {
659  DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number);
660  this->SetDirty();
661  }
662  }
663 
664  void OnResize() override
665  {
667  }
668 
674  void OnInvalidateData(int data = 0, bool gui_scope = true) override
675  {
676  if (data == 0) {
677  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
678  this->stations.ForceRebuild();
679  } else {
680  this->stations.ForceResort();
681  }
682  }
683 };
684 
685 Listing CompanyStationsWindow::last_sorting = {false, 0};
686 byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
687 bool CompanyStationsWindow::include_empty = true;
688 const CargoTypes CompanyStationsWindow::cargo_filter_max = ALL_CARGOTYPES;
689 CargoTypes CompanyStationsWindow::cargo_filter = ALL_CARGOTYPES;
690 
691 /* Available station sorting functions */
692 GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
699 };
700 
701 /* Names of the sorting functions */
702 const StringID CompanyStationsWindow::sorter_names[] = {
703  STR_SORT_BY_NAME,
704  STR_SORT_BY_FACILITY,
705  STR_SORT_BY_WAITING_TOTAL,
706  STR_SORT_BY_WAITING_AVAILABLE,
707  STR_SORT_BY_RATING_MAX,
708  STR_SORT_BY_RATING_MIN,
710 };
711 
717 static NWidgetBase *CargoWidgets(int *biggest_index)
718 {
719  NWidgetHorizontal *container = new NWidgetHorizontal();
720 
721  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
722  NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
723  panel->SetMinimalSize(14, 11);
724  panel->SetResize(0, 0);
725  panel->SetFill(0, 1);
726  panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
727  container->Add(panel);
728  }
730  return container;
731 }
732 
733 static const NWidgetPart _nested_company_stations_widgets[] = {
735  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
736  NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
737  NWidget(WWT_SHADEBOX, COLOUR_GREY),
738  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
739  NWidget(WWT_STICKYBOX, COLOUR_GREY),
740  EndContainer(),
742  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),
743  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),
744  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),
745  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),
746  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),
747  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1),
748  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(),
750  NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(),
751  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1),
752  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
753  EndContainer(),
755  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
756  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten.
757  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
758  EndContainer(),
760  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(),
763  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
764  EndContainer(),
765  EndContainer(),
766 };
767 
768 static WindowDesc _company_stations_desc(
769  WDP_AUTO, "list_stations", 358, 162,
771  0,
772  _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets)
773 );
774 
781 {
782  if (!Company::IsValidID(company)) return;
783 
784  AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
785 }
786 
787 static const NWidgetPart _nested_station_view_widgets[] = {
789  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
790  NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
791  NWidget(WWT_SHADEBOX, COLOUR_GREY),
792  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
793  NWidget(WWT_STICKYBOX, COLOUR_GREY),
794  EndContainer(),
796  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
797  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
798  EndContainer(),
800  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0),
801  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
802  EndContainer(),
806  EndContainer(),
810  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
811  SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
812  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1),
813  SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
814  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
815  SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
816  EndContainer(),
817  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
818  SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
819  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CATCHMENT), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
820  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
821  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
822  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
823  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
824  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
825  EndContainer(),
826 };
827 
837 static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
838 {
839  int width = ScaleGUITrad(10);
840  uint num = min((waiting + (width / 2)) / width, (right - left) / width); // maximum is width / 10 icons so it won't overflow
841  if (num == 0) return;
842 
843  SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon();
844 
845  int x = _current_text_dir == TD_RTL ? left : right - num * width;
846  do {
847  DrawSprite(sprite, PAL_NONE, x, y);
848  x += width;
849  } while (--num);
850 }
851 
852 enum SortOrder {
853  SO_DESCENDING,
854  SO_ASCENDING
855 };
856 
857 class CargoDataEntry;
858 
865 };
866 
867 class CargoSorter {
868 public:
869  CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {}
870  CargoSortType GetSortType() {return this->type;}
871  bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
872 
873 private:
874  CargoSortType type;
875  SortOrder order;
876 
877  template<class Tid>
878  bool SortId(Tid st1, Tid st2) const;
879  bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
880  bool SortStation (StationID st1, StationID st2) const;
881 };
882 
883 typedef std::set<CargoDataEntry *, CargoSorter> CargoDataSet;
884 
891 public:
892  CargoDataEntry();
893  ~CargoDataEntry();
894 
900  CargoDataEntry *InsertOrRetrieve(StationID station)
901  {
902  return this->InsertOrRetrieve<StationID>(station);
903  }
904 
911  {
912  return this->InsertOrRetrieve<CargoID>(cargo);
913  }
914 
915  void Update(uint count);
916 
921  void Remove(StationID station)
922  {
923  CargoDataEntry t(station);
924  this->Remove(&t);
925  }
926 
931  void Remove(CargoID cargo)
932  {
933  CargoDataEntry t(cargo);
934  this->Remove(&t);
935  }
936 
942  CargoDataEntry *Retrieve(StationID station) const
943  {
944  CargoDataEntry t(station);
945  return this->Retrieve(this->children->find(&t));
946  }
947 
954  {
955  CargoDataEntry t(cargo);
956  return this->Retrieve(this->children->find(&t));
957  }
958 
959  void Resort(CargoSortType type, SortOrder order);
960 
964  StationID GetStation() const { return this->station; }
965 
969  CargoID GetCargo() const { return this->cargo; }
970 
974  uint GetCount() const { return this->count; }
975 
979  CargoDataEntry *GetParent() const { return this->parent; }
980 
984  uint GetNumChildren() const { return this->num_children; }
985 
989  CargoDataSet::iterator Begin() const { return this->children->begin(); }
990 
994  CargoDataSet::iterator End() const { return this->children->end(); }
995 
999  bool HasTransfers() const { return this->transfers; }
1000 
1004  void SetTransfers(bool value) { this->transfers = value; }
1005 
1006  void Clear();
1007 private:
1008 
1009  CargoDataEntry(StationID st, uint c, CargoDataEntry *p);
1010  CargoDataEntry(CargoID car, uint c, CargoDataEntry *p);
1011  CargoDataEntry(StationID st);
1012  CargoDataEntry(CargoID car);
1013 
1014  CargoDataEntry *Retrieve(CargoDataSet::iterator i) const;
1015 
1016  template<class Tid>
1017  CargoDataEntry *InsertOrRetrieve(Tid s);
1018 
1019  void Remove(CargoDataEntry *comp);
1020  void IncrementSize();
1021 
1023  const union {
1024  StationID station;
1025  struct {
1027  bool transfers;
1028  };
1029  };
1031  uint count;
1032  CargoDataSet *children;
1033 };
1034 
1035 CargoDataEntry::CargoDataEntry() :
1036  parent(nullptr),
1037  station(INVALID_STATION),
1038  num_children(0),
1039  count(0),
1040  children(new CargoDataSet(CargoSorter(ST_CARGO_ID)))
1041 {}
1042 
1043 CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) :
1044  parent(parent),
1045  cargo(cargo),
1046  num_children(0),
1047  count(count),
1048  children(new CargoDataSet)
1049 {}
1050 
1051 CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) :
1052  parent(parent),
1053  station(station),
1054  num_children(0),
1055  count(count),
1056  children(new CargoDataSet)
1057 {}
1058 
1059 CargoDataEntry::CargoDataEntry(StationID station) :
1060  parent(nullptr),
1061  station(station),
1062  num_children(0),
1063  count(0),
1064  children(nullptr)
1065 {}
1066 
1067 CargoDataEntry::CargoDataEntry(CargoID cargo) :
1068  parent(nullptr),
1069  cargo(cargo),
1070  num_children(0),
1071  count(0),
1072  children(nullptr)
1073 {}
1074 
1075 CargoDataEntry::~CargoDataEntry()
1076 {
1077  this->Clear();
1078  delete this->children;
1079 }
1080 
1085 {
1086  if (this->children != nullptr) {
1087  for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) {
1088  assert(*i != this);
1089  delete *i;
1090  }
1091  this->children->clear();
1092  }
1093  if (this->parent != nullptr) this->parent->count -= this->count;
1094  this->count = 0;
1095  this->num_children = 0;
1096 }
1097 
1105 {
1106  CargoDataSet::iterator i = this->children->find(child);
1107  if (i != this->children->end()) {
1108  delete *i;
1109  this->children->erase(i);
1110  }
1111 }
1112 
1119 template<class Tid>
1121 {
1122  CargoDataEntry tmp(child_id);
1123  CargoDataSet::iterator i = this->children->find(&tmp);
1124  if (i == this->children->end()) {
1125  IncrementSize();
1126  return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first);
1127  } else {
1128  CargoDataEntry *ret = *i;
1129  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1130  return ret;
1131  }
1132 }
1133 
1140 {
1141  this->count += count;
1142  if (this->parent != nullptr) this->parent->Update(count);
1143 }
1144 
1149 {
1150  ++this->num_children;
1151  if (this->parent != nullptr) this->parent->IncrementSize();
1152 }
1153 
1154 void CargoDataEntry::Resort(CargoSortType type, SortOrder order)
1155 {
1156  CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order));
1157  delete this->children;
1158  this->children = new_subs;
1159 }
1160 
1161 CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const
1162 {
1163  if (i == this->children->end()) {
1164  return nullptr;
1165  } else {
1166  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1167  return *i;
1168  }
1169 }
1170 
1171 bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1172 {
1173  switch (this->type) {
1174  case ST_STATION_ID:
1175  return this->SortId<StationID>(cd1->GetStation(), cd2->GetStation());
1176  case ST_CARGO_ID:
1177  return this->SortId<CargoID>(cd1->GetCargo(), cd2->GetCargo());
1178  case ST_COUNT:
1179  return this->SortCount(cd1, cd2);
1180  case ST_STATION_STRING:
1181  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1182  default:
1183  NOT_REACHED();
1184  }
1185 }
1186 
1187 template<class Tid>
1188 bool CargoSorter::SortId(Tid st1, Tid st2) const
1189 {
1190  return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1;
1191 }
1192 
1193 bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1194 {
1195  uint c1 = cd1->GetCount();
1196  uint c2 = cd2->GetCount();
1197  if (c1 == c2) {
1198  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1199  } else if (this->order == SO_ASCENDING) {
1200  return c1 < c2;
1201  } else {
1202  return c2 < c1;
1203  }
1204 }
1205 
1206 bool CargoSorter::SortStation(StationID st1, StationID st2) const
1207 {
1208  if (!Station::IsValidID(st1)) {
1209  return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2);
1210  } else if (!Station::IsValidID(st2)) {
1211  return order == SO_DESCENDING;
1212  }
1213 
1214  int res = strnatcmp(Station::Get(st1)->GetCachedName(), Station::Get(st2)->GetCachedName()); // Sort by name (natural sorting).
1215  if (res == 0) {
1216  return this->SortId(st1, st2);
1217  } else {
1218  return (this->order == SO_ASCENDING) ? res < 0 : res > 0;
1219  }
1220 }
1221 
1225 struct StationViewWindow : public Window {
1229  struct RowDisplay {
1230  RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {}
1231  RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {}
1232 
1237  union {
1241  StationID next_station;
1242 
1247  };
1248  };
1249 
1250  typedef std::vector<RowDisplay> CargoDataVector;
1251 
1252  static const int NUM_COLUMNS = 4;
1253 
1258  INV_FLOWS = 0x100,
1259  INV_CARGO = 0x200
1260  };
1261 
1265  enum Grouping {
1270  };
1271 
1275  enum Mode {
1277  MODE_PLANNED
1278  };
1279 
1283  Scrollbar *vscroll;
1284 
1287  ALH_RATING = 13,
1288  ALH_ACCEPTS = 3,
1289  };
1290 
1291  static const StringID _sort_names[];
1292  static const StringID _group_names[];
1293 
1300  CargoSortType sortings[NUM_COLUMNS];
1301 
1303  SortOrder sort_orders[NUM_COLUMNS];
1304 
1308  Grouping groupings[NUM_COLUMNS];
1309 
1312  CargoDataVector displayed_rows;
1313 
1314  StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc),
1315  scroll_to_row(INT_MAX), grouping_index(0)
1316  {
1317  this->rating_lines = ALH_RATING;
1318  this->accepts_lines = ALH_ACCEPTS;
1319 
1320  this->CreateNestedTree();
1321  this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
1322  /* Nested widget tree creation is done in two steps to ensure that this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */
1323  this->FinishInitNested(window_number);
1324 
1325  this->groupings[0] = GR_CARGO;
1326  this->sortings[0] = ST_AS_GROUPING;
1327  this->SelectGroupBy(_settings_client.gui.station_gui_group_order);
1328  this->SelectSortBy(_settings_client.gui.station_gui_sort_by);
1329  this->sort_orders[0] = SO_ASCENDING;
1330  this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order);
1331  this->owner = Station::Get(window_number)->owner;
1332  }
1333 
1335  {
1336  DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->window_number).Pack(), false);
1337  DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).Pack(), false);
1338  DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).Pack(), false);
1339  DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).Pack(), false);
1340 
1341  SetViewportCatchmentStation(Station::Get(this->window_number), false);
1342  }
1343 
1354  void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count)
1355  {
1356  if (count == 0) return;
1357  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1358  const CargoDataEntry *expand = &this->expanded_rows;
1359  for (int i = 0; i < NUM_COLUMNS && expand != nullptr; ++i) {
1360  switch (groupings[i]) {
1361  case GR_CARGO:
1362  assert(i == 0);
1363  data = data->InsertOrRetrieve(cargo);
1364  data->SetTransfers(source != this->window_number);
1365  expand = expand->Retrieve(cargo);
1366  break;
1367  case GR_SOURCE:
1368  if (auto_distributed || source != this->window_number) {
1369  data = data->InsertOrRetrieve(source);
1370  expand = expand->Retrieve(source);
1371  }
1372  break;
1373  case GR_NEXT:
1374  if (auto_distributed) {
1375  data = data->InsertOrRetrieve(next);
1376  expand = expand->Retrieve(next);
1377  }
1378  break;
1379  case GR_DESTINATION:
1380  if (auto_distributed) {
1381  data = data->InsertOrRetrieve(dest);
1382  expand = expand->Retrieve(dest);
1383  }
1384  break;
1385  }
1386  }
1387  data->Update(count);
1388  }
1389 
1390  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1391  {
1392  switch (widget) {
1393  case WID_SV_WAITING:
1394  resize->height = FONT_HEIGHT_NORMAL;
1395  size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM;
1396  this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
1397  break;
1398 
1400  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;
1401  break;
1402 
1403  case WID_SV_CLOSE_AIRPORT:
1404  if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) {
1405  /* Hide 'Close Airport' button if no airport present. */
1406  size->width = 0;
1407  resize->width = 0;
1408  fill->width = 0;
1409  }
1410  break;
1411  }
1412  }
1413 
1414  void OnPaint() override
1415  {
1416  const Station *st = Station::Get(this->window_number);
1418  BuildCargoList(&cargo, st);
1419 
1420  this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar
1421 
1422  /* disable some buttons */
1423  this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company);
1424  this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN));
1425  this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
1426  this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK));
1427  this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT));
1428  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
1429  this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0);
1430 
1431  extern const Station *_viewport_highlight_station;
1432  this->SetWidgetDisabledState(WID_SV_CATCHMENT, st->facilities == FACIL_NONE);
1433  this->SetWidgetLoweredState(WID_SV_CATCHMENT, _viewport_highlight_station == st);
1434 
1435  this->DrawWidgets();
1436 
1437  if (!this->IsShaded()) {
1438  /* Draw 'accepted cargo' or 'cargo ratings'. */
1439  const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SV_ACCEPT_RATING_LIST);
1440  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)};
1441  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1442  int lines = this->DrawAcceptedCargo(r);
1443  if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window.
1444  this->accepts_lines = lines;
1445  this->ReInit();
1446  return;
1447  }
1448  } else {
1449  int lines = this->DrawCargoRatings(r);
1450  if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window.
1451  this->rating_lines = lines;
1452  this->ReInit();
1453  return;
1454  }
1455  }
1456 
1457  /* Draw arrow pointing up/down for ascending/descending sorting */
1458  this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN);
1459 
1460  int pos = this->vscroll->GetPosition();
1461 
1462  int maxrows = this->vscroll->GetCapacity();
1463 
1464  displayed_rows.clear();
1465 
1466  /* Draw waiting cargo. */
1467  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SV_WAITING);
1468  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)};
1469  this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0);
1470  scroll_to_row = INT_MAX;
1471  }
1472  }
1473 
1474  void SetStringParameters(int widget) const override
1475  {
1476  const Station *st = Station::Get(this->window_number);
1477  SetDParam(0, st->index);
1478  SetDParam(1, st->facilities);
1479  }
1480 
1487  {
1488  const Station *st = Station::Get(this->window_number);
1489  CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i);
1490  cargo_entry->Clear();
1491 
1492  const FlowStatMap &flows = st->goods[i].flows;
1493  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1494  StationID from = it->first;
1495  CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from);
1496  const FlowStat::SharesMap *shares = it->second.GetShares();
1497  uint32 prev_count = 0;
1498  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1499  StationID via = flow_it->second;
1500  CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via);
1501  if (via == this->window_number) {
1502  via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count);
1503  } else {
1504  EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry);
1505  }
1506  prev_count = flow_it->first;
1507  }
1508  }
1509  }
1510 
1520  void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest)
1521  {
1522  if (Station::IsValidID(next) && Station::IsValidID(source)) {
1523  CargoDataEntry tmp;
1524  const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows;
1525  FlowStatMap::const_iterator map_it = flowmap.find(source);
1526  if (map_it != flowmap.end()) {
1527  const FlowStat::SharesMap *shares = map_it->second.GetShares();
1528  uint32 prev_count = 0;
1529  for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) {
1530  tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
1531  prev_count = i->first;
1532  }
1533  }
1534 
1535  if (tmp.GetCount() == 0) {
1536  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1537  } else {
1538  uint sum_estimated = 0;
1539  while (sum_estimated < count) {
1540  for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) {
1541  CargoDataEntry *child = *i;
1542  uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount());
1543  if (estimate == 0) estimate = 1;
1544 
1545  sum_estimated += estimate;
1546  if (sum_estimated > count) {
1547  estimate -= sum_estimated - count;
1548  sum_estimated = count;
1549  }
1550 
1551  if (estimate > 0) {
1552  if (child->GetStation() == next) {
1553  dest->InsertOrRetrieve(next)->Update(estimate);
1554  } else {
1555  EstimateDestinations(cargo, source, child->GetStation(), estimate, dest);
1556  }
1557  }
1558  }
1559 
1560  }
1561  }
1562  } else {
1563  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1564  }
1565  }
1566 
1574  {
1575  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1576  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1577  StationID from = it->first;
1578  const CargoDataEntry *source_entry = source_dest->Retrieve(from);
1579  const FlowStat::SharesMap *shares = it->second.GetShares();
1580  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1581  const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second);
1582  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1583  CargoDataEntry *dest_entry = *dest_it;
1584  ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount());
1585  }
1586  }
1587  }
1588  }
1589 
1597  {
1598  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1599  for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) {
1600  const CargoPacket *cp = *it;
1601  StationID next = it.GetKey();
1602 
1603  const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation());
1604  if (source_entry == nullptr) {
1605  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1606  continue;
1607  }
1608 
1609  const CargoDataEntry *via_entry = source_entry->Retrieve(next);
1610  if (via_entry == nullptr) {
1611  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1612  continue;
1613  }
1614 
1615  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1616  CargoDataEntry *dest_entry = *dest_it;
1617  uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount());
1618  this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val);
1619  }
1620  }
1621  this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount());
1622  }
1623 
1630  {
1631  for (CargoID i = 0; i < NUM_CARGO; i++) {
1632 
1633  if (this->cached_destinations.Retrieve(i) == nullptr) {
1634  this->RecalcDestinations(i);
1635  }
1636 
1637  if (this->current_mode == MODE_WAITING) {
1638  this->BuildCargoList(i, st->goods[i].cargo, cargo);
1639  } else {
1640  this->BuildFlowList(i, st->goods[i].flows, cargo);
1641  }
1642  }
1643  }
1644 
1650  {
1651  std::list<StationID> stations;
1652  const CargoDataEntry *parent = data->GetParent();
1653  if (parent->GetParent() == nullptr) {
1654  this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo()));
1655  return;
1656  }
1657 
1658  StationID next = data->GetStation();
1659  while (parent->GetParent()->GetParent() != nullptr) {
1660  stations.push_back(parent->GetStation());
1661  parent = parent->GetParent();
1662  }
1663 
1664  CargoID cargo = parent->GetCargo();
1665  CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo);
1666  while (!stations.empty()) {
1667  filter = filter->Retrieve(stations.back());
1668  stations.pop_back();
1669  }
1670 
1671  this->displayed_rows.push_back(RowDisplay(filter, next));
1672  }
1673 
1682  StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any)
1683  {
1684  if (station == this->window_number) {
1685  return here;
1686  } else if (station == INVALID_STATION) {
1687  return any;
1688  } else if (station == NEW_STATION) {
1689  return STR_STATION_VIEW_RESERVED;
1690  } else {
1691  SetDParam(2, station);
1692  return other_station;
1693  }
1694  }
1695 
1703  StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column)
1704  {
1705  CargoDataEntry *parent = cd->GetParent();
1706  for (int i = column - 1; i > 0; --i) {
1707  if (this->groupings[i] == GR_DESTINATION) {
1708  if (parent->GetStation() == station) {
1709  return STR_STATION_VIEW_NONSTOP;
1710  } else {
1711  return STR_STATION_VIEW_VIA;
1712  }
1713  }
1714  parent = parent->GetParent();
1715  }
1716 
1717  if (this->groupings[column + 1] == GR_DESTINATION) {
1718  CargoDataSet::iterator begin = cd->Begin();
1719  CargoDataSet::iterator end = cd->End();
1720  if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) {
1721  return STR_STATION_VIEW_NONSTOP;
1722  } else {
1723  return STR_STATION_VIEW_VIA;
1724  }
1725  }
1726 
1727  return STR_STATION_VIEW_VIA;
1728  }
1729 
1740  int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID)
1741  {
1742  if (this->sortings[column] == ST_AS_GROUPING) {
1743  if (this->groupings[column] != GR_CARGO) {
1744  entry->Resort(ST_STATION_STRING, this->sort_orders[column]);
1745  }
1746  } else {
1747  entry->Resort(ST_COUNT, this->sort_orders[column]);
1748  }
1749  for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) {
1750  CargoDataEntry *cd = *i;
1751 
1752  Grouping grouping = this->groupings[column];
1753  if (grouping == GR_CARGO) cargo = cd->GetCargo();
1754  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1755 
1756  if (pos > -maxrows && pos <= 0) {
1757  StringID str = STR_EMPTY;
1758  int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL;
1759  SetDParam(0, cargo);
1760  SetDParam(1, cd->GetCount());
1761 
1762  if (this->groupings[column] == GR_CARGO) {
1763  str = STR_STATION_VIEW_WAITING_CARGO;
1764  DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y);
1765  } else {
1766  if (!auto_distributed) grouping = GR_SOURCE;
1767  StationID station = cd->GetStation();
1768 
1769  switch (grouping) {
1770  case GR_SOURCE:
1771  str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY);
1772  break;
1773  case GR_NEXT:
1774  str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY);
1775  if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column);
1776  break;
1777  case GR_DESTINATION:
1778  str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY);
1779  break;
1780  default:
1781  NOT_REACHED();
1782  }
1783  if (pos == -this->scroll_to_row && Station::IsValidID(station)) {
1784  ScrollMainWindowToTile(Station::Get(station)->xy);
1785  }
1786  }
1787 
1788  bool rtl = _current_text_dir == TD_RTL;
1789  int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width;
1790  int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width;
1791  int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT;
1792  int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT;
1793 
1794  DrawString(text_left, text_right, y, str);
1795 
1796  if (column < NUM_COLUMNS - 1) {
1797  const char *sym = nullptr;
1798  if (cd->GetNumChildren() > 0) {
1799  sym = "-";
1800  } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) {
1801  sym = "+";
1802  } else {
1803  /* Only draw '+' if there is something to be shown. */
1804  const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo;
1805  if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) {
1806  sym = "+";
1807  }
1808  }
1809  if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW);
1810  }
1811  this->SetDisplayedRow(cd);
1812  }
1813  --pos;
1814  if (auto_distributed || column == 0) {
1815  pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo);
1816  }
1817  }
1818  return pos;
1819  }
1820 
1826  int DrawAcceptedCargo(const Rect &r) const
1827  {
1828  const Station *st = Station::Get(this->window_number);
1829 
1830  CargoTypes cargo_mask = 0;
1831  for (CargoID i = 0; i < NUM_CARGO; i++) {
1832  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i);
1833  }
1834  SetDParam(0, cargo_mask);
1835  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);
1836  return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1837  }
1838 
1844  int DrawCargoRatings(const Rect &r) const
1845  {
1846  const Station *st = Station::Get(this->window_number);
1847  int y = r.top + WD_FRAMERECT_TOP;
1848 
1849  if (st->town->exclusive_counter > 0) {
1850  SetDParam(0, st->town->exclusivity);
1851  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);
1852  y += WD_PAR_VSEP_WIDE;
1853  }
1854 
1855  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE);
1856  y += FONT_HEIGHT_NORMAL;
1857 
1858  const CargoSpec *cs;
1860  const GoodsEntry *ge = &st->goods[cs->Index()];
1861  if (!ge->HasRating()) continue;
1862 
1863  const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph);
1864  SetDParam(0, cs->name);
1865  SetDParam(1, lg != nullptr ? lg->Monthly((*lg)[ge->node].Supply()) : 0);
1866  SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5));
1867  SetDParam(3, ToPercent8(ge->rating));
1868  DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING);
1869  y += FONT_HEIGHT_NORMAL;
1870  }
1871  return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1872  }
1873 
1879  template<class Tid>
1880  void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
1881  {
1882  if (filter->Retrieve(next) != nullptr) {
1883  filter->Remove(next);
1884  } else {
1885  filter->InsertOrRetrieve(next);
1886  }
1887  }
1888 
1894  {
1895  if (row < 0 || (uint)row >= this->displayed_rows.size()) return;
1896  if (_ctrl_pressed) {
1897  this->scroll_to_row = row;
1898  } else {
1899  RowDisplay &display = this->displayed_rows[row];
1900  if (display.filter == &this->expanded_rows) {
1901  this->HandleCargoWaitingClick<CargoID>(display.filter, display.next_cargo);
1902  } else {
1903  this->HandleCargoWaitingClick<StationID>(display.filter, display.next_station);
1904  }
1905  }
1906  this->SetWidgetDirty(WID_SV_WAITING);
1907  }
1908 
1909  void OnClick(Point pt, int widget, int click_count) override
1910  {
1911  switch (widget) {
1912  case WID_SV_WAITING:
1913  this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition());
1914  break;
1915 
1916  case WID_SV_CATCHMENT:
1917  SetViewportCatchmentStation(Station::Get(this->window_number), !this->IsWidgetLowered(WID_SV_CATCHMENT));
1918  break;
1919 
1920  case WID_SV_LOCATION:
1921  if (_ctrl_pressed) {
1922  ShowExtraViewPortWindow(Station::Get(this->window_number)->xy);
1923  } else {
1924  ScrollMainWindowToTile(Station::Get(this->window_number)->xy);
1925  }
1926  break;
1927 
1928  case WID_SV_ACCEPTS_RATINGS: {
1929  /* Swap between 'accepts' and 'ratings' view. */
1930  int height_change;
1931  NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS);
1932  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1933  nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view.
1934  height_change = this->rating_lines - this->accepts_lines;
1935  } else {
1936  nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view.
1937  height_change = this->accepts_lines - this->rating_lines;
1938  }
1939  this->ReInit(0, height_change * FONT_HEIGHT_NORMAL);
1940  break;
1941  }
1942 
1943  case WID_SV_RENAME:
1944  SetDParam(0, this->window_number);
1945  ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
1947  break;
1948 
1949  case WID_SV_CLOSE_AIRPORT:
1950  DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT);
1951  break;
1952 
1953  case WID_SV_TRAINS: // Show list of scheduled trains to this station
1954  case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station
1955  case WID_SV_SHIPS: // Show list of scheduled ships to this station
1956  case WID_SV_PLANES: { // Show list of scheduled aircraft to this station
1957  Owner owner = Station::Get(this->window_number)->owner;
1958  ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number);
1959  break;
1960  }
1961 
1962  case WID_SV_SORT_BY: {
1963  /* The initial selection is composed of current mode and
1964  * sorting criteria for columns 1, 2, and 3. Column 0 is always
1965  * sorted by cargo ID. The others can theoretically be sorted
1966  * by different things but there is no UI for that. */
1967  ShowDropDownMenu(this, _sort_names,
1968  this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0),
1969  WID_SV_SORT_BY, 0, 0);
1970  break;
1971  }
1972 
1973  case WID_SV_GROUP_BY: {
1974  ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
1975  break;
1976  }
1977 
1978  case WID_SV_SORT_ORDER: { // flip sorting method asc/desc
1979  this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING);
1980  this->SetTimeout();
1981  this->LowerWidget(WID_SV_SORT_ORDER);
1982  break;
1983  }
1984  }
1985  }
1986 
1991  void SelectSortOrder(SortOrder order)
1992  {
1993  this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order;
1994  _settings_client.gui.station_gui_sort_order = this->sort_orders[1];
1995  this->SetDirty();
1996  }
1997 
2002  void SelectSortBy(int index)
2003  {
2005  switch (_sort_names[index]) {
2006  case STR_STATION_VIEW_WAITING_STATION:
2007  this->current_mode = MODE_WAITING;
2008  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
2009  break;
2010  case STR_STATION_VIEW_WAITING_AMOUNT:
2011  this->current_mode = MODE_WAITING;
2012  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
2013  break;
2014  case STR_STATION_VIEW_PLANNED_STATION:
2015  this->current_mode = MODE_PLANNED;
2016  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
2017  break;
2018  case STR_STATION_VIEW_PLANNED_AMOUNT:
2019  this->current_mode = MODE_PLANNED;
2020  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
2021  break;
2022  default:
2023  NOT_REACHED();
2024  }
2025  /* Display the current sort variant */
2026  this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->widget_data = _sort_names[index];
2027  this->SetDirty();
2028  }
2029 
2034  void SelectGroupBy(int index)
2035  {
2036  this->grouping_index = index;
2038  this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->widget_data = _group_names[index];
2039  switch (_group_names[index]) {
2040  case STR_STATION_VIEW_GROUP_S_V_D:
2041  this->groupings[1] = GR_SOURCE;
2042  this->groupings[2] = GR_NEXT;
2043  this->groupings[3] = GR_DESTINATION;
2044  break;
2045  case STR_STATION_VIEW_GROUP_S_D_V:
2046  this->groupings[1] = GR_SOURCE;
2047  this->groupings[2] = GR_DESTINATION;
2048  this->groupings[3] = GR_NEXT;
2049  break;
2050  case STR_STATION_VIEW_GROUP_V_S_D:
2051  this->groupings[1] = GR_NEXT;
2052  this->groupings[2] = GR_SOURCE;
2053  this->groupings[3] = GR_DESTINATION;
2054  break;
2055  case STR_STATION_VIEW_GROUP_V_D_S:
2056  this->groupings[1] = GR_NEXT;
2057  this->groupings[2] = GR_DESTINATION;
2058  this->groupings[3] = GR_SOURCE;
2059  break;
2060  case STR_STATION_VIEW_GROUP_D_S_V:
2061  this->groupings[1] = GR_DESTINATION;
2062  this->groupings[2] = GR_SOURCE;
2063  this->groupings[3] = GR_NEXT;
2064  break;
2065  case STR_STATION_VIEW_GROUP_D_V_S:
2066  this->groupings[1] = GR_DESTINATION;
2067  this->groupings[2] = GR_NEXT;
2068  this->groupings[3] = GR_SOURCE;
2069  break;
2070  }
2071  this->SetDirty();
2072  }
2073 
2074  void OnDropdownSelect(int widget, int index) override
2075  {
2076  if (widget == WID_SV_SORT_BY) {
2077  this->SelectSortBy(index);
2078  } else {
2079  this->SelectGroupBy(index);
2080  }
2081  }
2082 
2083  void OnQueryTextFinished(char *str) override
2084  {
2085  if (str == nullptr) return;
2086 
2087  DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), nullptr, str);
2088  }
2089 
2090  void OnResize() override
2091  {
2093  }
2094 
2100  void OnInvalidateData(int data = 0, bool gui_scope = true) override
2101  {
2102  if (gui_scope) {
2103  if (data >= 0 && data < NUM_CARGO) {
2104  this->cached_destinations.Remove((CargoID)data);
2105  } else {
2106  this->ReInit();
2107  }
2108  }
2109  }
2110 };
2111 
2113  STR_STATION_VIEW_WAITING_STATION,
2114  STR_STATION_VIEW_WAITING_AMOUNT,
2115  STR_STATION_VIEW_PLANNED_STATION,
2116  STR_STATION_VIEW_PLANNED_AMOUNT,
2118 };
2119 
2121  STR_STATION_VIEW_GROUP_S_V_D,
2122  STR_STATION_VIEW_GROUP_S_D_V,
2123  STR_STATION_VIEW_GROUP_V_S_D,
2124  STR_STATION_VIEW_GROUP_V_D_S,
2125  STR_STATION_VIEW_GROUP_D_S_V,
2126  STR_STATION_VIEW_GROUP_D_V_S,
2128 };
2129 
2130 static WindowDesc _station_view_desc(
2131  WDP_AUTO, "view_station", 249, 117,
2133  0,
2134  _nested_station_view_widgets, lengthof(_nested_station_view_widgets)
2135 );
2136 
2143 {
2144  AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
2145 }
2146 
2150  StationID station;
2151 };
2152 
2153 static std::vector<TileAndStation> _deleted_stations_nearby;
2154 static std::vector<StationID> _stations_nearby_list;
2155 
2163 template <class T>
2164 static bool AddNearbyStation(TileIndex tile, void *user_data)
2165 {
2166  TileArea *ctx = (TileArea *)user_data;
2167 
2168  /* First check if there were deleted stations here */
2169  for (uint i = 0; i < _deleted_stations_nearby.size(); i++) {
2170  auto ts = _deleted_stations_nearby.begin() + i;
2171  if (ts->tile == tile) {
2172  _stations_nearby_list.push_back(_deleted_stations_nearby[i].station);
2173  _deleted_stations_nearby.erase(ts);
2174  i--;
2175  }
2176  }
2177 
2178  /* Check if own station and if we stay within station spread */
2179  if (!IsTileType(tile, MP_STATION)) return false;
2180 
2181  StationID sid = GetStationIndex(tile);
2182 
2183  /* This station is (likely) a waypoint */
2184  if (!T::IsValidID(sid)) return false;
2185 
2186  T *st = T::Get(sid);
2187  if (st->owner != _local_company || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false;
2188 
2189  if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
2190  _stations_nearby_list.push_back(sid);
2191  }
2192 
2193  return false; // We want to include *all* nearby stations
2194 }
2195 
2205 template <class T>
2206 static const T *FindStationsNearby(TileArea ta, bool distant_join)
2207 {
2208  TileArea ctx = ta;
2209 
2210  _stations_nearby_list.clear();
2211  _deleted_stations_nearby.clear();
2212 
2213  /* Check the inside, to return, if we sit on another station */
2214  TILE_AREA_LOOP(t, ta) {
2215  if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
2216  }
2217 
2218  /* Look for deleted stations */
2219  for (const BaseStation *st : BaseStation::Iterate()) {
2220  if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
2221  /* Include only within station spread (yes, it is strictly less than) */
2222  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) {
2223  _deleted_stations_nearby.push_back({st->xy, st->index});
2224 
2225  /* Add the station when it's within where we're going to build */
2226  if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
2227  IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
2228  AddNearbyStation<T>(st->xy, &ctx);
2229  }
2230  }
2231  }
2232  }
2233 
2234  /* Only search tiles where we have a chance to stay within the station spread.
2235  * The complete check needs to be done in the callback as we don't know the
2236  * extent of the found station, yet. */
2237  if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return nullptr;
2238  uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1;
2239 
2240  TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
2241  CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
2242 
2243  return nullptr;
2244 }
2245 
2246 static const NWidgetPart _nested_select_station_widgets[] = {
2248  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
2249  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2250  NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
2251  EndContainer(),
2253  NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(),
2255  NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR),
2256  NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
2257  EndContainer(),
2258  EndContainer(),
2259 };
2260 
2265 template <class T>
2269  Scrollbar *vscroll;
2270 
2271  SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) :
2272  Window(desc),
2273  select_station_cmd(cmd),
2274  area(ta)
2275  {
2276  this->CreateNestedTree();
2277  this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
2278  this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
2279  this->FinishInitNested(0);
2280  this->OnInvalidateData(0);
2281 
2282  _thd.freeze = true;
2283  }
2284 
2286  {
2288 
2289  _thd.freeze = false;
2290  }
2291 
2292  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2293  {
2294  if (widget != WID_JS_PANEL) return;
2295 
2296  /* Determine the widest string */
2297  Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
2298  for (uint i = 0; i < _stations_nearby_list.size(); i++) {
2299  const T *st = T::Get(_stations_nearby_list[i]);
2300  SetDParam(0, st->index);
2301  SetDParam(1, st->facilities);
2302  d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION));
2303  }
2304 
2305  resize->height = d.height;
2306  d.height *= 5;
2308  d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2309  *size = d;
2310  }
2311 
2312  void DrawWidget(const Rect &r, int widget) const override
2313  {
2314  if (widget != WID_JS_PANEL) return;
2315 
2316  uint y = r.top + WD_FRAMERECT_TOP;
2317  if (this->vscroll->GetPosition() == 0) {
2318  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);
2319  y += this->resize.step_height;
2320  }
2321 
2322  for (uint i = max<uint>(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.size(); ++i, y += this->resize.step_height) {
2323  /* Don't draw anything if it extends past the end of the window. */
2324  if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break;
2325 
2326  const T *st = T::Get(_stations_nearby_list[i - 1]);
2327  SetDParam(0, st->index);
2328  SetDParam(1, st->facilities);
2329  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);
2330  }
2331  }
2332 
2333  void OnClick(Point pt, int widget, int click_count) override
2334  {
2335  if (widget != WID_JS_PANEL) return;
2336 
2337  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2338  bool distant_join = (st_index > 0);
2339  if (distant_join) st_index--;
2340 
2341  if (distant_join && st_index >= _stations_nearby_list.size()) return;
2342 
2343  /* Insert station to be joined into stored command */
2344  SB(this->select_station_cmd.p2, 16, 16,
2345  (distant_join ? _stations_nearby_list[st_index] : NEW_STATION));
2346 
2347  /* Execute stored Command */
2348  DoCommandP(&this->select_station_cmd);
2349 
2350  /* Close Window; this might cause double frees! */
2352  }
2353 
2354  void OnRealtimeTick(uint delta_ms) override
2355  {
2356  if (_thd.dirty & 2) {
2357  _thd.dirty &= ~2;
2358  this->SetDirty();
2359  }
2360  }
2361 
2362  void OnResize() override
2363  {
2364  this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
2365  }
2366 
2372  void OnInvalidateData(int data = 0, bool gui_scope = true) override
2373  {
2374  if (!gui_scope) return;
2375  FindStationsNearby<T>(this->area, true);
2376  this->vscroll->SetCount((uint)_stations_nearby_list.size() + 1);
2377  this->SetDirty();
2378  }
2379 
2380  void OnMouseOver(Point pt, int widget) override
2381  {
2382  if (widget != WID_JS_PANEL || T::EXPECTED_FACIL == FACIL_WAYPOINT) {
2383  SetViewportCatchmentStation(nullptr, true);
2384  return;
2385  }
2386 
2387  /* Show coverage area of station under cursor */
2388  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2389  if (st_index == 0 || st_index > _stations_nearby_list.size()) {
2390  SetViewportCatchmentStation(nullptr, true);
2391  } else {
2392  st_index--;
2393  SetViewportCatchmentStation(Station::Get(_stations_nearby_list[st_index]), true);
2394  }
2395  }
2396 };
2397 
2398 static WindowDesc _select_station_desc(
2399  WDP_AUTO, "build_station_join", 200, 180,
2402  _nested_select_station_widgets, lengthof(_nested_select_station_widgets)
2403 );
2404 
2405 
2413 template <class T>
2414 static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta)
2415 {
2416  /* Only show selection if distant join is enabled in the settings */
2417  if (!_settings_game.station.distant_join_stations) return false;
2418 
2419  /* If a window is already opened and we didn't ctrl-click,
2420  * return true (i.e. just flash the old window) */
2421  Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
2422  if (selection_window != nullptr) {
2423  /* Abort current distant-join and start new one */
2424  delete selection_window;
2426  }
2427 
2428  /* only show the popup, if we press ctrl */
2429  if (!_ctrl_pressed) return false;
2430 
2431  /* Now check if we could build there */
2432  if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false;
2433 
2434  /* Test for adjacent station or station below selection.
2435  * If adjacent-stations is disabled and we are building next to a station, do not show the selection window.
2436  * but join the other station immediately. */
2437  const T *st = FindStationsNearby<T>(ta, false);
2438  return st == nullptr && (_settings_game.station.adjacent_stations || _stations_nearby_list.size() == 0);
2439 }
2440 
2447 template <class T>
2449 {
2450  if (StationJoinerNeeded<T>(cmd, ta)) {
2452  new SelectStationWindow<T>(&_select_station_desc, cmd, ta);
2453  } else {
2454  DoCommandP(&cmd);
2455  }
2456 }
2457 
2464 {
2465  ShowSelectBaseStationIfNeeded<Station>(cmd, ta);
2466 }
2467 
2474 {
2475  ShowSelectBaseStationIfNeeded<Waypoint>(cmd, ta);
2476 }
&#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:80
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:340
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:1870
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:334
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:1133
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:480
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:227
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
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:388
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:1831
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:1847
CargoDataSet * children
the children of this entry.
static const uint8 PC_GREEN
Green palette colour.
Definition: gfx_func.h:221
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:174
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:445
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:477
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:177
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:79
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:636
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:536
#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:838
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:1165
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:378
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:1257
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:211
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:75
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:318
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:247
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:370
uint count
sum of counts of all children or amount of cargo for this entry.
uint16 Count() const
Gets the number of &#39;items&#39; in this packet.
Definition: cargopacket.h:99
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:711
&#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:74
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:481
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:973
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:759
(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