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);