39 #include "table/strings.h" 
   59   uint32 cargo_mask = 0;
 
   74         default: NOT_REACHED();
 
   76       if (cargoes[i] >= (supplies ? 1U : 8U)) 
SetBit(cargo_mask, i);
 
   80   return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO);
 
  113   static const uint units_full  = 576; 
 
  114   static const uint rating_full = 224; 
 
  119   int colour = cs->rating_colour;
 
  121   uint w = (
minu(amount, units_full) + 5) / 36;
 
  126   if (w != 0) 
GfxFillRect(left, y, left + w - 1, y + height, colour);
 
  131     uint rest = amount / 5;
 
  134       GfxFillRect(w, y + height - rest, w, y + height, colour);
 
  143   rating = 
minu(rating, rating_full) / 16;
 
  157   static byte facilities;               
 
  158   static bool include_empty;            
 
  159   static const uint32 cargo_filter_max;
 
  160   static uint32 cargo_filter;           
 
  161   static const Station *last_station;
 
  164   static const StringID sorter_names[];
 
  179     DEBUG(misc, 3, 
"Building station list for company %d", owner);
 
  181     this->stations.
Clear();
 
  184     FOR_ALL_STATIONS(st) {
 
  187           int num_waiting_cargo = 0;
 
  191               if (
HasBit(this->cargo_filter, j)) {
 
  192                 *this->stations.
Append() = st;
 
  198           if (num_waiting_cargo == 0 && this->include_empty) {
 
  199             *this->stations.
Append() = st;
 
  214     static char buf_cache[64];
 
  218     GetString(buf, STR_STATION_NAME, 
lastof(buf));
 
  220     if (*b != last_station) {
 
  223       GetString(buf_cache, STR_STATION_NAME, 
lastof(buf_cache));
 
  227     if (r == 0) 
return (*a)->index - (*b)->index;
 
  234     return (*a)->facilities - (*b)->facilities;
 
  243     FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
 
  244       diff += (*a)->goods[j].cargo.TotalCount() - (*b)->goods[j].cargo.TotalCount();
 
  256     FOR_EACH_SET_CARGO_ID(j, cargo_filter) {
 
  257       diff += (*a)->goods[j].cargo.AvailableCount() - (*b)->goods[j].cargo.AvailableCount();
 
  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);
 
  275     return maxr1 - maxr2;
 
  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);
 
  290     return -(minr1 - minr2);
 
  296     if (!this->stations.
Sort()) 
return;
 
  299     this->last_station = NULL;
 
  308     this->stations.
SetListing(this->last_sorting);
 
  321       if (!
HasBit(this->cargo_filter, cs->
Index())) 
continue;
 
  325     if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = 
_cargo_mask;
 
  327     for (uint i = 0; i < 5; i++) {
 
  337     this->last_sorting = this->stations.
GetListing();
 
  346         d.height += padding.height;
 
  356         d.width += padding.width;
 
  357         d.height += padding.height;
 
  379         d.width  += padding.width + 2;
 
  380         d.height += padding.height;
 
  388           d.width  += padding.width + 2;
 
  389           d.height += padding.height;
 
  396   virtual void OnPaint()
 
  398     this->BuildStationsList((
Owner)this->window_number);
 
  399     this->SortStationsList();
 
  404   virtual void DrawWidget(
const Rect &r, 
int widget)
 const 
  414         int max = 
min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length());
 
  416         for (
int i = this->vscroll->GetPosition(); i < 
max; ++i) { 
 
  417           const Station *st = this->stations[i];
 
  451         if (this->vscroll->GetCount() == 0) { 
 
  459         int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
 
  465         int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
 
  471         int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
 
  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);
 
  488   virtual void SetStringParameters(
int widget)
 const 
  496   virtual void OnClick(
Point pt, 
int widget, 
int click_count)
 
  501         if (id_v >= this->stations.Length()) 
return; 
 
  503         const Station *st = this->stations[id_v];
 
  522           this->ToggleWidgetLoweredState(widget);
 
  529           this->LowerWidget(widget);
 
  531         this->stations.ForceRebuild();
 
  537           this->LowerWidget(i);
 
  541         this->stations.ForceRebuild();
 
  552         this->include_empty = 
true;
 
  553         this->stations.ForceRebuild();
 
  559         this->stations.ToggleSortOrder();
 
  569           this->include_empty = !this->include_empty;
 
  576           this->cargo_filter = 0;
 
  577           this->include_empty = 
true;
 
  581         this->stations.ForceRebuild();
 
  592             this->ToggleWidgetLoweredState(widget);
 
  599             this->cargo_filter = 0;
 
  600             this->include_empty = 
false;
 
  603             this->LowerWidget(widget);
 
  605           this->stations.ForceRebuild();
 
  612   virtual void OnDropdownSelect(
int widget, 
int index)
 
  614     if (this->stations.SortType() != index) {
 
  615       this->stations.SetSortType(index);
 
  618       this->GetWidget<NWidgetCore>(
WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
 
  624   virtual void OnTick()
 
  627     if (this->stations.NeedResort()) {
 
  628       DEBUG(misc, 3, 
"Periodic rebuild station list company %d", this->window_number);
 
  633   virtual void OnResize()
 
  643   virtual void OnInvalidateData(
int data = 0, 
bool gui_scope = 
true)
 
  647       this->stations.ForceRebuild();
 
  649       this->stations.ForceResort();
 
  654 Listing CompanyStationsWindow::last_sorting = {
false, 0};
 
  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;
 
  665   &StationWaitingTotalSorter,
 
  666   &StationWaitingAvailableSorter,
 
  667   &StationRatingMaxSorter,
 
  668   &StationRatingMinSorter
 
  672 const StringID CompanyStationsWindow::sorter_names[] = {
 
  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,
 
  696     panel->
SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
 
  697     container->
Add(panel);
 
  703 static const NWidgetPart _nested_company_stations_widgets[] = {
 
  720     NWidget(
WWT_PANEL, COLOUR_GREY, 
WID_STL_NOCARGOWAITING), 
SetMinimalSize(14, 11), 
SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), 
SetFill(0, 1), 
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(),
 
  739   WDP_AUTO, 
"list_stations", 358, 162,
 
  742   _nested_company_stations_widgets, 
lengthof(_nested_company_stations_widgets)
 
  754   AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
 
  757 static const NWidgetPart _nested_station_view_widgets[] = {
 
  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),
 
  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),
 
  781           SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
 
  783           SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
 
  785           SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
 
  788         SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
 
  810   uint num = 
min((waiting + (width / 2)) / width, (right - left) / width); 
 
  811   if (num == 0) 
return;
 
  848   bool SortId(Tid st1, Tid st2) 
const;
 
  850   bool SortStation (StationID st1, StationID st2) 
const;
 
  853 typedef std::set<CargoDataEntry *, CargoSorter> CargoDataSet;
 
  872     return this->InsertOrRetrieve<StationID>(
station);
 
  882     return this->InsertOrRetrieve<CargoID>(
cargo);
 
  964   CargoDataSet::iterator 
End()
 const { 
return this->
children->end(); }
 
 1005 CargoDataEntry::CargoDataEntry() :
 
 1007   station(INVALID_STATION),
 
 1018   children(new CargoDataSet)
 
 1021 CargoDataEntry::CargoDataEntry(StationID station, uint count, 
CargoDataEntry *parent) :
 
 1026   children(new CargoDataSet)
 
 1029 CargoDataEntry::CargoDataEntry(StationID station) :
 
 1037 CargoDataEntry::CargoDataEntry(
CargoID cargo) :
 
 1045 CargoDataEntry::~CargoDataEntry()
 
 1057     for (CargoDataSet::iterator i = this->
children->begin(); i != this->
children->end(); ++i) {
 
 1076   CargoDataSet::iterator i = this->
children->find(child);
 
 1093   CargoDataSet::iterator i = this->
children->find(&tmp);
 
 1111   this->count += 
count;
 
 1124 void CargoDataEntry::Resort(
CargoSortType type, SortOrder order)
 
 1128   this->children = new_subs;
 
 1143   switch (this->type) {
 
 1149       return this->SortCount(cd1, cd2);
 
 1158 bool CargoSorter::SortId(Tid st1, Tid st2)
 const 
 1160   return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1;
 
 1169   } 
else if (this->order == SO_ASCENDING) {
 
 1176 bool CargoSorter::SortStation(StationID st1, StationID st2)
 const 
 1182     return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2);
 
 1184     return order == SO_DESCENDING;
 
 1188   GetString(buf1, STR_STATION_NAME, 
lastof(buf1));
 
 1190   GetString(buf2, STR_STATION_NAME, 
lastof(buf2));
 
 1194     return this->SortId(st1, st2);
 
 1196     return (this->order == SO_ASCENDING) ? res < 0 : res > 0;
 
 1228   typedef std::vector<RowDisplay> CargoDataVector;
 
 1332     if (count == 0) 
return;
 
 1335     for (
int i = 0; i < 
NUM_COLUMNS && expand != NULL; ++i) {
 
 1344           if (auto_distributed || source != this->window_number) {
 
 1350           if (auto_distributed) {
 
 1356           if (auto_distributed) {
 
 1413       if (this->GetWidget<NWidgetCore>(
WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) {
 
 1441       this->
DrawEntries(&cargo, waiting_rect, pos, maxrows, 0);
 
 1462     cargo_entry->
Clear();
 
 1465     for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
 
 1466       StationID from = it->first;
 
 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;
 
 1473         if (via == this->window_number) {
 
 1478         prev_count = flow_it->first;
 
 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) {
 
 1503           prev_count = i->first;
 
 1510         uint sum_estimated = 0;
 
 1511         while (sum_estimated < count) {
 
 1512           for (CargoDataSet::iterator i = tmp.
Begin(); i != tmp.
End() && sum_estimated < count; ++i) {
 
 1515             if (estimate == 0) estimate = 1;
 
 1517             sum_estimated += estimate;
 
 1518             if (sum_estimated > count) {
 
 1519               estimate -= sum_estimated - count;
 
 1520               sum_estimated = count;
 
 1548     for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
 
 1549       StationID from = it->first;
 
 1551       const FlowStat::SharesMap *shares = it->second.GetShares();
 
 1552       for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
 
 1554         for (CargoDataSet::iterator dest_it = via_entry->
Begin(); dest_it != via_entry->
End(); ++dest_it) {
 
 1573       StationID next = it.GetKey();
 
 1576       if (source_entry == NULL) {
 
 1582       if (via_entry == NULL) {
 
 1587       for (CargoDataSet::iterator dest_it = via_entry->
Begin(); dest_it != via_entry->
End(); ++dest_it) {
 
 1623     std::list<StationID> stations;
 
 1638     while (!stations.empty()) {
 
 1639       filter = filter->
Retrieve(stations.back());
 
 1640       stations.pop_back();
 
 1656     if (station == this->window_number) {
 
 1658     } 
else if (station == INVALID_STATION) {
 
 1660     } 
else if (station == NEW_STATION) {
 
 1661       return STR_STATION_VIEW_RESERVED;
 
 1664       return other_station;
 
 1678     for (
int i = column - 1; i > 0; --i) {
 
 1681           return STR_STATION_VIEW_NONSTOP;
 
 1683           return STR_STATION_VIEW_VIA;
 
 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;
 
 1695         return STR_STATION_VIEW_VIA;
 
 1699     return STR_STATION_VIEW_VIA;
 
 1721     for (CargoDataSet::iterator i = entry->
Begin(); i != entry->
End(); ++i) {
 
 1728       if (pos > -maxrows && pos <= 0) {
 
 1735           str = STR_STATION_VIEW_WAITING_CARGO;
 
 1738           if (!auto_distributed) grouping = 
GR_SOURCE;
 
 1743               str = this->
GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY);
 
 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);
 
 1750               str = this->
GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY);
 
 1769           const char *sym = NULL;
 
 1772           } 
else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) {
 
 1781           if (sym) 
DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW);
 
 1786       if (auto_distributed || column == 0) {
 
 1787         pos = this->
DrawEntries(cd, r, pos, maxrows, column + 1, cargo);
 
 1802     uint32 cargo_mask = 0;
 
 1854     if (filter->
Retrieve(next) != NULL) {
 
 1872       if (display.
filter == &this->expanded_rows) {
 
 1873         this->HandleCargoWaitingClick<CargoID>(display.
filter, display.
next_cargo);
 
 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); 
 
 1904           nwi->
SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); 
 
 1974       case STR_STATION_VIEW_WAITING_STATION:
 
 1978       case STR_STATION_VIEW_WAITING_AMOUNT:
 
 1982       case STR_STATION_VIEW_PLANNED_STATION:
 
 1986       case STR_STATION_VIEW_PLANNED_AMOUNT:
 
 2008       case STR_STATION_VIEW_GROUP_S_V_D:
 
 2013       case STR_STATION_VIEW_GROUP_S_D_V:
 
 2018       case STR_STATION_VIEW_GROUP_V_S_D:
 
 2023       case STR_STATION_VIEW_GROUP_V_D_S:
 
 2028       case STR_STATION_VIEW_GROUP_D_S_V:
 
 2033       case STR_STATION_VIEW_GROUP_D_V_S:
 
 2053     if (str == NULL) 
return;
 
 2081   STR_STATION_VIEW_WAITING_STATION,
 
 2082   STR_STATION_VIEW_WAITING_AMOUNT,
 
 2083   STR_STATION_VIEW_PLANNED_STATION,
 
 2084   STR_STATION_VIEW_PLANNED_AMOUNT,
 
 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,
 
 2099   WDP_AUTO, 
"view_station", 249, 117,
 
 2102   _nested_station_view_widgets, 
lengthof(_nested_station_view_widgets)
 
 2112   AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
 
 2137   for (uint i = 0; i < _deleted_stations_nearby.
Length(); i++) {
 
 2139     if (ts->
tile == tile) {
 
 2140       *_stations_nearby_list.
Append() = _deleted_stations_nearby[i].station;
 
 2141       _deleted_stations_nearby.
Erase(ts);
 
 2152   if (!T::IsValidID(sid)) 
return false;
 
 2154   T *st = T::Get(sid);
 
 2157   if (st->rect.BeforeAddRect(ctx->
tile, ctx->
w, ctx->
h, StationRect::ADD_TEST).Succeeded()) {
 
 2158     *_stations_nearby_list.
Append() = sid;
 
 2178   _stations_nearby_list.
Clear();
 
 2179   _deleted_stations_nearby.
Clear();
 
 2188   FOR_ALL_BASE_STATIONS(st) {
 
 2199           AddNearbyStation<T>(st->
xy, &ctx);
 
 2217 static const NWidgetPart _nested_select_station_widgets[] = {
 
 2249     this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == 
FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
 
 2256     if (widget != WID_JS_PANEL) 
return;
 
 2260     for (uint i = 0; i < _stations_nearby_list.
Length(); i++) {
 
 2261       const T *st = T::Get(_stations_nearby_list[i]);
 
 2267     resize->height = d.height;
 
 2276     if (widget != WID_JS_PANEL) 
return;
 
 2288       const T *st = T::Get(_stations_nearby_list[i - 1]);
 
 2297     if (widget != WID_JS_PANEL) 
return;
 
 2300     bool distant_join = (st_index > 0);
 
 2301     if (distant_join) st_index--;
 
 2303     if (distant_join && st_index >= _stations_nearby_list.
Length()) 
return;
 
 2307        (distant_join ? _stations_nearby_list[st_index] : NEW_STATION));
 
 2318     if (_thd.
dirty & 2) {
 
 2336     if (!gui_scope) 
return;
 
 2337     FindStationsNearby<T>(this->
area, 
true);
 
 2344   WDP_AUTO, 
"build_station_join", 200, 180,
 
 2347   _nested_select_station_widgets, 
lengthof(_nested_select_station_widgets)
 
 2367   if (selection_window != NULL) {
 
 2369     delete selection_window;
 
 2382   const T *st = FindStationsNearby<T>(ta, 
false);
 
 2395   if (StationJoinerNeeded<T>(cmd, ta)) {
 
 2410   ShowSelectBaseStationIfNeeded<Station>(cmd, ta);
 
 2420   ShowSelectBaseStationIfNeeded<Waypoint>(cmd, ta);