OpenTTD
station_gui.cpp
Go to the documentation of this file.
1 /* $Id: station_gui.cpp 27894 2017-08-20 07:11:08Z alberth $ */
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  uint32 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 uint32 cargo_filter_max;
160  static uint32 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 OnTick()
625  {
626  if (_pause_mode != PM_UNPAUSED) return;
627  if (this->stations.NeedResort()) {
628  DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number);
629  this->SetDirty();
630  }
631  }
632 
633  virtual void OnResize()
634  {
636  }
637 
643  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
644  {
645  if (data == 0) {
646  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
647  this->stations.ForceRebuild();
648  } else {
649  this->stations.ForceResort();
650  }
651  }
652 };
653 
654 Listing CompanyStationsWindow::last_sorting = {false, 0};
655 byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
656 bool CompanyStationsWindow::include_empty = true;
657 const uint32 CompanyStationsWindow::cargo_filter_max = UINT32_MAX;
658 uint32 CompanyStationsWindow::cargo_filter = UINT32_MAX;
659 const Station *CompanyStationsWindow::last_station = NULL;
660 
661 /* Availible station sorting functions */
662 GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
669 };
670 
671 /* Names of the sorting functions */
672 const StringID CompanyStationsWindow::sorter_names[] = {
673  STR_SORT_BY_NAME,
674  STR_SORT_BY_FACILITY,
675  STR_SORT_BY_WAITING_TOTAL,
676  STR_SORT_BY_WAITING_AVAILABLE,
677  STR_SORT_BY_RATING_MAX,
678  STR_SORT_BY_RATING_MIN,
680 };
681 
687 static NWidgetBase *CargoWidgets(int *biggest_index)
688 {
689  NWidgetHorizontal *container = new NWidgetHorizontal();
690 
691  for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
692  NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
693  panel->SetMinimalSize(14, 11);
694  panel->SetResize(0, 0);
695  panel->SetFill(0, 1);
696  panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
697  container->Add(panel);
698  }
700  return container;
701 }
702 
703 static const NWidgetPart _nested_company_stations_widgets[] = {
705  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
706  NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
707  NWidget(WWT_SHADEBOX, COLOUR_GREY),
708  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
709  NWidget(WWT_STICKYBOX, COLOUR_GREY),
710  EndContainer(),
712  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),
713  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),
714  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),
715  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),
716  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),
717  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1),
718  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(),
720  NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(),
721  NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1),
722  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
723  EndContainer(),
725  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
726  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten.
727  NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
728  EndContainer(),
730  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(),
733  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
734  EndContainer(),
735  EndContainer(),
736 };
737 
738 static WindowDesc _company_stations_desc(
739  WDP_AUTO, "list_stations", 358, 162,
741  0,
742  _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets)
743 );
744 
751 {
752  if (!Company::IsValidID(company)) return;
753 
754  AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
755 }
756 
757 static const NWidgetPart _nested_station_view_widgets[] = {
759  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
760  NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
761  NWidget(WWT_SHADEBOX, COLOUR_GREY),
762  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
763  NWidget(WWT_STICKYBOX, COLOUR_GREY),
764  EndContainer(),
766  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
767  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
768  EndContainer(),
770  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0),
771  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
772  EndContainer(),
776  EndContainer(),
780  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
781  SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
782  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1),
783  SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
784  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
785  SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
786  EndContainer(),
787  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
788  SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
789  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
790  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
791  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
792  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
793  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
794  EndContainer(),
795 };
796 
807 static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
808 {
809  int width = ScaleGUITrad(10);
810  uint num = min((waiting + (width / 2)) / width, (right - left) / width); // maximum is width / 10 icons so it won't overflow
811  if (num == 0) return;
812 
813  SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon();
814 
815  int x = _current_text_dir == TD_RTL ? left : right - num * width;
816  do {
817  DrawSprite(sprite, PAL_NONE, x, y);
818  x += width;
819  } while (--num);
820 }
821 
822 enum SortOrder {
823  SO_DESCENDING,
824  SO_ASCENDING
825 };
826 
827 class CargoDataEntry;
828 
835 };
836 
837 class CargoSorter {
838 public:
839  CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {}
840  CargoSortType GetSortType() {return this->type;}
841  bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
842 
843 private:
844  CargoSortType type;
845  SortOrder order;
846 
847  template<class Tid>
848  bool SortId(Tid st1, Tid st2) const;
849  bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const;
850  bool SortStation (StationID st1, StationID st2) const;
851 };
852 
853 typedef std::set<CargoDataEntry *, CargoSorter> CargoDataSet;
854 
861 public:
862  CargoDataEntry();
863  ~CargoDataEntry();
864 
870  CargoDataEntry *InsertOrRetrieve(StationID station)
871  {
872  return this->InsertOrRetrieve<StationID>(station);
873  }
874 
881  {
882  return this->InsertOrRetrieve<CargoID>(cargo);
883  }
884 
885  void Update(uint count);
886 
891  void Remove(StationID station)
892  {
893  CargoDataEntry t(station);
894  this->Remove(&t);
895  }
896 
901  void Remove(CargoID cargo)
902  {
903  CargoDataEntry t(cargo);
904  this->Remove(&t);
905  }
906 
912  CargoDataEntry *Retrieve(StationID station) const
913  {
914  CargoDataEntry t(station);
915  return this->Retrieve(this->children->find(&t));
916  }
917 
924  {
925  CargoDataEntry t(cargo);
926  return this->Retrieve(this->children->find(&t));
927  }
928 
929  void Resort(CargoSortType type, SortOrder order);
930 
934  StationID GetStation() const { return this->station; }
935 
939  CargoID GetCargo() const { return this->cargo; }
940 
944  uint GetCount() const { return this->count; }
945 
949  CargoDataEntry *GetParent() const { return this->parent; }
950 
954  uint GetNumChildren() const { return this->num_children; }
955 
959  CargoDataSet::iterator Begin() const { return this->children->begin(); }
960 
964  CargoDataSet::iterator End() const { return this->children->end(); }
965 
969  bool HasTransfers() const { return this->transfers; }
970 
974  void SetTransfers(bool value) { this->transfers = value; }
975 
976  void Clear();
977 private:
978 
979  CargoDataEntry(StationID st, uint c, CargoDataEntry *p);
980  CargoDataEntry(CargoID car, uint c, CargoDataEntry *p);
981  CargoDataEntry(StationID st);
982  CargoDataEntry(CargoID car);
983 
984  CargoDataEntry *Retrieve(CargoDataSet::iterator i) const;
985 
986  template<class Tid>
987  CargoDataEntry *InsertOrRetrieve(Tid s);
988 
989  void Remove(CargoDataEntry *comp);
990  void IncrementSize();
991 
993  const union {
994  StationID station;
995  struct {
997  bool transfers;
998  };
999  };
1001  uint count;
1002  CargoDataSet *children;
1003 };
1004 
1005 CargoDataEntry::CargoDataEntry() :
1006  parent(NULL),
1007  station(INVALID_STATION),
1008  num_children(0),
1009  count(0),
1010  children(new CargoDataSet(CargoSorter(ST_CARGO_ID)))
1011 {}
1012 
1013 CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) :
1014  parent(parent),
1015  cargo(cargo),
1016  num_children(0),
1017  count(count),
1018  children(new CargoDataSet)
1019 {}
1020 
1021 CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) :
1022  parent(parent),
1023  station(station),
1024  num_children(0),
1025  count(count),
1026  children(new CargoDataSet)
1027 {}
1028 
1029 CargoDataEntry::CargoDataEntry(StationID station) :
1030  parent(NULL),
1031  station(station),
1032  num_children(0),
1033  count(0),
1034  children(NULL)
1035 {}
1036 
1037 CargoDataEntry::CargoDataEntry(CargoID cargo) :
1038  parent(NULL),
1039  cargo(cargo),
1040  num_children(0),
1041  count(0),
1042  children(NULL)
1043 {}
1044 
1045 CargoDataEntry::~CargoDataEntry()
1046 {
1047  this->Clear();
1048  delete this->children;
1049 }
1050 
1055 {
1056  if (this->children != NULL) {
1057  for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) {
1058  assert(*i != this);
1059  delete *i;
1060  }
1061  this->children->clear();
1062  }
1063  if (this->parent != NULL) this->parent->count -= this->count;
1064  this->count = 0;
1065  this->num_children = 0;
1066 }
1067 
1075 {
1076  CargoDataSet::iterator i = this->children->find(child);
1077  if (i != this->children->end()) {
1078  delete *i;
1079  this->children->erase(i);
1080  }
1081 }
1082 
1089 template<class Tid>
1091 {
1092  CargoDataEntry tmp(child_id);
1093  CargoDataSet::iterator i = this->children->find(&tmp);
1094  if (i == this->children->end()) {
1095  IncrementSize();
1096  return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first);
1097  } else {
1098  CargoDataEntry *ret = *i;
1099  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1100  return ret;
1101  }
1102 }
1103 
1110 {
1111  this->count += count;
1112  if (this->parent != NULL) this->parent->Update(count);
1113 }
1114 
1119 {
1120  ++this->num_children;
1121  if (this->parent != NULL) this->parent->IncrementSize();
1122 }
1123 
1124 void CargoDataEntry::Resort(CargoSortType type, SortOrder order)
1125 {
1126  CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order));
1127  delete this->children;
1128  this->children = new_subs;
1129 }
1130 
1131 CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const
1132 {
1133  if (i == this->children->end()) {
1134  return NULL;
1135  } else {
1136  assert(this->children->value_comp().GetSortType() != ST_COUNT);
1137  return *i;
1138  }
1139 }
1140 
1141 bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1142 {
1143  switch (this->type) {
1144  case ST_STATION_ID:
1145  return this->SortId<StationID>(cd1->GetStation(), cd2->GetStation());
1146  case ST_CARGO_ID:
1147  return this->SortId<CargoID>(cd1->GetCargo(), cd2->GetCargo());
1148  case ST_COUNT:
1149  return this->SortCount(cd1, cd2);
1150  case ST_STATION_STRING:
1151  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1152  default:
1153  NOT_REACHED();
1154  }
1155 }
1156 
1157 template<class Tid>
1158 bool CargoSorter::SortId(Tid st1, Tid st2) const
1159 {
1160  return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1;
1161 }
1162 
1163 bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const
1164 {
1165  uint c1 = cd1->GetCount();
1166  uint c2 = cd2->GetCount();
1167  if (c1 == c2) {
1168  return this->SortStation(cd1->GetStation(), cd2->GetStation());
1169  } else if (this->order == SO_ASCENDING) {
1170  return c1 < c2;
1171  } else {
1172  return c2 < c1;
1173  }
1174 }
1175 
1176 bool CargoSorter::SortStation(StationID st1, StationID st2) const
1177 {
1178  static char buf1[MAX_LENGTH_STATION_NAME_CHARS];
1179  static char buf2[MAX_LENGTH_STATION_NAME_CHARS];
1180 
1181  if (!Station::IsValidID(st1)) {
1182  return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2);
1183  } else if (!Station::IsValidID(st2)) {
1184  return order == SO_DESCENDING;
1185  }
1186 
1187  SetDParam(0, st1);
1188  GetString(buf1, STR_STATION_NAME, lastof(buf1));
1189  SetDParam(0, st2);
1190  GetString(buf2, STR_STATION_NAME, lastof(buf2));
1191 
1192  int res = strnatcmp(buf1, buf2); // Sort by name (natural sorting).
1193  if (res == 0) {
1194  return this->SortId(st1, st2);
1195  } else {
1196  return (this->order == SO_ASCENDING) ? res < 0 : res > 0;
1197  }
1198 }
1199 
1203 struct StationViewWindow : public Window {
1207  struct RowDisplay {
1208  RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {}
1209  RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {}
1210 
1215  union {
1219  StationID next_station;
1220 
1225  };
1226  };
1227 
1228  typedef std::vector<RowDisplay> CargoDataVector;
1229 
1230  static const int NUM_COLUMNS = 4;
1231 
1236  INV_FLOWS = 0x100,
1237  INV_CARGO = 0x200
1238  };
1239 
1243  enum Grouping {
1248  };
1249 
1253  enum Mode {
1255  MODE_PLANNED
1256  };
1257 
1261  Scrollbar *vscroll;
1262 
1265  ALH_RATING = 13,
1266  ALH_ACCEPTS = 3,
1267  };
1268 
1269  static const StringID _sort_names[];
1270  static const StringID _group_names[];
1271 
1278  CargoSortType sortings[NUM_COLUMNS];
1279 
1281  SortOrder sort_orders[NUM_COLUMNS];
1282 
1286  Grouping groupings[NUM_COLUMNS];
1287 
1290  CargoDataVector displayed_rows;
1291 
1292  StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc),
1293  scroll_to_row(INT_MAX), grouping_index(0)
1294  {
1295  this->rating_lines = ALH_RATING;
1296  this->accepts_lines = ALH_ACCEPTS;
1297 
1298  this->CreateNestedTree();
1299  this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
1300  /* Nested widget tree creation is done in two steps to ensure that this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */
1301  this->FinishInitNested(window_number);
1302 
1303  this->groupings[0] = GR_CARGO;
1304  this->sortings[0] = ST_AS_GROUPING;
1305  this->SelectGroupBy(_settings_client.gui.station_gui_group_order);
1306  this->SelectSortBy(_settings_client.gui.station_gui_sort_by);
1307  this->sort_orders[0] = SO_ASCENDING;
1308  this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order);
1309  this->owner = Station::Get(window_number)->owner;
1310  }
1311 
1313  {
1314  DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->window_number).Pack(), false);
1315  DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).Pack(), false);
1316  DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).Pack(), false);
1317  DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).Pack(), false);
1318  }
1319 
1330  void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count)
1331  {
1332  if (count == 0) return;
1333  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1334  const CargoDataEntry *expand = &this->expanded_rows;
1335  for (int i = 0; i < NUM_COLUMNS && expand != NULL; ++i) {
1336  switch (groupings[i]) {
1337  case GR_CARGO:
1338  assert(i == 0);
1339  data = data->InsertOrRetrieve(cargo);
1340  data->SetTransfers(source != this->window_number);
1341  expand = expand->Retrieve(cargo);
1342  break;
1343  case GR_SOURCE:
1344  if (auto_distributed || source != this->window_number) {
1345  data = data->InsertOrRetrieve(source);
1346  expand = expand->Retrieve(source);
1347  }
1348  break;
1349  case GR_NEXT:
1350  if (auto_distributed) {
1351  data = data->InsertOrRetrieve(next);
1352  expand = expand->Retrieve(next);
1353  }
1354  break;
1355  case GR_DESTINATION:
1356  if (auto_distributed) {
1357  data = data->InsertOrRetrieve(dest);
1358  expand = expand->Retrieve(dest);
1359  }
1360  break;
1361  }
1362  }
1363  data->Update(count);
1364  }
1365 
1366  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
1367  {
1368  switch (widget) {
1369  case WID_SV_WAITING:
1370  resize->height = FONT_HEIGHT_NORMAL;
1371  size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM;
1372  this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
1373  break;
1374 
1376  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;
1377  break;
1378 
1379  case WID_SV_CLOSE_AIRPORT:
1380  if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) {
1381  /* Hide 'Close Airport' button if no airport present. */
1382  size->width = 0;
1383  resize->width = 0;
1384  fill->width = 0;
1385  }
1386  break;
1387  }
1388  }
1389 
1390  virtual void OnPaint()
1391  {
1392  const Station *st = Station::Get(this->window_number);
1394  BuildCargoList(&cargo, st);
1395 
1396  this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar
1397 
1398  /* disable some buttons */
1399  this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company);
1400  this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN));
1401  this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
1402  this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK));
1403  this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT));
1404  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
1405  this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0);
1406 
1407  this->DrawWidgets();
1408 
1409  if (!this->IsShaded()) {
1410  /* Draw 'accepted cargo' or 'cargo ratings'. */
1411  const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SV_ACCEPT_RATING_LIST);
1412  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)};
1413  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1414  int lines = this->DrawAcceptedCargo(r);
1415  if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window.
1416  this->accepts_lines = lines;
1417  this->ReInit();
1418  return;
1419  }
1420  } else {
1421  int lines = this->DrawCargoRatings(r);
1422  if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window.
1423  this->rating_lines = lines;
1424  this->ReInit();
1425  return;
1426  }
1427  }
1428 
1429  /* Draw arrow pointing up/down for ascending/descending sorting */
1430  this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN);
1431 
1432  int pos = this->vscroll->GetPosition();
1433 
1434  int maxrows = this->vscroll->GetCapacity();
1435 
1436  displayed_rows.clear();
1437 
1438  /* Draw waiting cargo. */
1439  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SV_WAITING);
1440  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)};
1441  this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0);
1442  scroll_to_row = INT_MAX;
1443  }
1444  }
1445 
1446  virtual void SetStringParameters(int widget) const
1447  {
1448  const Station *st = Station::Get(this->window_number);
1449  SetDParam(0, st->index);
1450  SetDParam(1, st->facilities);
1451  }
1452 
1459  {
1460  const Station *st = Station::Get(this->window_number);
1461  CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i);
1462  cargo_entry->Clear();
1463 
1464  const FlowStatMap &flows = st->goods[i].flows;
1465  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1466  StationID from = it->first;
1467  CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from);
1468  const FlowStat::SharesMap *shares = it->second.GetShares();
1469  uint32 prev_count = 0;
1470  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1471  StationID via = flow_it->second;
1472  CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via);
1473  if (via == this->window_number) {
1474  via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count);
1475  } else {
1476  EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry);
1477  }
1478  prev_count = flow_it->first;
1479  }
1480  }
1481  }
1482 
1492  void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest)
1493  {
1494  if (Station::IsValidID(next) && Station::IsValidID(source)) {
1495  CargoDataEntry tmp;
1496  const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows;
1497  FlowStatMap::const_iterator map_it = flowmap.find(source);
1498  if (map_it != flowmap.end()) {
1499  const FlowStat::SharesMap *shares = map_it->second.GetShares();
1500  uint32 prev_count = 0;
1501  for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) {
1502  tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
1503  prev_count = i->first;
1504  }
1505  }
1506 
1507  if (tmp.GetCount() == 0) {
1508  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1509  } else {
1510  uint sum_estimated = 0;
1511  while (sum_estimated < count) {
1512  for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) {
1513  CargoDataEntry *child = *i;
1514  uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount());
1515  if (estimate == 0) estimate = 1;
1516 
1517  sum_estimated += estimate;
1518  if (sum_estimated > count) {
1519  estimate -= sum_estimated - count;
1520  sum_estimated = count;
1521  }
1522 
1523  if (estimate > 0) {
1524  if (child->GetStation() == next) {
1525  dest->InsertOrRetrieve(next)->Update(estimate);
1526  } else {
1527  EstimateDestinations(cargo, source, child->GetStation(), estimate, dest);
1528  }
1529  }
1530  }
1531 
1532  }
1533  }
1534  } else {
1535  dest->InsertOrRetrieve(INVALID_STATION)->Update(count);
1536  }
1537  }
1538 
1546  {
1547  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1548  for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
1549  StationID from = it->first;
1550  const CargoDataEntry *source_entry = source_dest->Retrieve(from);
1551  const FlowStat::SharesMap *shares = it->second.GetShares();
1552  for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
1553  const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second);
1554  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1555  CargoDataEntry *dest_entry = *dest_it;
1556  ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount());
1557  }
1558  }
1559  }
1560  }
1561 
1569  {
1570  const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
1571  for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) {
1572  const CargoPacket *cp = *it;
1573  StationID next = it.GetKey();
1574 
1575  const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation());
1576  if (source_entry == NULL) {
1577  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1578  continue;
1579  }
1580 
1581  const CargoDataEntry *via_entry = source_entry->Retrieve(next);
1582  if (via_entry == NULL) {
1583  this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count());
1584  continue;
1585  }
1586 
1587  for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {
1588  CargoDataEntry *dest_entry = *dest_it;
1589  uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount());
1590  this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val);
1591  }
1592  }
1593  this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount());
1594  }
1595 
1602  {
1603  for (CargoID i = 0; i < NUM_CARGO; i++) {
1604 
1605  if (this->cached_destinations.Retrieve(i) == NULL) {
1606  this->RecalcDestinations(i);
1607  }
1608 
1609  if (this->current_mode == MODE_WAITING) {
1610  this->BuildCargoList(i, st->goods[i].cargo, cargo);
1611  } else {
1612  this->BuildFlowList(i, st->goods[i].flows, cargo);
1613  }
1614  }
1615  }
1616 
1622  {
1623  std::list<StationID> stations;
1624  const CargoDataEntry *parent = data->GetParent();
1625  if (parent->GetParent() == NULL) {
1626  this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo()));
1627  return;
1628  }
1629 
1630  StationID next = data->GetStation();
1631  while (parent->GetParent()->GetParent() != NULL) {
1632  stations.push_back(parent->GetStation());
1633  parent = parent->GetParent();
1634  }
1635 
1636  CargoID cargo = parent->GetCargo();
1637  CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo);
1638  while (!stations.empty()) {
1639  filter = filter->Retrieve(stations.back());
1640  stations.pop_back();
1641  }
1642 
1643  this->displayed_rows.push_back(RowDisplay(filter, next));
1644  }
1645 
1654  StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any)
1655  {
1656  if (station == this->window_number) {
1657  return here;
1658  } else if (station == INVALID_STATION) {
1659  return any;
1660  } else if (station == NEW_STATION) {
1661  return STR_STATION_VIEW_RESERVED;
1662  } else {
1663  SetDParam(2, station);
1664  return other_station;
1665  }
1666  }
1667 
1675  StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column)
1676  {
1677  CargoDataEntry *parent = cd->GetParent();
1678  for (int i = column - 1; i > 0; --i) {
1679  if (this->groupings[i] == GR_DESTINATION) {
1680  if (parent->GetStation() == station) {
1681  return STR_STATION_VIEW_NONSTOP;
1682  } else {
1683  return STR_STATION_VIEW_VIA;
1684  }
1685  }
1686  parent = parent->GetParent();
1687  }
1688 
1689  if (this->groupings[column + 1] == GR_DESTINATION) {
1690  CargoDataSet::iterator begin = cd->Begin();
1691  CargoDataSet::iterator end = cd->End();
1692  if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) {
1693  return STR_STATION_VIEW_NONSTOP;
1694  } else {
1695  return STR_STATION_VIEW_VIA;
1696  }
1697  }
1698 
1699  return STR_STATION_VIEW_VIA;
1700  }
1701 
1712  int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID)
1713  {
1714  if (this->sortings[column] == ST_AS_GROUPING) {
1715  if (this->groupings[column] != GR_CARGO) {
1716  entry->Resort(ST_STATION_STRING, this->sort_orders[column]);
1717  }
1718  } else {
1719  entry->Resort(ST_COUNT, this->sort_orders[column]);
1720  }
1721  for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) {
1722  CargoDataEntry *cd = *i;
1723 
1724  Grouping grouping = this->groupings[column];
1725  if (grouping == GR_CARGO) cargo = cd->GetCargo();
1726  bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL;
1727 
1728  if (pos > -maxrows && pos <= 0) {
1729  StringID str = STR_EMPTY;
1730  int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL;
1731  SetDParam(0, cargo);
1732  SetDParam(1, cd->GetCount());
1733 
1734  if (this->groupings[column] == GR_CARGO) {
1735  str = STR_STATION_VIEW_WAITING_CARGO;
1736  DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y);
1737  } else {
1738  if (!auto_distributed) grouping = GR_SOURCE;
1739  StationID station = cd->GetStation();
1740 
1741  switch (grouping) {
1742  case GR_SOURCE:
1743  str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY);
1744  break;
1745  case GR_NEXT:
1746  str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY);
1747  if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column);
1748  break;
1749  case GR_DESTINATION:
1750  str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY);
1751  break;
1752  default:
1753  NOT_REACHED();
1754  }
1755  if (pos == -this->scroll_to_row && Station::IsValidID(station)) {
1756  ScrollMainWindowToTile(Station::Get(station)->xy);
1757  }
1758  }
1759 
1760  bool rtl = _current_text_dir == TD_RTL;
1761  int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width;
1762  int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width;
1763  int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT;
1764  int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT;
1765 
1766  DrawString(text_left, text_right, y, str);
1767 
1768  if (column < NUM_COLUMNS - 1) {
1769  const char *sym = NULL;
1770  if (cd->GetNumChildren() > 0) {
1771  sym = "-";
1772  } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) {
1773  sym = "+";
1774  } else {
1775  /* Only draw '+' if there is something to be shown. */
1776  const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo;
1777  if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) {
1778  sym = "+";
1779  }
1780  }
1781  if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW);
1782  }
1783  this->SetDisplayedRow(cd);
1784  }
1785  --pos;
1786  if (auto_distributed || column == 0) {
1787  pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo);
1788  }
1789  }
1790  return pos;
1791  }
1792 
1798  int DrawAcceptedCargo(const Rect &r) const
1799  {
1800  const Station *st = Station::Get(this->window_number);
1801 
1802  uint32 cargo_mask = 0;
1803  for (CargoID i = 0; i < NUM_CARGO; i++) {
1804  if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i);
1805  }
1806  SetDParam(0, cargo_mask);
1807  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);
1808  return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1809  }
1810 
1816  int DrawCargoRatings(const Rect &r) const
1817  {
1818  const Station *st = Station::Get(this->window_number);
1819  int y = r.top + WD_FRAMERECT_TOP;
1820 
1821  if (st->town->exclusive_counter > 0) {
1822  SetDParam(0, st->town->exclusivity);
1823  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);
1824  y += WD_PAR_VSEP_WIDE;
1825  }
1826 
1827  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE);
1828  y += FONT_HEIGHT_NORMAL;
1829 
1830  const CargoSpec *cs;
1832  const GoodsEntry *ge = &st->goods[cs->Index()];
1833  if (!ge->HasRating()) continue;
1834 
1835  const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph);
1836  SetDParam(0, cs->name);
1837  SetDParam(1, lg != NULL ? lg->Monthly((*lg)[ge->node].Supply()) : 0);
1838  SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5));
1839  SetDParam(3, ToPercent8(ge->rating));
1840  DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING);
1841  y += FONT_HEIGHT_NORMAL;
1842  }
1843  return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
1844  }
1845 
1851  template<class Tid>
1852  void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next)
1853  {
1854  if (filter->Retrieve(next) != NULL) {
1855  filter->Remove(next);
1856  } else {
1857  filter->InsertOrRetrieve(next);
1858  }
1859  }
1860 
1866  {
1867  if (row < 0 || (uint)row >= this->displayed_rows.size()) return;
1868  if (_ctrl_pressed) {
1869  this->scroll_to_row = row;
1870  } else {
1871  RowDisplay &display = this->displayed_rows[row];
1872  if (display.filter == &this->expanded_rows) {
1873  this->HandleCargoWaitingClick<CargoID>(display.filter, display.next_cargo);
1874  } else {
1875  this->HandleCargoWaitingClick<StationID>(display.filter, display.next_station);
1876  }
1877  }
1878  this->SetWidgetDirty(WID_SV_WAITING);
1879  }
1880 
1881  virtual void OnClick(Point pt, int widget, int click_count)
1882  {
1883  switch (widget) {
1884  case WID_SV_WAITING:
1885  this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition());
1886  break;
1887 
1888  case WID_SV_LOCATION:
1889  if (_ctrl_pressed) {
1890  ShowExtraViewPortWindow(Station::Get(this->window_number)->xy);
1891  } else {
1892  ScrollMainWindowToTile(Station::Get(this->window_number)->xy);
1893  }
1894  break;
1895 
1896  case WID_SV_ACCEPTS_RATINGS: {
1897  /* Swap between 'accepts' and 'ratings' view. */
1898  int height_change;
1899  NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS);
1900  if (this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
1901  nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view.
1902  height_change = this->rating_lines - this->accepts_lines;
1903  } else {
1904  nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view.
1905  height_change = this->accepts_lines - this->rating_lines;
1906  }
1907  this->ReInit(0, height_change * FONT_HEIGHT_NORMAL);
1908  break;
1909  }
1910 
1911  case WID_SV_RENAME:
1912  SetDParam(0, this->window_number);
1913  ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
1915  break;
1916 
1917  case WID_SV_CLOSE_AIRPORT:
1918  DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT);
1919  break;
1920 
1921  case WID_SV_TRAINS: // Show list of scheduled trains to this station
1922  case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station
1923  case WID_SV_SHIPS: // Show list of scheduled ships to this station
1924  case WID_SV_PLANES: { // Show list of scheduled aircraft to this station
1925  Owner owner = Station::Get(this->window_number)->owner;
1926  ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number);
1927  break;
1928  }
1929 
1930  case WID_SV_SORT_BY: {
1931  /* The initial selection is composed of current mode and
1932  * sorting criteria for columns 1, 2, and 3. Column 0 is always
1933  * sorted by cargo ID. The others can theoretically be sorted
1934  * by different things but there is no UI for that. */
1935  ShowDropDownMenu(this, _sort_names,
1936  this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0),
1937  WID_SV_SORT_BY, 0, 0);
1938  break;
1939  }
1940 
1941  case WID_SV_GROUP_BY: {
1942  ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
1943  break;
1944  }
1945 
1946  case WID_SV_SORT_ORDER: { // flip sorting method asc/desc
1947  this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING);
1948  this->SetTimeout();
1949  this->LowerWidget(WID_SV_SORT_ORDER);
1950  break;
1951  }
1952  }
1953  }
1954 
1959  void SelectSortOrder(SortOrder order)
1960  {
1961  this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order;
1962  _settings_client.gui.station_gui_sort_order = this->sort_orders[1];
1963  this->SetDirty();
1964  }
1965 
1970  void SelectSortBy(int index)
1971  {
1973  switch (_sort_names[index]) {
1974  case STR_STATION_VIEW_WAITING_STATION:
1975  this->current_mode = MODE_WAITING;
1976  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
1977  break;
1978  case STR_STATION_VIEW_WAITING_AMOUNT:
1979  this->current_mode = MODE_WAITING;
1980  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
1981  break;
1982  case STR_STATION_VIEW_PLANNED_STATION:
1983  this->current_mode = MODE_PLANNED;
1984  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING;
1985  break;
1986  case STR_STATION_VIEW_PLANNED_AMOUNT:
1987  this->current_mode = MODE_PLANNED;
1988  this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT;
1989  break;
1990  default:
1991  NOT_REACHED();
1992  }
1993  /* Display the current sort variant */
1994  this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->widget_data = _sort_names[index];
1995  this->SetDirty();
1996  }
1997 
2002  void SelectGroupBy(int index)
2003  {
2004  this->grouping_index = index;
2006  this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->widget_data = _group_names[index];
2007  switch (_group_names[index]) {
2008  case STR_STATION_VIEW_GROUP_S_V_D:
2009  this->groupings[1] = GR_SOURCE;
2010  this->groupings[2] = GR_NEXT;
2011  this->groupings[3] = GR_DESTINATION;
2012  break;
2013  case STR_STATION_VIEW_GROUP_S_D_V:
2014  this->groupings[1] = GR_SOURCE;
2015  this->groupings[2] = GR_DESTINATION;
2016  this->groupings[3] = GR_NEXT;
2017  break;
2018  case STR_STATION_VIEW_GROUP_V_S_D:
2019  this->groupings[1] = GR_NEXT;
2020  this->groupings[2] = GR_SOURCE;
2021  this->groupings[3] = GR_DESTINATION;
2022  break;
2023  case STR_STATION_VIEW_GROUP_V_D_S:
2024  this->groupings[1] = GR_NEXT;
2025  this->groupings[2] = GR_DESTINATION;
2026  this->groupings[3] = GR_SOURCE;
2027  break;
2028  case STR_STATION_VIEW_GROUP_D_S_V:
2029  this->groupings[1] = GR_DESTINATION;
2030  this->groupings[2] = GR_SOURCE;
2031  this->groupings[3] = GR_NEXT;
2032  break;
2033  case STR_STATION_VIEW_GROUP_D_V_S:
2034  this->groupings[1] = GR_DESTINATION;
2035  this->groupings[2] = GR_NEXT;
2036  this->groupings[3] = GR_SOURCE;
2037  break;
2038  }
2039  this->SetDirty();
2040  }
2041 
2042  virtual void OnDropdownSelect(int widget, int index)
2043  {
2044  if (widget == WID_SV_SORT_BY) {
2045  this->SelectSortBy(index);
2046  } else {
2047  this->SelectGroupBy(index);
2048  }
2049  }
2050 
2051  virtual void OnQueryTextFinished(char *str)
2052  {
2053  if (str == NULL) return;
2054 
2055  DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), NULL, str);
2056  }
2057 
2058  virtual void OnResize()
2059  {
2061  }
2062 
2068  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2069  {
2070  if (gui_scope) {
2071  if (data >= 0 && data < NUM_CARGO) {
2072  this->cached_destinations.Remove((CargoID)data);
2073  } else {
2074  this->ReInit();
2075  }
2076  }
2077  }
2078 };
2079 
2081  STR_STATION_VIEW_WAITING_STATION,
2082  STR_STATION_VIEW_WAITING_AMOUNT,
2083  STR_STATION_VIEW_PLANNED_STATION,
2084  STR_STATION_VIEW_PLANNED_AMOUNT,
2086 };
2087 
2089  STR_STATION_VIEW_GROUP_S_V_D,
2090  STR_STATION_VIEW_GROUP_S_D_V,
2091  STR_STATION_VIEW_GROUP_V_S_D,
2092  STR_STATION_VIEW_GROUP_V_D_S,
2093  STR_STATION_VIEW_GROUP_D_S_V,
2094  STR_STATION_VIEW_GROUP_D_V_S,
2096 };
2097 
2098 static WindowDesc _station_view_desc(
2099  WDP_AUTO, "view_station", 249, 117,
2101  0,
2102  _nested_station_view_widgets, lengthof(_nested_station_view_widgets)
2103 );
2104 
2111 {
2112  AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
2113 }
2114 
2118  StationID station;
2119 };
2120 
2121 static SmallVector<TileAndStation, 8> _deleted_stations_nearby;
2122 static SmallVector<StationID, 8> _stations_nearby_list;
2123 
2131 template <class T>
2132 static bool AddNearbyStation(TileIndex tile, void *user_data)
2133 {
2134  TileArea *ctx = (TileArea *)user_data;
2135 
2136  /* First check if there were deleted stations here */
2137  for (uint i = 0; i < _deleted_stations_nearby.Length(); i++) {
2138  TileAndStation *ts = _deleted_stations_nearby.Get(i);
2139  if (ts->tile == tile) {
2140  *_stations_nearby_list.Append() = _deleted_stations_nearby[i].station;
2141  _deleted_stations_nearby.Erase(ts);
2142  i--;
2143  }
2144  }
2145 
2146  /* Check if own station and if we stay within station spread */
2147  if (!IsTileType(tile, MP_STATION)) return false;
2148 
2149  StationID sid = GetStationIndex(tile);
2150 
2151  /* This station is (likely) a waypoint */
2152  if (!T::IsValidID(sid)) return false;
2153 
2154  T *st = T::Get(sid);
2155  if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false;
2156 
2157  if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
2158  *_stations_nearby_list.Append() = sid;
2159  }
2160 
2161  return false; // We want to include *all* nearby stations
2162 }
2163 
2173 template <class T>
2174 static const T *FindStationsNearby(TileArea ta, bool distant_join)
2175 {
2176  TileArea ctx = ta;
2177 
2178  _stations_nearby_list.Clear();
2179  _deleted_stations_nearby.Clear();
2180 
2181  /* Check the inside, to return, if we sit on another station */
2182  TILE_AREA_LOOP(t, ta) {
2183  if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
2184  }
2185 
2186  /* Look for deleted stations */
2187  const BaseStation *st;
2188  FOR_ALL_BASE_STATIONS(st) {
2189  if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
2190  /* Include only within station spread (yes, it is strictly less than) */
2191  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) {
2192  TileAndStation *ts = _deleted_stations_nearby.Append();
2193  ts->tile = st->xy;
2194  ts->station = st->index;
2195 
2196  /* Add the station when it's within where we're going to build */
2197  if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
2198  IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
2199  AddNearbyStation<T>(st->xy, &ctx);
2200  }
2201  }
2202  }
2203  }
2204 
2205  /* Only search tiles where we have a chance to stay within the station spread.
2206  * The complete check needs to be done in the callback as we don't know the
2207  * extent of the found station, yet. */
2208  if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL;
2209  uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1;
2210 
2211  TileIndex tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N));
2212  CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
2213 
2214  return NULL;
2215 }
2216 
2217 static const NWidgetPart _nested_select_station_widgets[] = {
2219  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
2220  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2221  NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
2222  EndContainer(),
2224  NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(),
2226  NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR),
2227  NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
2228  EndContainer(),
2229  EndContainer(),
2230 };
2231 
2236 template <class T>
2240  Scrollbar *vscroll;
2241 
2242  SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) :
2243  Window(desc),
2244  select_station_cmd(cmd),
2245  area(ta)
2246  {
2247  this->CreateNestedTree();
2248  this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
2249  this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
2250  this->FinishInitNested(0);
2251  this->OnInvalidateData(0);
2252  }
2253 
2254  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
2255  {
2256  if (widget != WID_JS_PANEL) return;
2257 
2258  /* Determine the widest string */
2259  Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
2260  for (uint i = 0; i < _stations_nearby_list.Length(); i++) {
2261  const T *st = T::Get(_stations_nearby_list[i]);
2262  SetDParam(0, st->index);
2263  SetDParam(1, st->facilities);
2264  d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION));
2265  }
2266 
2267  resize->height = d.height;
2268  d.height *= 5;
2270  d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
2271  *size = d;
2272  }
2273 
2274  virtual void DrawWidget(const Rect &r, int widget) const
2275  {
2276  if (widget != WID_JS_PANEL) return;
2277 
2278  uint y = r.top + WD_FRAMERECT_TOP;
2279  if (this->vscroll->GetPosition() == 0) {
2280  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);
2281  y += this->resize.step_height;
2282  }
2283 
2284  for (uint i = max<uint>(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.Length(); ++i, y += this->resize.step_height) {
2285  /* Don't draw anything if it extends past the end of the window. */
2286  if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break;
2287 
2288  const T *st = T::Get(_stations_nearby_list[i - 1]);
2289  SetDParam(0, st->index);
2290  SetDParam(1, st->facilities);
2291  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);
2292  }
2293  }
2294 
2295  virtual void OnClick(Point pt, int widget, int click_count)
2296  {
2297  if (widget != WID_JS_PANEL) return;
2298 
2299  uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP);
2300  bool distant_join = (st_index > 0);
2301  if (distant_join) st_index--;
2302 
2303  if (distant_join && st_index >= _stations_nearby_list.Length()) return;
2304 
2305  /* Insert station to be joined into stored command */
2306  SB(this->select_station_cmd.p2, 16, 16,
2307  (distant_join ? _stations_nearby_list[st_index] : NEW_STATION));
2308 
2309  /* Execute stored Command */
2310  DoCommandP(&this->select_station_cmd);
2311 
2312  /* Close Window; this might cause double frees! */
2314  }
2315 
2316  virtual void OnTick()
2317  {
2318  if (_thd.dirty & 2) {
2319  _thd.dirty &= ~2;
2320  this->SetDirty();
2321  }
2322  }
2323 
2324  virtual void OnResize()
2325  {
2326  this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
2327  }
2328 
2334  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2335  {
2336  if (!gui_scope) return;
2337  FindStationsNearby<T>(this->area, true);
2338  this->vscroll->SetCount(_stations_nearby_list.Length() + 1);
2339  this->SetDirty();
2340  }
2341 };
2342 
2343 static WindowDesc _select_station_desc(
2344  WDP_AUTO, "build_station_join", 200, 180,
2347  _nested_select_station_widgets, lengthof(_nested_select_station_widgets)
2348 );
2349 
2350 
2358 template <class T>
2359 static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta)
2360 {
2361  /* Only show selection if distant join is enabled in the settings */
2362  if (!_settings_game.station.distant_join_stations) return false;
2363 
2364  /* If a window is already opened and we didn't ctrl-click,
2365  * return true (i.e. just flash the old window) */
2366  Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
2367  if (selection_window != NULL) {
2368  /* Abort current distant-join and start new one */
2369  delete selection_window;
2371  }
2372 
2373  /* only show the popup, if we press ctrl */
2374  if (!_ctrl_pressed) return false;
2375 
2376  /* Now check if we could build there */
2377  if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false;
2378 
2379  /* Test for adjacent station or station below selection.
2380  * If adjacent-stations is disabled and we are building next to a station, do not show the selection window.
2381  * but join the other station immediately. */
2382  const T *st = FindStationsNearby<T>(ta, false);
2383  return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0);
2384 }
2385 
2392 template <class T>
2394 {
2395  if (StationJoinerNeeded<T>(cmd, ta)) {
2397  new SelectStationWindow<T>(&_select_station_desc, cmd, ta);
2398  } else {
2399  DoCommandP(&cmd);
2400  }
2401 }
2402 
2409 {
2410  ShowSelectBaseStationIfNeeded<Station>(cmd, ta);
2411 }
2412 
2419 {
2420  ShowSelectBaseStationIfNeeded<Waypoint>(cmd, ta);
2421 }
&#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.
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:317
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:1843
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen...
Definition: gfx.cpp:112
void Update(uint count)
Update the count for this entry and propagate the change to the parent entry if there is one...
void CheckRedrawStationCoverage(const Window *w)
Check whether we need to redraw the station coverage text.
Definition: station_gui.cpp:88
Point pos
Location, in tile "units", of the northern tile of the selected area.
A normal unpaused game.
Definition: openttd.h:58
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:448
open/close an airport to incoming aircraft
Definition: command_type.h:330
Window * parent
Parent window.
Definition: window_gui.h:332
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:312
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:577
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:1105
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:1065
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.
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:475
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:458
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:2355
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:379
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:478
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:1804
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
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:271
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:1820
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:60
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:27
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 give tiletype.
Definition: tile_map.h:143
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:436
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:488
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:21
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:472
#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:56
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
TextColour GetContrastColour(uint8 background)
Determine a contrasty text colour for a coloured background.
Definition: gfx.cpp:1116
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
CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, uint32 *always_accepted)
Get the acceptance of cargoes around the tile in 1/8.
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:307
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:469
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:499
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:527
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
PauseModeByte _pause_mode
The current pause mode.
Definition: gfx.cpp:48
Road vehicle type.
Definition: vehicle_type.h:25
Invalid cargo type.
Definition: cargo_type.h:70
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:59
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:26
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:959
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:39
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:699
Maximal number of cargo types in a game.
Definition: cargo_type.h:66
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:1137
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:74
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:569
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
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.
virtual void OnTick()
Called once per (game) tick.
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:55
uint32 _cargo_mask
Bitmask of cargo types available.
Definition: cargotype.cpp:31
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
static TileIndexDiff TileOffsByDir(Direction dir)
Convert a Direction to a TileIndexDiff.
Definition: map_func.h:357
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2268
&#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:57
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:319
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 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:92
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:314
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:366
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:695
&#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:3211
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:307
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
#define TILE_ADD(x, y)
Adds to tiles together.
Definition: map_func.h:246
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:476
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:58
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:833
virtual void OnTick()
Called once per (game) tick.
CargoID cargo
ID of the cargo this entry is associated with.
CargoDataEntry * InsertOrRetrieve(StationID station)
Insert a new child or retrieve an existing child using a station ID as ID.
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:620
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:24
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