OpenTTD
station_gui.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "stdafx.h"
13 #include "debug.h"
14 #include "gui.h"
15 #include "textbuf_gui.h"
16 #include "company_func.h"
17 #include "command_func.h"
18 #include "vehicle_gui.h"
19 #include "cargotype.h"
20 #include "station_gui.h"
21 #include "strings_func.h"
22 #include "string_func.h"
23 #include "window_func.h"
24 #include "viewport_func.h"
25 #include "widgets/dropdown_func.h"
26 #include "station_base.h"
27 #include "waypoint_base.h"
28 #include "tilehighlight_func.h"
29 #include "company_base.h"
30 #include "sortlist_type.h"
31 #include "core/geometry_func.hpp"
32 #include "vehiclelist.h"
33 #include "town.h"
34 #include "linkgraph/linkgraph.h"
35 #include "zoom_func.h"
36 
37 #include "widgets/station_widget.h"
38 
39 #include "table/strings.h"
40 
41 #include <set>
42 #include <vector>
43 
44 #include "safeguards.h"
45 
56 int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies)
57 {
58  TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
59  CargoTypes cargo_mask = 0;
60  if (_thd.drawstyle == HT_RECT && tile < MapSize()) {
61  CargoArray cargoes;
62  if (supplies) {
63  cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
64  } else {
65  cargoes = GetAcceptanceAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
66  }
67 
68  /* Convert cargo counts to a set of cargo bits, and draw the result. */
69  for (CargoID i = 0; i < NUM_CARGO; i++) {
70  switch (sct) {
71  case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break;
72  case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break;
73  case SCT_ALL: break;
74  default: NOT_REACHED();
75  }
76  if (cargoes[i] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, i);
77  }
78  }
79  SetDParam(0, cargo_mask);
80  return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO);
81 }
82 
89 {
90  if (_thd.dirty & 1) {
91  _thd.dirty &= ~1;
92  w->SetDirty();
93  }
94 }
95 
111 static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating)
112 {
113  static const uint units_full = 576;
114  static const uint rating_full = 224;
115 
116  const CargoSpec *cs = CargoSpec::Get(type);
117  if (!cs->IsValid()) return;
118 
119  int colour = cs->rating_colour;
120  TextColour tc = GetContrastColour(colour);
121  uint w = (minu(amount, units_full) + 5) / 36;
122 
123  int height = GetCharacterHeight(FS_SMALL);
124 
125  /* Draw total cargo (limited) on station (fits into 16 pixels) */
126  if (w != 0) GfxFillRect(left, y, left + w - 1, y + height, colour);
127 
128  /* Draw a one pixel-wide bar of additional cargo meter, useful
129  * for stations with only a small amount (<=30) */
130  if (w == 0) {
131  uint rest = amount / 5;
132  if (rest != 0) {
133  w += left;
134  GfxFillRect(w, y + height - rest, w, y + height, colour);
135  }
136  }
137 
138  DrawString(left + 1, right, y, cs->abbrev, tc);
139 
140  /* Draw green/red ratings bar (fits into 14 pixels) */
141  y += height + 2;
142  GfxFillRect(left + 1, y, left + 14, y, PC_RED);
143  rating = minu(rating, rating_full) / 16;
144  if (rating != 0) GfxFillRect(left + 1, y, left + rating, y, PC_GREEN);
145 }
146 
148 
153 {
154 protected:
155  /* Runtime saved values */
156  static Listing last_sorting;
157  static byte facilities; // types of stations of interest
158  static bool include_empty; // whether we should include stations without waiting cargo
159  static const CargoTypes cargo_filter_max;
160  static CargoTypes cargo_filter; // bitmap of cargo types to include
161  static const Station *last_station;
162 
163  /* Constants for sorting stations */
164  static const StringID sorter_names[];
165  static GUIStationList::SortFunction * const sorter_funcs[];
166 
167  GUIStationList stations;
168  Scrollbar *vscroll;
169 
176  {
177  if (!this->stations.NeedRebuild()) return;
178 
179  DEBUG(misc, 3, "Building station list for company %d", owner);
180 
181  this->stations.Clear();
182 
183  const Station *st;
184  FOR_ALL_STATIONS(st) {
185  if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
186  if (this->facilities & st->facilities) { // only stations with selected facilities
187  int num_waiting_cargo = 0;
188  for (CargoID j = 0; j < NUM_CARGO; j++) {
189  if (st->goods[j].HasRating()) {
190  num_waiting_cargo++; // count number of waiting cargo
191  if (HasBit(this->cargo_filter, j)) {
192  *this->stations.Append() = st;
193  break;
194  }
195  }
196  }
197  /* stations without waiting cargo */
198  if (num_waiting_cargo == 0 && this->include_empty) {
199  *this->stations.Append() = st;
200  }
201  }
202  }
203  }
204 
205  this->stations.Compact();
206  this->stations.RebuildDone();
207 
208  this->vscroll->SetCount(this->stations.Length()); // Update the scrollbar
209  }
210 
212  static int CDECL StationNameSorter(const Station * const *a, const Station * const *b)
213  {
214  static char buf_cache[64];
215  char buf[64];
216 
217  SetDParam(0, (*a)->index);
218  GetString(buf, STR_STATION_NAME, lastof(buf));
219 
220  if (*b != last_station) {
221  last_station = *b;
222  SetDParam(0, (*b)->index);
223  GetString(buf_cache, STR_STATION_NAME, lastof(buf_cache));
224  }
225 
226  int r = strnatcmp(buf, buf_cache); // Sort by name (natural sorting).
227  if (r == 0) return (*a)->index - (*b)->index;
228  return r;
229  }
230 
232  static int CDECL StationTypeSorter(const Station * const *a, const Station * const *b)
233  {
234  return (*a)->facilities - (*b)->facilities;
235  }
236 
238  static int CDECL StationWaitingTotalSorter(const Station * const *a, const Station * const *b)
239  {
240  int diff = 0;
241 
242  CargoID j;
243  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
244  diff += (*a)->goods[j].cargo.TotalCount() - (*b)->goods[j].cargo.TotalCount();
245  }
246 
247  return diff;
248  }
249 
251  static int CDECL StationWaitingAvailableSorter(const Station * const *a, const Station * const *b)
252  {
253  int diff = 0;
254 
255  CargoID j;
256  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
257  diff += (*a)->goods[j].cargo.AvailableCount() - (*b)->goods[j].cargo.AvailableCount();
258  }
259 
260  return diff;
261  }
262 
264  static int CDECL StationRatingMaxSorter(const Station * const *a, const Station * const *b)
265  {
266  byte maxr1 = 0;
267  byte maxr2 = 0;
268 
269  CargoID j;
270  FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
271  if ((*a)->goods[j].HasRating()) maxr1 = max(maxr1, (*a)->goods[j].rating);
272  if ((*b)->goods[j].HasRating()) maxr2 = max(maxr2, (*b)->goods[j].rating);
273  }
274 
275  return maxr1 - maxr2;
276  }
277 
279  static int CDECL StationRatingMinSorter(const Station * const *a, const Station * const *b)
280  {
281  byte minr1 = 255;
282  byte minr2 = 255;
283 
284  for (CargoID j = 0; j < NUM_CARGO; j++) {
285  if (!HasBit(cargo_filter, j)) continue;
286  if ((*a)->goods[j].HasRating()) minr1 = min(minr1, (*a)->goods[j].rating);
287  if ((*b)->goods[j].HasRating()) minr2 = min(minr2, (*b)->goods[j].rating);
288  }
289 
290  return -(minr1 - minr2);
291  }
292 
295  {
296  if (!this->stations.Sort()) return;
297 
298  /* Reset name sorter sort cache */
299  this->last_station = NULL;
300 
301  /* Set the modified widget dirty */
303  }
304 
305 public:
307  {
308  this->stations.SetListing(this->last_sorting);
309  this->stations.SetSortFuncs(this->sorter_funcs);
310  this->stations.ForceRebuild();
311  this->stations.NeedResort();
312  this->SortStationsList();
313 
314  this->CreateNestedTree();
315  this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR);
316  this->FinishInitNested(window_number);
317  this->owner = (Owner)this->window_number;
318 
319  const CargoSpec *cs;
321  if (!HasBit(this->cargo_filter, cs->Index())) continue;
322  this->LowerWidget(WID_STL_CARGOSTART + index);
323  }
324 
325  if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask;
326 
327  for (uint i = 0; i < 5; i++) {
328  if (HasBit(this->facilities, i)) this->LowerWidget(i + WID_STL_TRAIN);
329  }
330  this->SetWidgetLoweredState(WID_STL_NOCARGOWAITING, this->include_empty);
331 
332  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
333  }
334 
336  {
337  this->last_sorting = this->stations.GetListing();
338  }
339 
340  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
341  {
342  switch (widget) {
343  case WID_STL_SORTBY: {
344  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
345  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
346  d.height += padding.height;
347  *size = maxdim(*size, d);
348  break;
349  }
350 
351  case WID_STL_SORTDROPBTN: {
352  Dimension d = {0, 0};
353  for (int i = 0; this->sorter_names[i] != INVALID_STRING_ID; i++) {
354  d = maxdim(d, GetStringBoundingBox(this->sorter_names[i]));
355  }
356  d.width += padding.width;
357  d.height += padding.height;
358  *size = maxdim(*size, d);
359  break;
360  }
361 
362  case WID_STL_LIST:
363  resize->height = FONT_HEIGHT_NORMAL;
364  size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM;
365  break;
366 
367  case WID_STL_TRAIN:
368  case WID_STL_TRUCK:
369  case WID_STL_BUS:
370  case WID_STL_AIRPLANE:
371  case WID_STL_SHIP:
372  size->height = max<uint>(FONT_HEIGHT_SMALL, 10) + padding.height;
373  break;
374 
375  case WID_STL_CARGOALL:
376  case WID_STL_FACILALL:
377  case WID_STL_NOCARGOWAITING: {
378  Dimension d = GetStringBoundingBox(widget == WID_STL_NOCARGOWAITING ? STR_ABBREV_NONE : STR_ABBREV_ALL);
379  d.width += padding.width + 2;
380  d.height += padding.height;
381  *size = maxdim(*size, d);
382  break;
383  }
384 
385  default:
386  if (widget >= WID_STL_CARGOSTART) {
388  d.width += padding.width + 2;
389  d.height += padding.height;
390  *size = maxdim(*size, d);
391  }
392  break;
393  }
394  }
395 
396  virtual void OnPaint()
397  {
398  this->BuildStationsList((Owner)this->window_number);
399  this->SortStationsList();
400 
401  this->DrawWidgets();
402  }
403 
404  virtual void DrawWidget(const Rect &r, int widget) const
405  {
406  switch (widget) {
407  case WID_STL_SORTBY:
408  /* draw arrow pointing up/down for ascending/descending sorting */
410  break;
411 
412  case WID_STL_LIST: {
413  bool rtl = _current_text_dir == TD_RTL;
414  int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length());
415  int y = r.top + WD_FRAMERECT_TOP;
416  for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner
417  const Station *st = this->stations[i];
418  assert(st->xy != INVALID_TILE);
419 
420  /* Do not do the complex check HasStationInUse here, it may be even false
421  * when the order had been removed and the station list hasn't been removed yet */
422  assert(st->owner == owner || st->owner == OWNER_NONE);
423 
424  SetDParam(0, st->index);
425  SetDParam(1, st->facilities);
426  int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION);
427  x += rtl ? -5 : 5;
428 
429  /* show cargo waiting and station ratings */
430  for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) {
431  CargoID cid = _sorted_cargo_specs[j]->Index();
432  if (st->goods[cid].cargo.TotalCount() > 0) {
433  /* For RTL we work in exactly the opposite direction. So
434  * decrement the space needed first, then draw to the left
435  * instead of drawing to the left and then incrementing
436  * the space. */
437  if (rtl) {
438  x -= 20;
439  if (x < r.left + WD_FRAMERECT_LEFT) break;
440  }
441  StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating);
442  if (!rtl) {
443  x += 20;
444  if (x > r.right - WD_FRAMERECT_RIGHT) break;
445  }
446  }
447  }
448  y += FONT_HEIGHT_NORMAL;
449  }
450 
451  if (this->vscroll->GetCount() == 0) { // company has no stations
452  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_NONE);
453  return;
454  }
455  break;
456  }
457 
458  case WID_STL_NOCARGOWAITING: {
459  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
460  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER);
461  break;
462  }
463 
464  case WID_STL_CARGOALL: {
465  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
466  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
467  break;
468  }
469 
470  case WID_STL_FACILALL: {
471  int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
472  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
473  break;
474  }
475 
476  default:
477  if (widget >= WID_STL_CARGOSTART) {
478  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
479  int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1;
480  GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour);
481  TextColour tc = GetContrastColour(cs->rating_colour);
482  DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER);
483  }
484  break;
485  }
486  }
487 
488  virtual void SetStringParameters(int widget) const
489  {
490  if (widget == WID_STL_CAPTION) {
491  SetDParam(0, this->window_number);
492  SetDParam(1, this->vscroll->GetCount());
493  }
494  }
495 
496  virtual void OnClick(Point pt, int widget, int click_count)
497  {
498  switch (widget) {
499  case WID_STL_LIST: {
500  uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL);
501  if (id_v >= this->stations.Length()) return; // click out of list bound
502 
503  const Station *st = this->stations[id_v];
504  /* do not check HasStationInUse - it is slow and may be invalid */
505  assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE);
506 
507  if (_ctrl_pressed) {
509  } else {
511  }
512  break;
513  }
514 
515  case WID_STL_TRAIN:
516  case WID_STL_TRUCK:
517  case WID_STL_BUS:
518  case WID_STL_AIRPLANE:
519  case WID_STL_SHIP:
520  if (_ctrl_pressed) {
521  ToggleBit(this->facilities, widget - WID_STL_TRAIN);
522  this->ToggleWidgetLoweredState(widget);
523  } else {
524  uint i;
525  FOR_EACH_SET_BIT(i, this->facilities) {
526  this->RaiseWidget(i + WID_STL_TRAIN);
527  }
528  this->facilities = 1 << (widget - WID_STL_TRAIN);
529  this->LowerWidget(widget);
530  }
531  this->stations.ForceRebuild();
532  this->SetDirty();
533  break;
534 
535  case WID_STL_FACILALL:
536  for (uint i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) {
537  this->LowerWidget(i);
538  }
539 
541  this->stations.ForceRebuild();
542  this->SetDirty();
543  break;
544 
545  case WID_STL_CARGOALL: {
546  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
547  this->LowerWidget(WID_STL_CARGOSTART + i);
548  }
550 
551  this->cargo_filter = _cargo_mask;
552  this->include_empty = true;
553  this->stations.ForceRebuild();
554  this->SetDirty();
555  break;
556  }
557 
558  case WID_STL_SORTBY: // flip sorting method asc/desc
559  this->stations.ToggleSortOrder();
560  this->SetDirty();
561  break;
562 
563  case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu
564  ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0);
565  break;
566 
568  if (_ctrl_pressed) {
569  this->include_empty = !this->include_empty;
571  } else {
572  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
573  this->RaiseWidget(WID_STL_CARGOSTART + i);
574  }
575 
576  this->cargo_filter = 0;
577  this->include_empty = true;
578 
580  }
581  this->stations.ForceRebuild();
582  this->SetDirty();
583  break;
584 
585  default:
586  if (widget >= WID_STL_CARGOSTART) { // change cargo_filter
587  /* Determine the selected cargo type */
588  const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
589 
590  if (_ctrl_pressed) {
591  ToggleBit(this->cargo_filter, cs->Index());
592  this->ToggleWidgetLoweredState(widget);
593  } else {
594  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
595  this->RaiseWidget(WID_STL_CARGOSTART + i);
596  }
598 
599  this->cargo_filter = 0;
600  this->include_empty = false;
601 
602  SetBit(this->cargo_filter, cs->Index());
603  this->LowerWidget(widget);
604  }
605  this->stations.ForceRebuild();
606  this->SetDirty();
607  }
608  break;
609  }
610  }
611 
612  virtual void OnDropdownSelect(int widget, int index)
613  {
614  if (this->stations.SortType() != index) {
615  this->stations.SetSortType(index);
616 
617  /* Display the current sort variant */
618  this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
619 
620  this->SetDirty();
621  }
622  }
623 
624  virtual void OnGameTick()
625  {
626  if (this->stations.NeedResort()) {
627  DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number);
628  this->SetDirty();
629  }
630  }
631 
632  virtual void OnResize()
633  {
635  }
636 
642  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
643  {
644  if (data == 0) {
645  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
646  this->stations.ForceRebuild();
647  } else {
648  this->stations.ForceResort();
649  }
650  }
651 };
652 
653 Listing CompanyStationsWindow::last_sorting = {false, 0};
654 byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
655 bool CompanyStationsWindow::include_empty = true;
656 const CargoTypes CompanyStationsWindow::cargo_filter_max = ALL_CARGOTYPES;
657 CargoTypes CompanyStationsWindow::cargo_filter = ALL_CARGOTYPES;
658 const Station *CompanyStationsWindow::last_station = NULL;
659 
660 /* Available station sorting functions */
661 GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
668 };
669 
670 /* Names of the sorting functions */
671 const StringID CompanyStationsWindow::sorter_names[] = {
672  STR_SORT_BY_NAME,
673  STR_SORT_BY_FACILITY,
674  STR_SORT_BY_WAITING_TOTAL,
675  STR_SORT_BY_WAITING_AVAILABLE,
676  STR_SORT_BY_RATING_MAX,
677  STR_SORT_BY_RATING_MIN,
679 };
680 
686 static NWidgetBase *CargoWidgets(int *biggest_index)
687 {
688  NWidgetHorizontal *container = new NWidgetHorizontal();
689 
690  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
691  NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
692  panel->SetMinimalSize(14, 11);
693  panel->SetResize(0, 0);
694  panel->SetFill(0, 1);
695  panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
696  container->Add(panel);
697  }
699  return container;
700 }
701 
702 static const NWidgetPart _nested_company_stations_widgets[] = {
704  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
705  NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
706  NWidget(WWT_SHADEBOX, COLOUR_GREY),
707  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
708  NWidget(WWT_STICKYBOX, COLOUR_GREY),
709  EndContainer(),
711  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),
712  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),
713  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),
714  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),
715  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),
716  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1),
717  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(),
719  NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(),
720  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1),
721  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
722  EndContainer(),
724  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
725  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten.
726  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
727  EndContainer(),
729  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(),
732  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
733  EndContainer(),
734  EndContainer(),
735 };
736 
737 static WindowDesc _company_stations_desc(
738  WDP_AUTO, "list_stations", 358, 162,
740  0,
741  _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets)
742 );
743 
750 {
751  if (!Company::IsValidID(company)) return;
752 
753  AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
754 }
755 
756 static const NWidgetPart _nested_station_view_widgets[] = {
758  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
759  NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
760  NWidget(WWT_SHADEBOX, COLOUR_GREY),
761  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
762  NWidget(WWT_STICKYBOX, COLOUR_GREY),
763  EndContainer(),
765  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
766  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
767  EndContainer(),
769  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0),
770  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
771  EndContainer(),
775  EndContainer(),
779  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
780  SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
781  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1),
782  SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
783  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
784  SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
785  EndContainer(),
786  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
787  SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
788  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
789  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
790  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
791  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
792  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
793  EndContainer(),
794 };
795 
805 static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
806 {
807  int width = ScaleGUITrad(10);
808  uint num = min((waiting + (width / 2)) / width, (right - left) / width); // maximum is width / 10 icons so it won't overflow
809  if (num == 0) return;
810 
811  SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon();
812 
813  int x = _current_text_dir == TD_RTL ? left : right - num * width;
814  do {
815  DrawSprite(sprite, PAL_NONE, x, y);
816  x += width;
817  } while (--num);
818 }
819 
820 enum SortOrder {
821  SO_DESCENDING,
822  SO_ASCENDING
823 };
824 
825 class CargoDataEntry;
826 
833 };
834 
835 class CargoSorter {
836 public:
837  CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {}
838  CargoSortType GetSortType() {return this->type;}
839  bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
840 
841 private:
842  CargoSortType type;
843  SortOrder order;
844 
845  template<class Tid>
846  bool SortId(Tid st1, Tid st2) const;
847  bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
848  bool SortStation (StationID st1, StationID st2) const;
849 };
850 
851 typedef std::set<CargoDataEntry *, CargoSorter> CargoDataSet;
852 
859 public:
860  CargoDataEntry();
861  ~CargoDataEntry();
862 
868  CargoDataEntry *InsertOrRetrieve(StationID station)
869  {
870  return this->InsertOrRetrieve<StationID>(station);
871  }
872 
879  {
880  return this->InsertOrRetrieve<CargoID>(cargo);
881  }
882 
883  void Update(uint count);
884 
889  void Remove(StationID station)
890  {
891  CargoDataEntry t(station);
892  this->Remove(&t);
893  }
894 
899  void Remove(CargoID cargo)
900  {
901  CargoDataEntry t(cargo);
902  this->Remove(&t);
903  }
904 
910  CargoDataEntry *Retrieve(StationID station) const
911  {
912  CargoDataEntry t(station);
913  return this->Retrieve(this->children->find(&t));
914  }
915 
922  {
923  CargoDataEntry t(cargo);
924  return this->Retrieve(this->children->find(&t));
925  }
926 
927  void Resort(CargoSortType type, SortOrder order);
928 
932  StationID GetStation() const { return this->station; }
933 
937  CargoID GetCargo() const { return this->cargo; }
938 
942  uint GetCount() const { return this->count; }
943 
947  CargoDataEntry *GetParent() const { return this->parent; }
948 
952  uint GetNumChildren() const { return this->num_children; }
953 
957  CargoDataSet::iterator Begin() const { return this->children->begin(); }
958 
962  CargoDataSet::iterator End() const { return this->children->end(); }
963 
967  bool HasTransfers() const { return this->transfers; }
968 
972  void SetTransfers(bool value) { this->transfers = value; }
973 
974  void Clear();
975 private:
976 
977  CargoDataEntry(StationID st, uint c, CargoDataEntry *p);
978  CargoDataEntry(CargoID car, uint c, CargoDataEntry *p);
979  CargoDataEntry(StationID st);
980  CargoDataEntry(CargoID car);
981 
982  CargoDataEntry *Retrieve(CargoDataSet::iterator i) const;
983 
984  template<class Tid>
985  CargoDataEntry *InsertOrRetrieve(Tid s);
986 
987  void Remove(CargoDataEntry *comp);
988  void IncrementSize();
989 
991  const union {
992  StationID station;
993  struct {
995  bool transfers;
996  };
997  };
999  uint count;
1000  CargoDataSet *children;
1001 };
1002 
1003 CargoDataEntry::CargoDataEntry() :
1004  parent(NULL),
1005  station(INVALID_STATION),
1006  num_children(0),
1007  count(0),
1008  children(new CargoDataSet(CargoSorter(ST_CARGO_ID)))
1009 {}
1010 
1011 CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) :
1012  parent(parent),
1013  cargo(cargo),
1014  num_children(0),
1015  count(count),
1016  children(new CargoDataSet)
1017 {}
1018 
1019 CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) :
1020  parent(parent),
1021  station(station),
1022  num_children(0),
1023  count(count),
1024  children(new CargoDataSet)
1025 {}
1026 
1027 CargoDataEntry::CargoDataEntry(StationID station) :
1028  parent(NULL),
1029  station(station),
1030  num_children(0),
1031  count(0),
1032  children(NULL)
1033 {}
1034 
1035 CargoDataEntry::CargoDataEntry(CargoID cargo) :
1036  parent(NULL),
1037  cargo(cargo),
1038  num_children(0),
1039  count(0),
1040  children(NULL)
1041 {}
1042 
1043 CargoDataEntry::~CargoDataEntry()
1044 {
1045  this->Clear();
1046  delete this->children;
1047 }
1048 
1053 {
1054  if (this->children != NULL) {
1055  for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) {
1056  assert(*i != this);
1057  delete *i;
1058  }
1059  this->children->clear();
1060  }
1061  if (this->parent != NULL) this->parent->count -= this->count;
1062  this->count = 0;
1063  this->num_children = 0;
1064 }
1065 
1073 {
1074  CargoDataSet::iterator i = this->children->find(child);
1075  if (i != this->children->end()) {
1076  delete *i;
1077  this->children->erase(i);
1078  }
1079 }
1080 
1087 template<class Tid>
1089 {
1090  CargoDataEntry tmp(child_id);
1091  CargoDataSet::iterator i = this->children->find(&tmp);
1092  if (i == this->children->end()) {
1093  IncrementSize();
1094  return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first);
1095  } else {
1096  CargoDataEntry *ret = *i;
1097  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1098  return ret;
1099  }
1100 }
1101 
1108 {
1109  this->count += count;
1110  if (this->parent != NULL) this->parent->Update(count);
1111 }
1112 
1117 {
1118  ++this->num_children;
1119  if (this->parent != NULL) this->parent->IncrementSize();
1120 }
1121 
1122 void CargoDataEntry::Resort(CargoSortType type, SortOrder order)
1123 {
1124  CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order));
1125  delete this->children;
1126  this->children = new_subs;
1127 }
1128 
1129 CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const
1130 {
1131  if (i == this->children->end()) {
1132  return NULL;
1133  } else {
1134  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1135  return *i;
1136  }
1137 }
1138 
1139 bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1140 {
1141  switch (this->type) {
1142  case ST_STATION_ID:
1143  return this->SortId<StationID>(cd1->GetStation(), cd2->GetStation());
1144  case ST_CARGO_ID:
1145  return this->SortId<CargoID>(cd1->GetCargo(), cd2->GetCargo());
1146  case ST_COUNT:
1147  return this->SortCount(cd1, cd2);
1148  case ST_STATION_STRING:
1149  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1150  default:
1151  NOT_REACHED();
1152  }
1153 }
1154 
1155 template<class Tid>
1156 bool CargoSorter::SortId(Tid st1, Tid st2) const
1157 {
1158  return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1;
1159 }
1160 
1161 bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1162 {
1163  uint c1 = cd1->GetCount();
1164  uint c2 = cd2->GetCount();
1165  if (c1 == c2) {
1166  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1167  } else if (this->order == SO_ASCENDING) {
1168  return c1 < c2;
1169  } else {
1170  return c2 < c1;
1171  }
1172 }
1173 
1174 bool CargoSorter::SortStation(StationID st1, StationID st2) const
1175 {
1176  static char buf1[MAX_LENGTH_STATION_NAME_CHARS];
1177  static char buf2[MAX_LENGTH_STATION_NAME_CHARS];
1178 
1179  if (!Station::IsValidID(st1)) {
1180  return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2);
1181  } else if (!Station::IsValidID(st2)) {
1182  return order == SO_DESCENDING;
1183  }
1184 
1185  SetDParam(0, st1);
1186  GetString(buf1, STR_STATION_NAME, lastof(buf1));
1187  SetDParam(0, st2);
1188  GetString(buf2, STR_STATION_NAME, lastof(buf2));
1189 
1190  int res = strnatcmp(buf1, buf2); // Sort by name (natural sorting).
1191  if (res == 0) {
1192  return this->SortId(st1, st2);
1193  } else {
1194  return (this->order == SO_ASCENDING) ? res < 0 : res > 0;
1195  }
1196 }
1197 
1201 struct StationViewWindow : public Window {
1205  struct RowDisplay {
1206  RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {}
1207  RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {}
1208 
1213  union {
1217  StationID next_station;
1218 
1223  };
1224  };
1225 
1226  typedef std::vector<RowDisplay> CargoDataVector;
1227 
1228  static const int NUM_COLUMNS = 4;
1229 
1234  INV_FLOWS = 0x100,
1235  INV_CARGO = 0x200
1236  };
1237 
1241  enum Grouping {
1246  };
1247 
1251  enum Mode {
1253  MODE_PLANNED
1254  };
1255 
1259  Scrollbar *vscroll;
1260 
1263  ALH_RATING = 13,
1264  ALH_ACCEPTS = 3,
1265  };
1266 
1267  static const StringID _sort_names[];
1268  static const StringID _group_names[];
1269 
1276  CargoSortType sortings[NUM_COLUMNS];
1277 
1279  SortOrder sort_orders[NUM_COLUMNS];
1280 
1284  Grouping groupings[NUM_COLUMNS];
1285 
1288  CargoDataVector displayed_rows;
1289 
1290  StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc),
1291  scroll_to_row(INT_MAX), grouping_index(0)
1292  {
1293  this->rating_lines = ALH_RATING;
1294  this->accepts_lines = ALH_ACCEPTS;
1295 
1296  this->CreateNestedTree();
1297  this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
1298  /* Nested widget tree creation is done in two steps to ensure that this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */
1299  this->FinishInitNested(window_number);
1300 
1301  this->groupings[0] = GR_CARGO;
1302  this->sortings[0] = ST_AS_GROUPING;
1303  this->SelectGroupBy(_settings_client.gui.station_gui_group_order);
1304  this->SelectSortBy(_settings_client.gui.station_gui_sort_by);
1305  this->sort_orders[0] = SO_ASCENDING;
1306  this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order);
1307  this->owner = Station::Get(window_number)->owner;
1308  }
1309 
1311  {
1312  DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->window_number).Pack(), false);
1313  DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).Pack(), false);
1314  DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).Pack(), false);
1315  DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).Pack(), false);
1316  }
1317 
1328  void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count)
1329  {
1330  if (count == 0) return;
1331  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1332  const CargoDataEntry *expand = &this->expanded_rows;
1333  for (int i = 0; i < NUM_COLUMNS && expand != NULL; ++i) {
1334  switch (groupings[i]) {
1335  case GR_CARGO:
1336  assert(i == 0);
1337  data = data->InsertOrRetrieve(cargo);
1338  data->SetTransfers(source != this->window_number);
1339  expand = expand->Retrieve(cargo);
1340  break;
1341  case GR_SOURCE:
1342  if (auto_distributed || source != this->window_number) {
1343  data = data->InsertOrRetrieve(source);
1344  expand = expand->Retrieve(source);
1345  }
1346  break;
1347  case GR_NEXT:
1348  if (auto_distributed) {
1349  data = data->InsertOrRetrieve(next);
1350  expand = expand->Retrieve(next);
1351  }
1352  break;
1353  case GR_DESTINATION:
1354  if (auto_distributed) {
1355  data = data->InsertOrRetrieve(dest);
1356  expand = expand->Retrieve(dest);
1357  }
1358  break;
1359  }
1360  }
1361  data->Update(count);
1362  }
1363 
1364  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
1365  {
1366  switch (widget) {
1367  case WID_SV_WAITING:
1368  resize->height = FONT_HEIGHT_NORMAL;
1369  size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM;
1370  this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
1371  break;
1372 
1374  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;
1375  break;
1376 
1377  case WID_SV_CLOSE_AIRPORT:
1378  if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) {
1379  /* Hide 'Close Airport' button if no airport present. */
1380  size->width = 0;
1381  resize->width = 0;
1382  fill->width = 0;
1383  }
1384  break;
1385  }
1386  }
1387 
1388  virtual void OnPaint()
1389  {
1390  const Station *st = Station::Get(this->window_number);
1392  BuildCargoList(&cargo, st);
1393 
1394  this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar
1395 
1396  /* disable some buttons */
1397  this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company);
1398  this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN));
1399  this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
1400  this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK));
1401  this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT));
1402  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
1403  this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0);
1404 
1405  this->DrawWidgets();
1406 
1407  if (!this->IsShaded()) {
1408  /* Draw 'accepted cargo' or 'cargo ratings'. */
1409  const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SV_ACCEPT_RATING_LIST);
1410  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)};
1411  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1412  int lines = this->DrawAcceptedCargo(r);
1413  if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window.
1414  this->accepts_lines = lines;
1415  this->ReInit();
1416  return;
1417  }
1418  } else {
1419  int lines = this->DrawCargoRatings(r);
1420  if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window.
1421  this->rating_lines = lines;
1422  this->ReInit();
1423  return;
1424  }
1425  }
1426 
1427  /* Draw arrow pointing up/down for ascending/descending sorting */
1428  this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN);
1429 
1430  int pos = this->vscroll->GetPosition();
1431 
1432  int maxrows = this->vscroll->GetCapacity();
1433 
1434  displayed_rows.clear();
1435 
1436  /* Draw waiting cargo. */
1437  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SV_WAITING);
1438  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)};
1439  this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0);
1440  scroll_to_row = INT_MAX;
1441  }
1442  }
1443 
1444  virtual void SetStringParameters(int widget) const
1445  {
1446  const Station *st = Station::Get(this->window_number);
1447  SetDParam(0, st->index);
1448  SetDParam(1, st->facilities);
1449  }
1450 
1457  {
1458  const Station *st = Station::Get(this->window_number);
1459  CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i);
1460  cargo_entry->Clear();
1461 
1462  const FlowStatMap &flows = st->goods[i].flows;
1463  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1464  StationID from = it->first;
1465  CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from);
1466  const FlowStat::SharesMap *shares = it->second.GetShares();
1467  uint32 prev_count = 0;
1468  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1469  StationID via = flow_it->second;
1470  CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via);
1471  if (via == this->window_number) {
1472  via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count);
1473  } else {
1474  EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry);
1475  }
1476  prev_count = flow_it->first;
1477  }
1478  }
1479  }
1480 
1490  void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest)
1491  {
1492  if (Station::IsValidID(next) && Station::IsValidID(source)) {
1493  CargoDataEntry tmp;
1494  const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows;
1495  FlowStatMap::const_iterator map_it = flowmap.find(source);
1496  if (map_it != flowmap.end()) {
1497  const FlowStat::SharesMap *shares = map_it->second.GetShares();
1498  uint32 prev_count = 0;
1499  for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) {
1500  tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
1501  prev_count = i->first;
1502  }
1503  }
1504 
1505  if (tmp.GetCount() == 0) {
1506  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1507  } else {
1508  uint sum_estimated = 0;
1509  while (sum_estimated < count) {
1510  for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) {
1511  CargoDataEntry *child = *i;
1512  uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount());
1513  if (estimate == 0) estimate = 1;
1514 
1515  sum_estimated += estimate;
1516  if (sum_estimated > count) {
1517  estimate -= sum_estimated - count;
1518  sum_estimated = count;
1519  }
1520 
1521  if (estimate > 0) {
1522  if (child->GetStation() == next) {
1523  dest->InsertOrRetrieve(next)->Update(estimate);
1524  } else {
1525  EstimateDestinations(cargo, source, child->GetStation(), estimate, dest);
1526  }
1527  }
1528  }
1529 
1530  }
1531  }
1532  } else {
1533  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1534  }
1535  }
1536 
1544  {
1545  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1546  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1547  StationID from = it->first;
1548  const CargoDataEntry *source_entry = source_dest->Retrieve(from);
1549  const FlowStat::SharesMap *shares = it->second.GetShares();
1550  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1551  const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second);
1552  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1553  CargoDataEntry *dest_entry = *dest_it;
1554  ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount());
1555  }
1556  }
1557  }
1558  }
1559 
1567  {
1568  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1569  for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) {
1570  const CargoPacket *cp = *it;
1571  StationID next = it.GetKey();
1572 
1573  const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation());
1574  if (source_entry == NULL) {
1575  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1576  continue;
1577  }
1578 
1579  const CargoDataEntry *via_entry = source_entry->Retrieve(next);
1580  if (via_entry == NULL) {
1581  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1582  continue;
1583  }
1584 
1585  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1586  CargoDataEntry *dest_entry = *dest_it;
1587  uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount());
1588  this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val);
1589  }
1590  }
1591  this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount());
1592  }
1593 
1600  {
1601  for (CargoID i = 0; i < NUM_CARGO; i++) {
1602 
1603  if (this->cached_destinations.Retrieve(i) == NULL) {
1604  this->RecalcDestinations(i);
1605  }
1606 
1607  if (this->current_mode == MODE_WAITING) {
1608  this->BuildCargoList(i, st->goods[i].cargo, cargo);
1609  } else {
1610  this->BuildFlowList(i, st->goods[i].flows, cargo);
1611  }
1612  }
1613  }
1614 
1620  {
1621  std::list<StationID> stations;
1622  const CargoDataEntry *parent = data->GetParent();
1623  if (parent->GetParent() == NULL) {
1624  this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo()));
1625  return;
1626  }
1627 
1628  StationID next = data->GetStation();
1629  while (parent->GetParent()->GetParent() != NULL) {
1630  stations.push_back(parent->GetStation());
1631  parent = parent->GetParent();
1632  }
1633 
1634  CargoID cargo = parent->GetCargo();
1635  CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo);
1636  while (!stations.empty()) {
1637  filter = filter->Retrieve(stations.back());
1638  stations.pop_back();
1639  }
1640 
1641  this->displayed_rows.push_back(RowDisplay(filter, next));
1642  }
1643 
1652  StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any)
1653  {
1654  if (station == this->window_number) {
1655  return here;
1656  } else if (station == INVALID_STATION) {
1657  return any;
1658  } else if (station == NEW_STATION) {
1659  return STR_STATION_VIEW_RESERVED;
1660  } else {
1661  SetDParam(2, station);
1662  return other_station;
1663  }
1664  }
1665 
1673  StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column)
1674  {
1675  CargoDataEntry *parent = cd->GetParent();
1676  for (int i = column - 1; i > 0; --i) {
1677  if (this->groupings[i] == GR_DESTINATION) {
1678  if (parent->GetStation() == station) {
1679  return STR_STATION_VIEW_NONSTOP;
1680  } else {
1681  return STR_STATION_VIEW_VIA;
1682  }
1683  }
1684  parent = parent->GetParent();
1685  }
1686 
1687  if (this->groupings[column + 1] == GR_DESTINATION) {
1688  CargoDataSet::iterator begin = cd->Begin();
1689  CargoDataSet::iterator end = cd->End();
1690  if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) {
1691  return STR_STATION_VIEW_NONSTOP;
1692  } else {
1693  return STR_STATION_VIEW_VIA;
1694  }
1695  }
1696 
1697  return STR_STATION_VIEW_VIA;
1698  }
1699 
1710  int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID)
1711  {
1712  if (this->sortings[column] == ST_AS_GROUPING) {
1713  if (this->groupings[column] != GR_CARGO) {
1714  entry->Resort(ST_STATION_STRING, this->sort_orders[column]);
1715  }
1716  } else {
1717  entry->Resort(ST_COUNT, this->sort_orders[column]);
1718  }
1719  for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) {
1720  CargoDataEntry *cd = *i;
1721 
1722  Grouping grouping = this->groupings[column];
1723  if (grouping == GR_CARGO) cargo = cd->GetCargo();
1724  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1725 
1726  if (pos > -maxrows && pos <= 0) {
1727  StringID str = STR_EMPTY;
1728  int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL;
1729  SetDParam(0, cargo);
1730  SetDParam(1, cd->GetCount());
1731 
1732  if (this->groupings[column] == GR_CARGO) {
1733  str = STR_STATION_VIEW_WAITING_CARGO;
1734  DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y);
1735  } else {
1736  if (!auto_distributed) grouping = GR_SOURCE;
1737  StationID station = cd->GetStation();
1738 
1739  switch (grouping) {
1740  case GR_SOURCE:
1741  str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY);
1742  break;
1743  case GR_NEXT:
1744  str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY);
1745  if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column);
1746  break;
1747  case GR_DESTINATION:
1748  str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY);
1749  break;
1750  default:
1751  NOT_REACHED();
1752  }
1753  if (pos == -this->scroll_to_row && Station::IsValidID(station)) {
1754  ScrollMainWindowToTile(Station::Get(station)->xy);
1755  }
1756  }
1757 
1758  bool rtl = _current_text_dir == TD_RTL;
1759  int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width;
1760  int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width;
1761  int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT;
1762  int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT;
1763 
1764  DrawString(text_left, text_right, y, str);
1765 
1766  if (column < NUM_COLUMNS - 1) {
1767  const char *sym = NULL;
1768  if (cd->GetNumChildren() > 0) {
1769  sym = "-";
1770  } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) {
1771  sym = "+";
1772  } else {
1773  /* Only draw '+' if there is something to be shown. */
1774  const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo;
1775  if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) {
1776  sym = "+";
1777  }
1778  }
1779  if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW);
1780  }
1781  this->SetDisplayedRow(cd);
1782  }
1783  --pos;
1784  if (auto_distributed || column == 0) {
1785  pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo);
1786  }
1787  }
1788  return pos;
1789  }
1790 
1796  int DrawAcceptedCargo(const Rect &r) const
1797  {
1798  const Station *st = Station::Get(this->window_number);
1799 
1800  CargoTypes cargo_mask = 0;
1801  for (CargoID i = 0; i < NUM_CARGO; i++) {
1802  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i);
1803  }
1804  SetDParam(0, cargo_mask);
1805  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);
1806  return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1807  }
1808 
1814  int DrawCargoRatings(const Rect &r) const
1815  {
1816  const Station *st = Station::Get(this->window_number);
1817  int y = r.top + WD_FRAMERECT_TOP;
1818 
1819  if (st->town->exclusive_counter > 0) {
1820  SetDParam(0, st->town->exclusivity);
1821  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);
1822  y += WD_PAR_VSEP_WIDE;
1823  }
1824 
1825  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE);
1826  y += FONT_HEIGHT_NORMAL;
1827 
1828  const CargoSpec *cs;
1830  const GoodsEntry *ge = &st->goods[cs->Index()];
1831  if (!ge->HasRating()) continue;
1832 
1833  const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph);
1834  SetDParam(0, cs->name);
1835  SetDParam(1, lg != NULL ? lg->Monthly((*lg)[ge->node].Supply()) : 0);
1836  SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5));
1837  SetDParam(3, ToPercent8(ge->rating));
1838  DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING);
1839  y += FONT_HEIGHT_NORMAL;
1840  }
1841  return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1842  }
1843 
1849  template<class Tid>
1850  void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
1851  {
1852  if (filter->Retrieve(next) != NULL) {
1853  filter->Remove(next);
1854  } else {
1855  filter->InsertOrRetrieve(next);
1856  }
1857  }
1858 
1864  {
1865  if (row < 0 || (uint)row >= this->displayed_rows.size()) return;
1866  if (_ctrl_pressed) {
1867  this->scroll_to_row = row;
1868  } else {
1869  RowDisplay &display = this->displayed_rows[row];
1870  if (display.filter == &this->expanded_rows) {
1871  this->HandleCargoWaitingClick<CargoID>(display.filter, display.next_cargo);
1872  } else {
1873  this->HandleCargoWaitingClick<StationID>(display.filter, display.next_station);
1874  }
1875  }
1876  this->SetWidgetDirty(WID_SV_WAITING);
1877  }
1878 
1879  virtual void OnClick(Point pt, int widget, int click_count)
1880  {
1881  switch (widget) {
1882  case WID_SV_WAITING:
1883  this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition());
1884  break;
1885 
1886  case WID_SV_LOCATION:
1887  if (_ctrl_pressed) {
1888  ShowExtraViewPortWindow(Station::Get(this->window_number)->xy);
1889  } else {
1890  ScrollMainWindowToTile(Station::Get(this->window_number)->xy);
1891  }
1892  break;
1893 
1894  case WID_SV_ACCEPTS_RATINGS: {
1895  /* Swap between 'accepts' and 'ratings' view. */
1896  int height_change;
1897  NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS);
1898  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1899  nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view.
1900  height_change = this->rating_lines - this->accepts_lines;
1901  } else {
1902  nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view.
1903  height_change = this->accepts_lines - this->rating_lines;
1904  }
1905  this->ReInit(0, height_change * FONT_HEIGHT_NORMAL);
1906  break;
1907  }
1908 
1909  case WID_SV_RENAME:
1910  SetDParam(0, this->window_number);
1911  ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
1913  break;
1914 
1915  case WID_SV_CLOSE_AIRPORT:
1916  DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT);
1917  break;
1918 
1919  case WID_SV_TRAINS: // Show list of scheduled trains to this station
1920  case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station
1921  case WID_SV_SHIPS: // Show list of scheduled ships to this station
1922  case WID_SV_PLANES: { // Show list of scheduled aircraft to this station
1923  Owner owner = Station::Get(this->window_number)->owner;
1924  ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number);
1925  break;
1926  }
1927 
1928  case WID_SV_SORT_BY: {
1929  /* The initial selection is composed of current mode and
1930  * sorting criteria for columns 1, 2, and 3. Column 0 is always
1931  * sorted by cargo ID. The others can theoretically be sorted
1932  * by different things but there is no UI for that. */
1933  ShowDropDownMenu(this, _sort_names,
1934  this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0),
1935  WID_SV_SORT_BY, 0, 0);
1936  break;
1937  }
1938 
1939  case WID_SV_GROUP_BY: {
1940  ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
1941  break;
1942  }
1943 
1944  case WID_SV_SORT_ORDER: { // flip sorting method asc/desc
1945  this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING);
1946  this->SetTimeout();
1947  this->LowerWidget(WID_SV_SORT_ORDER);
1948  break;
1949  }
1950  }
1951  }
1952 
1957  void SelectSortOrder(SortOrder order)
1958  {
1959  this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order;
1960  _settings_client.gui.station_gui_sort_order = this->sort_orders[1];
1961  this->SetDirty();
1962  }
1963 
1968  void SelectSortBy(int index)
1969  {
1971  switch (_sort_names[index]) {
1972  case STR_STATION_VIEW_WAITING_STATION:
1973  this->current_mode = MODE_WAITING;
1974  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
1975  break;
1976  case STR_STATION_VIEW_WAITING_AMOUNT:
1977  this->current_mode = MODE_WAITING;
1978  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
1979  break;
1980  case STR_STATION_VIEW_PLANNED_STATION:
1981  this->current_mode = MODE_PLANNED;
1982  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
1983  break;
1984  case STR_STATION_VIEW_PLANNED_AMOUNT:
1985  this->current_mode = MODE_PLANNED;
1986  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
1987  break;
1988  default:
1989  NOT_REACHED();
1990  }
1991  /* Display the current sort variant */
1992  this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->widget_data = _sort_names[index];
1993  this->SetDirty();
1994  }
1995 
2000  void SelectGroupBy(int index)
2001  {
2002  this->grouping_index = index;
2004  this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->widget_data = _group_names[index];
2005  switch (_group_names[index]) {
2006  case STR_STATION_VIEW_GROUP_S_V_D:
2007  this->groupings[1] = GR_SOURCE;
2008  this->groupings[2] = GR_NEXT;
2009  this->groupings[3] = GR_DESTINATION;
2010  break;
2011  case STR_STATION_VIEW_GROUP_S_D_V:
2012  this->groupings[1] = GR_SOURCE;
2013  this->groupings[2] = GR_DESTINATION;
2014  this->groupings[3] = GR_NEXT;
2015  break;
2016  case STR_STATION_VIEW_GROUP_V_S_D:
2017  this->groupings[1] = GR_NEXT;
2018  this->groupings[2] = GR_SOURCE;
2019  this->groupings[3] = GR_DESTINATION;
2020  break;
2021  case STR_STATION_VIEW_GROUP_V_D_S:
2022  this->groupings[1] = GR_NEXT;
2023  this->groupings[2] = GR_DESTINATION;
2024  this->groupings[3] = GR_SOURCE;
2025  break;
2026  case STR_STATION_VIEW_GROUP_D_S_V:
2027  this->groupings[1] = GR_DESTINATION;
2028  this->groupings[2] = GR_SOURCE;
2029  this->groupings[3] = GR_NEXT;
2030  break;
2031  case STR_STATION_VIEW_GROUP_D_V_S:
2032  this->groupings[1] = GR_DESTINATION;
2033  this->groupings[2] = GR_NEXT;
2034  this->groupings[3] = GR_SOURCE;
2035  break;
2036  }
2037  this->SetDirty();
2038  }
2039 
2040  virtual void OnDropdownSelect(int widget, int index)
2041  {
2042  if (widget == WID_SV_SORT_BY) {
2043  this->SelectSortBy(index);
2044  } else {
2045  this->SelectGroupBy(index);
2046  }
2047  }
2048 
2049  virtual void OnQueryTextFinished(char *str)
2050  {
2051  if (str == NULL) return;
2052 
2053  DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), NULL, str);
2054  }
2055 
2056  virtual void OnResize()
2057  {
2059  }
2060 
2066  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2067  {
2068  if (gui_scope) {
2069  if (data >= 0 && data < NUM_CARGO) {
2070  this->cached_destinations.Remove((CargoID)data);
2071  } else {
2072  this->ReInit();
2073  }
2074  }
2075  }
2076 };
2077 
2079  STR_STATION_VIEW_WAITING_STATION,
2080  STR_STATION_VIEW_WAITING_AMOUNT,
2081  STR_STATION_VIEW_PLANNED_STATION,
2082  STR_STATION_VIEW_PLANNED_AMOUNT,
2084 };
2085 
2087  STR_STATION_VIEW_GROUP_S_V_D,
2088  STR_STATION_VIEW_GROUP_S_D_V,
2089  STR_STATION_VIEW_GROUP_V_S_D,
2090  STR_STATION_VIEW_GROUP_V_D_S,
2091  STR_STATION_VIEW_GROUP_D_S_V,
2092  STR_STATION_VIEW_GROUP_D_V_S,
2094 };
2095 
2096 static WindowDesc _station_view_desc(
2097  WDP_AUTO, "view_station", 249, 117,
2099  0,
2100  _nested_station_view_widgets, lengthof(_nested_station_view_widgets)
2101 );
2102 
2109 {
2110  AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
2111 }
2112 
2116  StationID station;
2117 };
2118 
2119 static SmallVector<TileAndStation, 8> _deleted_stations_nearby;
2120 static SmallVector<StationID, 8> _stations_nearby_list;
2121 
2129 template <class T>
2130 static bool AddNearbyStation(TileIndex tile, void *user_data)
2131 {
2132  TileArea *ctx = (TileArea *)user_data;
2133 
2134  /* First check if there were deleted stations here */
2135  for (uint i = 0; i < _deleted_stations_nearby.Length(); i++) {
2136  TileAndStation *ts = _deleted_stations_nearby.Get(i);
2137  if (ts->tile == tile) {
2138  *_stations_nearby_list.Append() = _deleted_stations_nearby[i].station;
2139  _deleted_stations_nearby.Erase(ts);
2140  i--;
2141  }
2142  }
2143 
2144  /* Check if own station and if we stay within station spread */
2145  if (!IsTileType(tile, MP_STATION)) return false;
2146 
2147  StationID sid = GetStationIndex(tile);
2148 
2149  /* This station is (likely) a waypoint */
2150  if (!T::IsValidID(sid)) return false;
2151 
2152  T *st = T::Get(sid);
2153  if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false;
2154 
2155  if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
2156  *_stations_nearby_list.Append() = sid;
2157  }
2158 
2159  return false; // We want to include *all* nearby stations
2160 }
2161 
2171 template <class T>
2172 static const T *FindStationsNearby(TileArea ta, bool distant_join)
2173 {
2174  TileArea ctx = ta;
2175 
2176  _stations_nearby_list.Clear();
2177  _deleted_stations_nearby.Clear();
2178 
2179  /* Check the inside, to return, if we sit on another station */
2180  TILE_AREA_LOOP(t, ta) {
2181  if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
2182  }
2183 
2184  /* Look for deleted stations */
2185  const BaseStation *st;
2186  FOR_ALL_BASE_STATIONS(st) {
2187  if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
2188  /* Include only within station spread (yes, it is strictly less than) */
2189  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) {
2190  TileAndStation *ts = _deleted_stations_nearby.Append();
2191  ts->tile = st->xy;
2192  ts->station = st->index;
2193 
2194  /* Add the station when it's within where we're going to build */
2195  if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
2196  IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
2197  AddNearbyStation<T>(st->xy, &ctx);
2198  }
2199  }
2200  }
2201  }
2202 
2203  /* Only search tiles where we have a chance to stay within the station spread.
2204  * The complete check needs to be done in the callback as we don't know the
2205  * extent of the found station, yet. */
2206  if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL;
2207  uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1;
2208 
2209  TileIndex tile = TileAddByDir(ctx.tile, DIR_N);
2210  CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
2211 
2212  return NULL;
2213 }
2214 
2215 static const NWidgetPart _nested_select_station_widgets[] = {
2217  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
2218  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2219  NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
2220  EndContainer(),
2222  NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(),
2224  NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR),
2225  NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
2226  EndContainer(),
2227  EndContainer(),
2228 };
2229 
2234 template <class T>
2238  Scrollbar *vscroll;
2239 
2240  SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) :
2241  Window(desc),
2242  select_station_cmd(cmd),
2243  area(ta)
2244  {
2245  this->CreateNestedTree();
2246  this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
2247  this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
2248  this->FinishInitNested(0);
2249  this->OnInvalidateData(0);
2250  }
2251 
2252  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
2253  {
2254  if (widget != WID_JS_PANEL) return;
2255 
2256  /* Determine the widest string */
2257  Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
2258  for (uint i = 0; i < _stations_nearby_list.Length(); i++) {
2259  const T *st = T::Get(_stations_nearby_list[i]);
2260  SetDParam(0, st->index);
2261  SetDParam(1, st->facilities);
2262  d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION));
2263  }
2264 
2265  resize->height = d.height;
2266  d.height *= 5;
2268  d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2269  *size = d;
2270  }
2271 
2272  virtual void DrawWidget(const Rect &r, int widget) const
2273  {
2274  if (widget != WID_JS_PANEL) return;
2275 
2276  uint y = r.top + WD_FRAMERECT_TOP;
2277  if (this->vscroll->GetPosition() == 0) {
2278  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);
2279  y += this->resize.step_height;
2280  }
2281 
2282  for (uint i = max<uint>(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.Length(); ++i, y += this->resize.step_height) {
2283  /* Don't draw anything if it extends past the end of the window. */
2284  if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break;
2285 
2286  const T *st = T::Get(_stations_nearby_list[i - 1]);
2287  SetDParam(0, st->index);
2288  SetDParam(1, st->facilities);
2289  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);
2290  }
2291  }
2292 
2293  virtual void OnClick(Point pt, int widget, int click_count)
2294  {
2295  if (widget != WID_JS_PANEL) return;
2296 
2297  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2298  bool distant_join = (st_index > 0);
2299  if (distant_join) st_index--;
2300 
2301  if (distant_join && st_index >= _stations_nearby_list.Length()) return;
2302 
2303  /* Insert station to be joined into stored command */
2304  SB(this->select_station_cmd.p2, 16, 16,
2305  (distant_join ? _stations_nearby_list[st_index] : NEW_STATION));
2306 
2307  /* Execute stored Command */
2308  DoCommandP(&this->select_station_cmd);
2309 
2310  /* Close Window; this might cause double frees! */
2312  }
2313 
2314  virtual void OnRealtimeTick(uint delta_ms)
2315  {
2316  if (_thd.dirty & 2) {
2317  _thd.dirty &= ~2;
2318  this->SetDirty();
2319  }
2320  }
2321 
2322  virtual void OnResize()
2323  {
2324  this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
2325  }
2326 
2332  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2333  {
2334  if (!gui_scope) return;
2335  FindStationsNearby<T>(this->area, true);
2336  this->vscroll->SetCount(_stations_nearby_list.Length() + 1);
2337  this->SetDirty();
2338  }
2339 };
2340 
2341 static WindowDesc _select_station_desc(
2342  WDP_AUTO, "build_station_join", 200, 180,
2345  _nested_select_station_widgets, lengthof(_nested_select_station_widgets)
2346 );
2347 
2348 
2356 template <class T>
2357 static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta)
2358 {
2359  /* Only show selection if distant join is enabled in the settings */
2360  if (!_settings_game.station.distant_join_stations) return false;
2361 
2362  /* If a window is already opened and we didn't ctrl-click,
2363  * return true (i.e. just flash the old window) */
2364  Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
2365  if (selection_window != NULL) {
2366  /* Abort current distant-join and start new one */
2367  delete selection_window;
2369  }
2370 
2371  /* only show the popup, if we press ctrl */
2372  if (!_ctrl_pressed) return false;
2373 
2374  /* Now check if we could build there */
2375  if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false;
2376 
2377  /* Test for adjacent station or station below selection.
2378  * If adjacent-stations is disabled and we are building next to a station, do not show the selection window.
2379  * but join the other station immediately. */
2380  const T *st = FindStationsNearby<T>(ta, false);
2381  return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0);
2382 }
2383 
2390 template <class T>
2392 {
2393  if (StationJoinerNeeded<T>(cmd, ta)) {
2395  new SelectStationWindow<T>(&_select_station_desc, cmd, ta);
2396  } else {
2397  DoCommandP(&cmd);
2398  }
2399 }
2400 
2407 {
2408  ShowSelectBaseStationIfNeeded<Station>(cmd, ta);
2409 }
2410 
2417 {
2418  ShowSelectBaseStationIfNeeded<Waypoint>(cmd, ta);
2419 }
&#39;Location&#39; button.
Functions related to OTTD&#39;s strings.
virtual void OnClick(Point pt, int widget, int click_count)
A click with the left mouse button has been made on the window.
void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
Expand or collapse a specific row.
List of scheduled road vehs button.
virtual void OnRealtimeTick(uint delta_ms)
Called periodically.
Base types for having sorted lists in GUIs.
virtual void OnInvalidateData(int data=0, bool gui_scope=true)
Some data on this window has become invalid.
Draw all cargoes.
Definition: station_gui.h:24
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:77
Definition of stuff that is very close to a company, like the company struct itself.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:257
int DrawAcceptedCargo(const Rect &r) const
Draw accepted cargo in the WID_SV_ACCEPT_RATING_LIST widget.
static uint minu(const uint a, const uint b)
Returns the minimum of two unsigned integers.
Definition: math_func.hpp:70
Select station (when joining stations); Window numbers:
Definition: window_type.h:237
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.
Horizontally center the text.
Definition: gfx_func.h:99
The information about a vehicle list.
Definition: vehiclelist.h:31
ResizeInfo resize
Resize information.
Definition: window_gui.h:324
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition: cargotype.cpp:31
CargoID next_cargo
ID of the cargo belonging to the entry actually displayed if it&#39;s cargo.
static NWidgetPart SetResize(int16 dx, int16 dy)
Widget part function for setting the resize step.
Definition: widget_type.h:930
Window(WindowDesc *desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1851
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen...
Definition: gfx.cpp:113
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.
Definition: station_gui.cpp:88
Point pos
Location, in tile "units", of the northern tile of the selected area.
static NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
Definition: widget_type.h:1146
&#39;TRAIN&#39; button - list only facilities where is a railroad station.
void SetWidgetLoweredState(byte widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition: window_gui.h:455
open/close an airport to incoming aircraft
Definition: command_type.h:333
Window * parent
Parent window.
Definition: window_gui.h:339
High level window description.
Definition: window_gui.h:168
void SetMinimalSize(uint min_x, uint min_y)
Set minimal size of the widget.
Definition: widget.cpp:817
StationID next_station
ID of the station belonging to the entry actually displayed if it&#39;s to/from/via.
Functions and type for generating vehicle lists.
uint8 station_gui_group_order
the order of grouping cargo entries in the station gui
int left
x position of left edge of the window
Definition: window_gui.h:319
CargoList that is used for stations.
Definition: cargopacket.h:463
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:604
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.
CompanyByte exclusivity
which company has exclusivity
Definition: town.h:75
Scrollbar data structure.
Definition: widget_type.h:589
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:63
void ShowSelectStationIfNeeded(const CommandContainer &cmd, TileArea ta)
Show the station selection window when needed.
label for "group by"
Contains enums and function declarations connected with stations GUI.
void SetWidgetDirty(byte widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:581
CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted)
Get the acceptance of cargoes around the tile in 1/8.
Offset at top to draw the frame rectangular area.
Definition: window_gui.h:64
Functions related to debugging.
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
Draw only passenger class cargoes.
Definition: station_gui.h:22
Horizontal container.
Definition: widget_type.h:75
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1114
void Remove(StationID station)
Remove a child associated with the given station.
void SetSortFuncs(SortFunction *const *n_funcs)
Hand the array of sort function pointers to the sort list.
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1064
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:82
int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo=CT_INVALID)
Draw the given cargo entries in the station GUI.
Maximal number of cargo types in a game.
Definition: cargo_type.h:66
void RecalcDestinations(CargoID i)
Rebuild the cache for estimated destinations which is used to quickly show the "destination" entries ...
The main panel, list of stations.
Specification of a cargo type.
Definition: cargotype.h:56
bool IsInUse() const
Check whether the base station currently is in use; in use means that it is not scheduled for deletio...
&#39;Group by&#39; button
Point size
Size, in tile "units", of the white/red selection area.
static const StringID _group_names[]
Names of the grouping options in the dropdown.
void SelectGroupBy(int index)
Select a new grouping mode for the cargo view.
Manual distribution. No link graph calculations are run.
CargoDataEntry cached_destinations
Cache for the flows passing through this station.
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
uint32 p2
parameter p2.
Definition: command_type.h:478
uint TotalCount() const
Returns total count of cargo at the station, including cargo which is already reserved for loading...
Definition: cargopacket.h:541
void ShowCompanyStations(CompanyID company)
Opens window with list of company&#39;s stations.
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:207
virtual void SetStringParameters(int widget) const
Initialize string parameters for a widget.
void SelectSortBy(int index)
Select a new sort criterium for the cargo view.
int DivideApprox(int a, int b)
Deterministic approximate division.
Definition: math_func.cpp:59
int scroll_to_row
If set, scroll the main viewport to the station pointed to by this row.
uint num_children
the number of subentries belonging to this entry.
CargoDataSet::iterator End() const
Get an iterator pointing to the end of the set of children.
static bool IsInsideBS(const T x, const uint base, const uint size)
Checks if a value is between a window started at some base point.
Definition: math_func.hpp:250
byte station_spread
amount a station may spread
void Clear()
Remove all items from the list.
by station id
void ToggleWidgetLoweredState(byte widget_index)
Invert the lowered/raised status of a widget.
Definition: window_gui.h:465
void Compact()
Compact the list down to the smallest block size boundary.
List of scheduled planes button.
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:147
void BuildCargoList(CargoDataEntry *cargo, const Station *st)
Build up the cargo view for all cargoes.
Normal push-button (no toggle button) with custom drawing.
Definition: widget_type.h:103
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition: viewport.cpp:2220
Close box (at top-left of a window)
Definition: widget_type.h:69
virtual void DrawWidget(const Rect &r, int widget) const
Draw the contents of a nested widget.
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...
&#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:75
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
Invalidation
Type of data invalidation.
Simple vector template class.
CargoDataEntry * parent
the parent of this entry.
A row being displayed in the cargo view (as opposed to being "hidden" behind a plus sign)...
Stuff related to the text buffer GUI.
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
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
Update size and resize step of a widget in the window.
void SetTransfers(bool value)
Set the transfers state.
Group by cargo type.
CommandFlags GetCommandFlags(uint32 cmd)
Definition: command.cpp:383
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:26
The list of stations per company.
Town * town
The town this station is associated with.
bool HasRating() const
Does this cargo have a rating at this station?
Definition: station_base.h:273
void RaiseWidget(byte widget_index)
Marks a widget as raised.
Definition: window_gui.h:485
uint16 w
The width of the area.
Definition: tilearea_type.h:20
AcceptListHeight
Height of the WID_SV_ACCEPT_RATING_LIST widget for different views.
void CreateNestedTree(bool fill_nested=true)
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1812
Functions related to the vehicle&#39;s GUIs.
void SetListing(Listing l)
Import sort conditions.
Large amount of vertical space between two paragraphs of text.
Definition: window_gui.h:140
CargoDataVector displayed_rows
Parent entry of currently displayed rows (including collapsed ones).
StationSettings station
settings related to station management
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Definition: station_base.h:472
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
StringID name
Name of this type of cargo.
Definition: cargotype.h:71
virtual void OnGameTick()
Called once per (game) tick.
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.
List of waiting cargo.
&#39;Sort by&#39; button
T * Append(uint to_add=1)
Append an item and return it.
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:670
CompanyByte _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:46
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:910
Functions related to (drawing on) viewports.
void ForceRebuild()
Force that a rebuild is needed.
A connected component of a link graph.
Definition: linkgraph.h:40
Group by source of cargo ("from").
CargoDataEntry * InsertOrRetrieve(CargoID cargo)
Insert a new child or retrieve an existing child using a cargo ID as ID.
Data structure for an opened window.
Definition: window_gui.h:278
Invalid cargo type.
Definition: cargo_type.h:70
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:36
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1828
CargoDataSet * children
the children of this entry.
static const uint8 PC_GREEN
Green palette colour.
Definition: gfx_func.h:224
Station is a waypoint.
Definition: station_type.h:59
virtual void OnResize()
Called after the window got resized.
enable the &#39;Default&#39; button ("\0" is returned)
Definition: textbuf_gui.h:23
Aircraft vehicle type.
Definition: vehicle_type.h:29
void Add(NWidgetBase *wid)
Append widget wid to container.
Definition: widget.cpp:944
Functions related to low-level strings.
StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any)
Select the correct string for an entry referring to the specified station.
byte rating
Station rating for this cargo.
Definition: station_base.h:235
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.
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:152
static int CDECL StationNameSorter(const Station *const *a, const Station *const *b)
Sort stations by their name.
int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies)
Calculates and draws the accepted or supplied cargo around the selected tile(s)
Definition: station_gui.cpp:56
Scrollbar next to the main panel.
#define FONT_HEIGHT_SMALL
Height of characters in the small (FS_SMALL) font.
Definition: gfx_func.h:177
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:440
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) ...
Definition: widget_type.h:65
uint Length() const
Get the number of items in the list.
int GetScrolledRowFromWidget(int clickpos, const Window *const w, int widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:1959
virtual void OnDropdownSelect(int widget, int index)
A dropdown option associated to this window has been selected.
uint pos_y
Vertical position of top-left corner of the widget in the window.
Definition: widget_type.h:178
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:210
bool IsWidgetLowered(byte widget_index) const
Gets the lowered state of a widget.
Definition: window_gui.h:495
void SetDataTip(uint32 widget_data, StringID tool_tip)
Set data and tool tip of the nested widget.
Definition: widget.cpp:894
void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count)
Show a certain cargo entry characterized by source/next/dest station, cargo ID and amount of cargo at...
Listing GetListing() const
Export current sort conditions.
bool Contains(const T &item) const
Tests whether a item is present in the vector.
VehicleType
Available vehicle types.
Definition: vehicle_type.h:23
uint current_y
Current vertical size (after resizing).
Definition: widget_type.h:175
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition: map.cpp:191
North.
Sort descending.
Definition: window_gui.h:227
List of accepted cargoes / rating of cargoes.
Structure for buffering the build command when selecting a station to join.
Definition: command_type.h:475
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:180
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1014
void SetFill(uint fill_x, uint fill_y)
Set the filling of the widget from initial size.
Definition: widget.cpp:839
virtual void SetStringParameters(int widget) const
Initialize string parameters for a widget.
CargoID GetCargo() const
Get the cargo ID for this entry.
Station with truck stops.
Definition: station_type.h:55
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:76
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:947
&#39;Close airport&#39; button.
Container for cargo from the same location and time.
Definition: cargopacket.h:44
StationCoverageType
Types of cargo to display for station coverage.
Definition: station_gui.h:21
#define TILE_AREA_LOOP(var, ta)
A loop which iterates over the tiles of a TileArea.
Definition of base types and functions in a cross-platform compatible way.
StationID SourceStation() const
Gets the ID of the station where the cargo was loaded for the first time.
Definition: cargopacket.h:160
the length of the string is counted in characters
Definition: textbuf_gui.h:24
by cargo id
&#39;AIRPLANE&#39; button - list only facilities where is an airport.
int accepts_lines
Number of lines in the accepted cargo view.
#define TILE_ADDXY(tile, x, y)
Adds a given offset to a tile.
Definition: map_func.h:260
A number of safeguards to prevent using unsafe methods.
uint Monthly(uint base) const
Scale a value to its monthly equivalent, based on last compression.
Definition: linkgraph.h:518
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:247
bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data)
Function performing a search around a center tile and going outward, thus in circle.
Definition: map.cpp:260
static const uint64 AIRPORT_CLOSED_block
Dummy block for indicating a closed airport.
Definition: airport.h:129
bool HasTransfers() const
Has this entry transfers.
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:104
Base of waypoints.
Geometry functions.
rectangle (stations, depots, ...)
Simple depressed panel.
Definition: widget_type.h:50
static uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition: math_func.hpp:316
bool HasStationInUse(StationID station, bool include_company, CompanyID company)
Tests whether the company&#39;s vehicles have this station in orders.
virtual void OnClick(Point pt, int widget, int click_count)
A click with the left mouse button has been made on the window.
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:638
const Scrollbar * GetScrollbar(uint widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:311
Represents the covered area of e.g.
Definition: tilearea_type.h:18
void LowerWidget(byte widget_index)
Marks a widget as lowered.
Definition: window_gui.h:476
HighLightStyle drawstyle
Lower bits 0-3 are reserved for detailed highlight information.
CargoDataEntry expanded_rows
Parent entry of currently expanded rows.
uint GetNumChildren() const
Get the number of children for this entry.
void BuildFlowList(CargoID i, const FlowStatMap &flows, CargoDataEntry *cargo)
Build up the cargo view for PLANNED mode and a specific cargo.
Road vehicle list; Window numbers:
Definition: window_type.h:309
Caption of the window.
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new &#39;real&#39; widget.
Definition: widget_type.h:1114
void Clear()
Delete all subentries, reset count and num_children and adapt parent&#39;s count.
The tile has no ownership.
Definition: company_type.h:27
Offset at bottom to draw the frame rectangular area.
Definition: window_gui.h:65
by amount of cargo
static DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags)
Extracts the DC flags needed for DoCommand from the flags returned by GetCommandFlags.
Definition: command_func.h:62
Baseclass for nested widgets.
Definition: widget_type.h:126
void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest)
Estimate the amounts of cargo per final destination for a given cargo, source station and next hop an...
Station view; Window numbers:
Definition: window_type.h:340
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:500
StationFacilityByte facilities
The facilities that this station has.
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:531
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
Road vehicle type.
Definition: vehicle_type.h:27
void BuildCargoList(CargoID i, const StationCargoList &packets, CargoDataEntry *cargo)
Build up the cargo view for WAITING mode and a specific cargo.
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:42
uint pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:177
Types related to the station widgets.
int DrawCargoRatings(const Rect &r) const
Draw cargo ratings in the WID_SV_ACCEPT_RATING_LIST widget.
#define FOR_ALL_SORTED_STANDARD_CARGOSPECS(var)
Loop header for iterating over &#39;real&#39; cargoes, sorted by name.
Definition: cargotype.h:173
static bool IsCargoInClass(CargoID c, CargoClass cc)
Does cargo c have cargo class cc?
Definition: cargotype.h:150
static int CDECL StationTypeSorter(const Station *const *a, const Station *const *b)
Sort stations by their type.
Station with a dock.
Definition: station_type.h:58
Horizontal container.
Definition: widget_type.h:454
void SetSortType(uint8 n_type)
Set the sorttype of the list.
bool Sort(SortFunction *compare)
Sort the list.
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:658
static int CDECL StationWaitingTotalSorter(const Station *const *a, const Station *const *b)
Sort stations by their waiting cargo.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:18
bool Failed() const
Did this command fail?
Definition: command_type.h:161
StationID station
StationID.
&#39;BUS&#39; button - list only facilities where is a bus stop.
uint ReservedCount() const
Returns sum of cargo reserved for loading onto vehicles.
Definition: cargopacket.h:531
by station name
Station list; Window numbers:
Definition: window_type.h:297
Ship vehicle type.
Definition: vehicle_type.h:28
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:968
void ShowExtraViewPortWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:36
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:700
virtual void OnQueryTextFinished(char *str)
The query window opened from this window has closed.
static int CDECL StationWaitingAvailableSorter(const Station *const *a, const Station *const *b)
Sort stations by their available waiting cargo.
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:19
uint16 GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:613
OwnerByte owner
The owner of this station.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
The StationView window.
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:40
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1146
CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
Get the cargo types being produced around the tile (in a rectangle).
virtual void DrawWidget(const Rect &r, int widget) const
Draw the contents of a nested widget.
CargoSortType
void SetResize(uint resize_x, uint resize_y)
Set resize step of the widget.
Definition: widget.cpp:850
Functions related to companies.
uint8 _sorted_standard_cargo_specs_size
Number of standard cargo specifications stored at the _sorted_cargo_specs array.
Definition: cargotype.cpp:137
virtual void OnInvalidateData(int data=0, bool gui_scope=true)
Some data on this window has become invalid.
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:29
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:196
StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column)
Determine if we need to show the special "non-stop" string.
&#39;SHIP&#39; button - list only facilities where is a dock.
&#39;Rename&#39; button.
List of scheduled ships button.
static uint MapSize()
Get the size of the map.
Definition: map_func.h:94
Mode current_mode
Currently selected display mode of cargo view.
Class for storing amounts of cargo.
Definition: cargo_type.h:83
Show cargo waiting at the station.
static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
Draws icons of waiting cargo in the StationView window.
&#39;ALL&#39; button - list all facilities.
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:27
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
Update size and resize step of a widget in the window.
SpriteID GetCargoIcon() const
Get sprite for showing cargo of this type.
Definition: cargotype.cpp:122
GUISettings gui
settings related to the GUI
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:580
static const T * FindStationsNearby(TileArea ta, bool distant_join)
Circulate around the to-be-built station to find stations we could join.
uint32 SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:19
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:118
StationCargoPacketMap ::const_iterator ConstIterator
The const iterator for our container.
Definition: cargopacket.h:222
Ships list; Window numbers:
Definition: window_type.h:315
TextColour GetContrastColour(uint8 background, uint8 threshold)
Determine a contrasty text colour for a coloured background.
Definition: gfx.cpp:1118
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:80
Draw all non-passenger class cargoes.
Definition: station_gui.h:23
static uint ToPercent8(uint i)
Converts a "fract" value 0..255 to "percent" value 0..100.
Definition: math_func.hpp:289
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:52
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here...
static int CDECL StationRatingMaxSorter(const Station *const *a, const Station *const *b)
Sort stations by their rating.
Sort ascending.
Definition: window_gui.h:226
static NWidgetBase * CargoWidgets(int *biggest_index)
Make a horizontal row of cargo buttons, starting at widget WID_STL_CARGOSTART.
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:217
CargoDataEntry * Retrieve(CargoID cargo) const
Retrieve a child for the given cargo.
Vertical container.
Definition: widget_type.h:77
int CDECL SortFunction(const T *, const T *)
Signature of sort function.
Definition: sortlist_type.h:52
CargoDataEntry * Retrieve(StationID station) const
Retrieve a child for the given station.
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
TileIndex xy
Base tile of the station.
void SetDisplayedRow(const CargoDataEntry *data)
Mark a specific row, characterized by its CargoDataEntry, as expanded.
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL).
Definition: widget_type.h:999
static const uint8 PC_RED
Red palette colour.
Definition: gfx_func.h:214
Trains list; Window numbers:
Definition: window_type.h:303
Functions related to zooming.
void Remove(CargoID cargo)
Remove a child associated with the given cargo.
uint8 station_gui_sort_by
sort cargo entries in the station gui by station name or amount
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:174
A tile of a station.
Definition: tile_type.h:48
Widget numbers used for list of cargo types (not present in _company_stations_widgets).
static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta)
Check whether we need to show the station selection window.
void Erase(T *item)
Removes given item from this vector.
virtual void OnResize()
Called after the window got resized.
List of scheduled trains button.
uint8 exclusive_counter
months till the exclusivity expires
Definition: town.h:76
Station with train station.
Definition: station_type.h:54
StationID GetStation() const
Get the station ID for this entry.
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
Update size and resize step of a widget in the window.
Aircraft list; Window numbers:
Definition: window_type.h:321
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2133
&#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:89
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-NULL) Titem.
Definition: pool_type.hpp:235
virtual void OnPaint()
The window must be repainted.
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:34
Drop down list.
Definition: widget_type.h:70
rename a station
Definition: command_type.h:247
uint16 GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:622
Index of the small font in the font tables.
Definition: gfx_type.h:205
bool adjacent_stations
allow stations to be built directly adjacent to other stations
Flow descriptions by origin stations.
Definition: station_base.h:152
Station with bus stops.
Definition: station_type.h:56
Declaration of link graph classes used for cargo distribution.
virtual void OnResize()
Called after the window got resized.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:19
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable...
Definition: window_gui.h:326
virtual void OnInvalidateData(int data=0, bool gui_scope=true)
Some data on this window has become invalid.
Grouping
Type of grouping used in each of the "columns".
static TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition: map_func.h:372
static const StringID _sort_names[]
Names of the sorting options in the dropdown.
Airport airport
Tile area the airport covers.
Definition: station_base.h:460
void ShowSelectBaseStationIfNeeded(const CommandContainer &cmd, TileArea ta)
Show the station selection window when needed.
Offset at right to draw the frame rectangular area.
Definition: window_gui.h:63
Dropdown button.
static const uint MAX_LENGTH_STATION_NAME_CHARS
The maximum length of a station name in characters including &#39;\0&#39;.
Definition: station_type.h:91
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
virtual void OnClick(Point pt, int widget, int click_count)
A click with the left mouse button has been made on the window.
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:321
StationID station
ID of the station this entry is associated with.
Passengers.
Definition: cargotype.h:40
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Definition: cargopacket.h:261
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:983
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
bool IsValid() const
Tests for validity of this cargospec.
Definition: cargotype.h:99
virtual void OnPaint()
The window must be repainted.
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:85
Window for selecting stations/waypoints to (distant) join to.
int rating_lines
Number of lines in the cargo ratings view.
Base of the town class.
const T * Get(uint index) const
Get the pointer to item "number" (const)
bool IsDescSortOrder() const
Check if the sort order is descending.
Caption of the window.
#define CMD_MSG(x)
Used to combine a StringID with the command.
Definition: command_type.h:369
uint count
sum of counts of all children or amount of cargo for this entry.
uint16 Count() const
Gets the number of &#39;items&#39; in this packet.
Definition: cargopacket.h:101
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:707
&#39;Accepts&#39; / &#39;Ratings&#39; button.
void SetCapacityFromWidget(Window *w, int widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget. ...
Definition: widget.cpp:1973
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows)...
Definition: viewport.cpp:3088
Specification of a rectangle with absolute coordinates of all edges.
Vertical scrollbar.
Definition: widget_type.h:84
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
Text is written right-to-left by default.
Definition: strings_type.h:26
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:314
Functions related to tile highlights.
Owner
Enum for all companies/owners.
Definition: company_type.h:20
Window functions not directly related to making/drawing windows.
void IncrementSize()
Increment.
void BuildStationsList(const Owner owner)
(Re)Build station list
Find a place automatically.
Definition: window_gui.h:156
const CargoSpec * _sorted_cargo_specs[NUM_CARGO]
Cargo specifications sorted alphabetically by name.
Definition: cargotype.cpp:135
&#39;ALL&#39; button - list all stations.
&#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.
Base classes/functions for stations.
static Station * Get(size_t index)
Gets station with given index.
uint16 h
The height of the area.
Definition: tilearea_type.h:21
uint GetCount() const
Get the cargo count for this entry.
uint8 station_gui_sort_order
the sort order of entries in the station gui - ascending or descending
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1095
CargoDataEntry * GetParent() const
Get the parent entry for this entry.
Dimensions (a width and height) of a rectangle in 2D.
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:429
int grouping_index
Currently selected entry in the grouping drop down.
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:62
Struct containing TileIndex and StationID.
Base class for all station-ish types.
Station data structure.
Definition: station_base.h:446
Nested widget with a child.
Definition: widget_type.h:545
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
uint32 cmd
command being executed.
Definition: command_type.h:479
LinkGraphSettings linkgraph
settings for link graph calculations
Set when the station accepts the cargo currently for final deliveries.
Definition: station_base.h:177
Station with an airport.
Definition: station_type.h:57
byte dirty
Whether the build station window needs to redraw due to the changed selection.
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:834
CargoID cargo
ID of the cargo this entry is associated with.
CargoDataEntry * InsertOrRetrieve(StationID station)
Insert a new child or retrieve an existing child using a station ID as ID.
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:621
virtual void OnDropdownSelect(int widget, int index)
A dropdown option associated to this window has been selected.
(Toggle) Button with text
Definition: widget_type.h:55
uint16 GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:631
static int CDECL StationRatingMinSorter(const Station *const *a, const Station *const *b)
Sort stations by their rating.
Train vehicle type.
Definition: vehicle_type.h:26
uint8 SortType() const
Get the sorttype of the list.
Definition: sortlist_type.h:97
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:201
Base class for a &#39;real&#39; widget.
Definition: widget_type.h:284