summaryrefslogtreecommitdiff
path: root/src/station_gui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/station_gui.cpp')
-rw-r--r--src/station_gui.cpp503
1 files changed, 481 insertions, 22 deletions
diff --git a/src/station_gui.cpp b/src/station_gui.cpp
index b0709e2c2..219bcae9d 100644
--- a/src/station_gui.cpp
+++ b/src/station_gui.cpp
@@ -20,6 +20,7 @@
#include "station_gui.h"
#include "strings_func.h"
#include "window_func.h"
+#include "layer_func.h"
#include "viewport_func.h"
#include "widgets/dropdown_func.h"
#include "station_base.h"
@@ -30,6 +31,9 @@
#include "core/geometry_func.hpp"
#include "vehiclelist.h"
#include "town.h"
+#include "industry.h"
+#include "cargodest_base.h"
+#include "departures_gui.h"
#include "widgets/station_widget.h"
@@ -743,14 +747,18 @@ static const NWidgetPart _nested_station_view_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_ACCEPT_RATING_LIST), SetMinimalSize(249, 32), SetResize(1, 0), EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
- NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(36, 12), SetResize(1, 0), SetFill(1, 1),
SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
- NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(37, 12), SetResize(1, 0), SetFill(1, 1),
SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP),
- NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_CARGO_FROM_TO_VIA), SetMinimalSize(36, 12), SetResize(1, 0), SetFill(1, 1),
+ SetDataTip(STR_STATION_VIEW_WAITING_VIA_BUTTON, STR_STATION_VIEW_WAITING_VIA_TOOLTIP),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(36, 12), SetResize(1, 0), SetFill(1, 1),
SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_DEPARTURES), SetMinimalSize(80, 12), SetResize(1, 0), SetFill(1, 1),
+ SetDataTip(STR_STATION_VIEW_DEPARTURES_BUTTON, STR_STATION_VIEW_DEPARTURES_TOOLTIP),
EndContainer(),
- NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
+ NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(36, 12), SetResize(1, 0), SetFill(1, 1),
SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
@@ -786,18 +794,145 @@ static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y)
struct CargoData {
CargoID cargo;
- StationID source;
+ union {
+ StationID station;
+ SourceID css;
+ };
uint count;
+ SourceType type;
- CargoData(CargoID cargo, StationID source, uint count) :
+ CargoData(CargoID cargo, StationID station, uint count, SourceType type = ST_INDUSTRY) :
cargo(cargo),
- source(source),
- count(count)
+ station(station),
+ count(count),
+ type(type)
{ }
};
typedef std::list<CargoData> CargoDataList;
+/** List of cargo for either one next hop or one destination. */
+struct CargoDestEntry {
+ typedef std::list<CargoDestEntry> List;
+
+ /** Enum for type of stored data. */
+ enum Type {
+ FINAL_DEST, ///< Data is the final destination.
+ NEXT_HOP, ///< Data is the next hop.
+ TRANSFER_HOP ///< Data is the transfer station.
+ };
+
+ List children; ///< Child entries of this entry.
+ CargoData data; ///< Stores the info for the current item.
+ Type type; ///< Type of the data stored in #entry.
+ uint16 start_row; ///< Row number of the header line.
+ bool expanded; ///< Is this entry expanded?
+
+ CargoDestEntry(Type type, StationID station, uint count, SourceType st = ST_INDUSTRY) :
+ data(INVALID_CARGO, station, count, st),
+ type(type),
+ start_row(0),
+ expanded(false)
+ { }
+
+ /** Zero out this entry and all child entries. */
+ void Zero()
+ {
+ for (List::iterator i = this->children.begin(); i != this->children.end(); ++i ) {
+ i->Zero();
+ }
+ this->data.count = 0;
+ this->start_row = 0;
+ }
+
+ /** Remove all empty child entries. */
+ void RemoveEmpty()
+ {
+ for (List::iterator i = this->children.begin(); i != this->children.end(); ) {
+ if (i->data.count > 0) {
+ i->RemoveEmpty();
+ ++i;
+ } else {
+ i = this->children.erase(i);
+ }
+ }
+ }
+
+ /** Update header row number. */
+ int UpdateRowCount(int row)
+ {
+ this->start_row = ++row;
+ if (this->expanded) {
+ for (List::iterator i = this->children.begin(); i != this->children.end(); ++i) {
+ row = i->UpdateRowCount(row);
+ }
+ }
+ return row;
+ }
+};
+
+/**
+ * Get the next hop of a cargo packet.
+ * @param ge Station cargo info for the matching cargo type.
+ * @param cp The cargo packet.
+ * @return Station ID of the next hop or INVALID_STATION if not possible.
+ */
+static StationID GetNextHopStation(const GoodsEntry &ge, const CargoPacket *cp)
+{
+ StationID next = INVALID_STATION;
+ for (RouteLinkList::const_iterator i = ge.routes.begin(); i != ge.routes.end(); ++i) {
+ if ((*i)->GetOriginOrderId() == cp->NextHop()) {
+ next = (*i)->GetDestination();
+ break;
+ }
+ }
+ return next;
+}
+
+/**
+ * Add a cargo packet to a #CargoDestEntry list.
+ * @param list The list to add the packet to.
+ * @param type Which value to select as the entry info.
+ * @param cp The cargo packet.
+ * @param ge Where this cargo packets belongs to.
+ * @return Pointer to the added entry or NULL if the packet had no valid destination of the specified type.
+ */
+static CargoDestEntry *AddCargoPacketToList(CargoDestEntry::List &list, CargoDestEntry::Type type, const CargoPacket *cp, const GoodsEntry &ge)
+{
+ assert_compile(INVALID_STATION == INVALID_SOURCE);
+
+ /* Extract the wanted sort type from the cargo packet. */
+ uint16 sort_val;
+ switch (type) {
+ case CargoDestEntry::FINAL_DEST:
+ sort_val = cp->DestinationID();
+ break;
+ case CargoDestEntry::NEXT_HOP:
+ sort_val = GetNextHopStation(ge, cp);
+ break;
+ case CargoDestEntry::TRANSFER_HOP:
+ sort_val = cp->NextStation();
+ break;
+ default:
+ NOT_REACHED();
+ }
+
+ if (sort_val == INVALID_STATION) return NULL;
+
+ /* Search for a matching child. */
+ for (CargoDestEntry::List::iterator i = list.begin(); i != list.end(); ++i) {
+ if (type == CargoDestEntry::FINAL_DEST ? i->data.css == sort_val && i->data.type == cp->DestinationType() : i->data.station == sort_val) {
+ i->data.count += cp->Count();
+ return &*i;
+ }
+ }
+
+ /* No entry found, add new. */
+ list.push_back(CargoDestEntry(type, sort_val, cp->Count(), cp->DestinationType()));
+ return &list.back();
+}
+
+
/**
* The StationView window
*/
@@ -808,6 +943,10 @@ struct StationViewWindow : public Window {
int rating_lines; ///< Number of lines in the cargo ratings view.
int accepts_lines; ///< Number of lines in the accepted cargo view.
Scrollbar *vscroll;
+ CargoDestEntry::List cargodest_list[NUM_CARGO]; ///< List of cargoes sorted by destination.
+
+ static StringID last_cargo_from_str;
+ static StringID last_cargo_from_tooltip;
/** Height of the #WID_SV_ACCEPT_RATING_LIST widget for different views. */
enum AcceptListHeight {
@@ -822,6 +961,7 @@ struct StationViewWindow : public Window {
this->CreateNestedTree(desc);
this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
+ this->GetWidget<NWidgetCore>(WID_SV_CARGO_FROM_TO_VIA)->SetDataTip(StationViewWindow::last_cargo_from_str, StationViewWindow::last_cargo_from_tooltip);
/* Nested widget tree creation is done in two steps to ensure that this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */
this->FinishInitNested(desc, window_number);
@@ -866,9 +1006,30 @@ struct StationViewWindow : public Window {
{
CargoDataList cargolist;
uint32 transfers = 0;
- this->OrderWaitingCargo(&cargolist, &transfers);
- this->vscroll->SetCount((int)cargolist.size() + 1); // update scrollbar
+ NWidgetCore *cargo_btn = this->GetWidget<NWidgetCore>(WID_SV_CARGO_FROM_TO_VIA);
+ if (cargo_btn->widget_data == STR_STATION_VIEW_WAITING_TO_BUTTON) {
+ this->OrderWaitingCargo(&cargolist, &transfers);
+ this->vscroll->SetCount((int)cargolist.size() + 1); // update scrollbar
+ } else {
+ /* Determine the current view. */
+ CargoDestEntry::Type dest_type;
+ switch (cargo_btn->widget_data) {
+ case STR_STATION_VIEW_WAITING_VIA_BUTTON:
+ dest_type = CargoDestEntry::FINAL_DEST;
+ break;
+ case STR_STATION_VIEW_WAITING_TRANSFER_BUTTON:
+ dest_type = CargoDestEntry::NEXT_HOP;
+ break;
+ case STR_STATION_VIEW_WAITING_BUTTON:
+ dest_type = CargoDestEntry::TRANSFER_HOP;
+ break;
+ default:
+ NOT_REACHED();
+ }
+ int num = this->FillCargodestList(dest_type, this->cargodest_list);
+ this->vscroll->SetCount(num + 1); // update scrollbar
+ }
/* disable some buttons */
const Station *st = Station::Get(this->window_number);
@@ -905,7 +1066,11 @@ struct StationViewWindow : public Window {
/* Draw waiting cargo. */
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SV_WAITING);
Rect waiting_rect = {nwi->pos_x, nwi->pos_y, nwi->pos_x + nwi->current_x - 1, nwi->pos_y + nwi->current_y - 1};
- this->DrawWaitingCargo(waiting_rect, cargolist, transfers);
+ if (cargo_btn->widget_data == STR_STATION_VIEW_WAITING_TO_BUTTON) {
+ this->DrawWaitingCargo(waiting_rect, cargolist, transfers);
+ } else {
+ this->DrawWaitingCargoByDest(waiting_rect, this->cargodest_list);
+ }
}
}
@@ -959,7 +1124,7 @@ struct StationViewWindow : public Window {
/* Check if we already have this source in the list */
for (CargoDataList::iterator jt(cargolist->begin()); jt != cargolist->end(); jt++) {
CargoData *cd = &(*jt);
- if (cd->cargo == i && cd->source == cp->SourceStation()) {
+ if (cd->cargo == i && cd->station == cp->SourceStation()) {
cd->count += cp->Count();
added = true;
break;
@@ -974,6 +1139,70 @@ struct StationViewWindow : public Window {
}
/**
+ * Fill cargo list sorted by type and destination/next hop.
+ * @param sort_via Set to true to sort by next hop, false to sort by final destination.
+ * @param list Cargo list to fill.
+ * @return Number of visible lines.
+ */
+ int FillCargodestList(CargoDestEntry::Type sort_by, CargoDestEntry::List *list)
+ {
+ StationID station_id = this->window_number;
+ const Station *st = Station::Get(station_id);
+
+ int lines = 0;
+
+ /* Fill the list for each cargo type. */
+ for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
+ /* Zero out all existing items. */
+ for (CargoDestEntry::List::iterator i = list[cid].begin(); i != list[cid].end(); ++i) {
+ i->Zero();
+ }
+
+ /* Remove all entries if no cargo of this type is present. */
+ if (st->goods[cid].cargo.Empty()) {
+ this->cargo_rows[cid] = 0;
+ list[cid].clear();
+ continue;
+ }
+
+ /* Store line number of the header line. */
+ this->cargo_rows[cid] = ++lines;
+
+ /* Add each cargo packet to the list. */
+ const StationCargoList::List *packets = st->goods[cid].cargo.Packets();
+ for (StationCargoList::ConstIterator it = packets->begin(); it != packets->end(); ++it) {
+ const CargoPacket *cp = *it;
+
+ /* Add entry and sub-entries according to the chosen sort type. */
+ static const CargoDestEntry::Type sort_types[][3] = {
+ {CargoDestEntry::FINAL_DEST, CargoDestEntry::NEXT_HOP, CargoDestEntry::TRANSFER_HOP},
+ {CargoDestEntry::NEXT_HOP, CargoDestEntry::TRANSFER_HOP, CargoDestEntry::FINAL_DEST},
+ {CargoDestEntry::TRANSFER_HOP, CargoDestEntry::NEXT_HOP, CargoDestEntry::FINAL_DEST}
+ };
+
+ CargoDestEntry *entry = AddCargoPacketToList(list[cid], sort_types[sort_by][0], cp, st->goods[cid]);
+ if (entry != NULL) {
+ entry = AddCargoPacketToList(entry->children, sort_types[sort_by][1], cp, st->goods[cid]);
+ if (entry != NULL) AddCargoPacketToList(entry->children, sort_types[sort_by][2], cp, st->goods[cid]);
+ }
+ }
+
+ /* Remove all empty list items and update visible row numbers. */
+ for (CargoDestEntry::List::iterator i = list[cid].begin(); i != list[cid].end(); ) {
+ if (i->data.count > 0) {
+ i->RemoveEmpty();
+ if (HasBit(this->cargo, cid)) lines = i->UpdateRowCount(lines);
+ ++i;
+ } else {
+ i = list[cid].erase(i);
+ }
+ }
+ }
+
+ return lines;
+ }
+
+ /**
* Draw waiting cargo.
* @param r Rectangle of the widget.
* @param cargolist Cargo, ordered by type and destination.
@@ -1006,7 +1235,7 @@ struct StationViewWindow : public Window {
for (CargoDataList::const_iterator it = cargolist.begin(); it != cargolist.end() && pos > -maxrows; ++it) {
if (--pos < 0) {
const CargoData *cd = &(*it);
- if (cd->source == INVALID_STATION) {
+ if (cd->station == INVALID_STATION) {
/* Heading */
DrawCargoIcons(cd->cargo, cd->count, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y);
SetDParam(0, cd->cargo);
@@ -1022,7 +1251,7 @@ struct StationViewWindow : public Window {
} else {
SetDParam(0, cd->cargo);
SetDParam(1, cd->count);
- SetDParam(2, cd->source);
+ SetDParam(2, cd->station);
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_EN_ROUTE_FROM, TC_FROMSTRING, SA_RIGHT);
}
@@ -1032,6 +1261,111 @@ struct StationViewWindow : public Window {
}
/**
+ * Draw a dest entry and its children.
+ * @param cid Current cargo type.
+ * @param pos Scroll position
+ * @param maxrows Number of visible rows.
+ * @param left Left string bound.
+ * @param right Right string bound.
+ * @param shrink_left Left bound of the expand marker.
+ * @param shrink_right Right bound of the expand marker.
+ * @param offs_left Child offset of the left bound.
+ * @param offs_right Child offset of the right bound.
+ * @param y Top of the current line.
+ * @param entry The entry to draw.
+ * @return The new y value.
+ */
+ int DrawSingleDestEntry(CargoID cid, int *pos, int maxrows, int left, int right, int shrink_left, int shrink_right, int offs_left, int offs_right, int y, const CargoDestEntry &entry) const
+ {
+ if (--(*pos) < 0) {
+ /* Draw current line. */
+ StringID str;
+
+ SetDParam(0, cid);
+ SetDParam(1, entry.data.count);
+ if (entry.type == CargoDestEntry::FINAL_DEST) {
+ SetDParam(2, entry.data.type == ST_INDUSTRY ? STR_INDUSTRY_NAME : (entry.data.type == ST_TOWN ? STR_TOWN_NAME : STR_COMPANY_NAME));
+ SetDParam(3, entry.data.css);
+ str = STR_STATION_VIEW_WAITING_TO;
+ } else {
+ SetDParam(2, entry.data.station);
+ str = (entry.type == CargoDestEntry::NEXT_HOP) ? STR_STATION_VIEW_WAITING_VIA : STR_STATION_VIEW_WAITING_TRANSFER;
+ }
+ DrawString(left, right, y, str);
+ y += FONT_HEIGHT_NORMAL;
+
+ if (!entry.children.empty()) {
+ /* Draw expand/collapse marker. */
+ DrawString(shrink_left, shrink_right, y - FONT_HEIGHT_NORMAL, entry.expanded ? "-" : "+", TC_YELLOW, SA_RIGHT);
+
+ if (entry.expanded) {
+ /* Draw visible children. */
+ for (CargoDestEntry::List::const_iterator i = entry.children.begin(); i != entry.children.end() && *pos > -maxrows; ++i) {
+ y = this->DrawSingleDestEntry(cid, pos, maxrows, left + offs_left, right + offs_right, shrink_left, shrink_right, offs_left, offs_right, y, *i);
+ }
+ }
+ }
+ }
+
+ return y;
+ }
+
+ /**
+ * Draw waiting cargo ordered by destination/next hop.
+ * @param r Rectangle of the widget.
+ * @param list List to draw.
+ */
+ void DrawWaitingCargoByDest(const Rect &r, const CargoDestEntry::List *list) const
+ {
+ int y = r.top + WD_FRAMERECT_TOP;
+ int pos = this->vscroll->GetPosition();
+
+ const Station *st = Station::Get(this->window_number);
+ if (--pos < 0) {
+ StringID str = STR_JUST_NOTHING;
+ for (CargoID i = 0; i < NUM_CARGO; i++) {
+ if (!st->goods[i].cargo.Empty()) str = STR_EMPTY;
+ }
+ SetDParam(0, str);
+ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_WAITING_TITLE);
+ y += FONT_HEIGHT_NORMAL;
+ }
+
+ bool rtl = _current_text_dir == TD_RTL;
+ int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT;
+ int text_right = rtl ? r.right - WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width;
+ int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT;
+ int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT;
+
+ int offs_left = rtl ? 0 : this->expand_shrink_width;
+ int offs_right = rtl ? this->expand_shrink_width : 0;
+
+ int maxrows = this->vscroll->GetCapacity();
+ for (CargoID cid = 0; cid < NUM_CARGO && pos > -maxrows; cid++) {
+ if (st->goods[cid].cargo.Empty()) continue;
+
+ if (--pos < 0) {
+ /* Draw heading. */
+ DrawCargoIcons(cid, st->goods[cid].cargo.Count(), r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMERECT_RIGHT, y);
+ SetDParam(0, cid);
+ SetDParam(1, st->goods[cid].cargo.Count());
+ DrawString(text_left, text_right, y, STR_STATION_VIEW_WAITING_CARGO, TC_FROMSTRING, SA_RIGHT);
+ if (!list[cid].empty()) {
+ DrawString(shrink_left, shrink_right, y, HasBit(this->cargo, cid) ? "-" : "+", TC_YELLOW, SA_RIGHT);
+ }
+ y += FONT_HEIGHT_NORMAL;
+ }
+
+ /* Draw sub-entries. */
+ if (HasBit(this->cargo, cid)) {
+ for (CargoDestEntry::List::const_iterator i = list[cid].begin(); i != list[cid].end() && pos > -maxrows; ++i) {
+ y = this->DrawSingleDestEntry(cid, &pos, maxrows, text_left + offs_left, text_right + offs_right, shrink_left, shrink_right, offs_left, offs_right, y, *i);
+ }
+ }
+ }
+ }
+
+ /**
* Draw accepted cargo in the #WID_SV_ACCEPT_RATING_LIST widget.
* @param r Rectangle of the widget.
* @return Number of lines needed for drawing the accepted cargo.
@@ -1082,16 +1416,93 @@ struct StationViewWindow : public Window {
return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL);
}
+ /**
+ * Test and handle a possible mouse click on a dest entry and its children.
+ * @param entry The entry to test for a hit.
+ * @param row The number of the clicked row.
+ * @return True if further entries need to be processed.
+ */
+ bool HandleCargoDestEntryClick(CargoDestEntry &entry, int row)
+ {
+ if (entry.start_row == row) {
+ if (_ctrl_pressed) {
+ /* Scroll viewport to destination tile .*/
+ TileIndex dest_tile = 0;
+ switch (entry.type) {
+ case CargoDestEntry::FINAL_DEST:
+ switch (entry.data.type) {
+ case ST_INDUSTRY:
+ dest_tile = Industry::Get(entry.data.css)->location.tile;
+ break;
+ case ST_TOWN:
+ dest_tile = Town::Get(entry.data.css)->xy;
+ break;
+ case ST_HEADQUARTERS:
+ dest_tile = Company::Get(entry.data.css)->location_of_HQ;
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+ break;
+
+ case CargoDestEntry::NEXT_HOP:
+ case CargoDestEntry::TRANSFER_HOP:
+ dest_tile = Station::Get(entry.data.station)->xy;
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+ ScrollMainWindowToTile(dest_tile);
+ } else if (!entry.children.empty()) {
+ /* Expand/collapse entry. */
+ entry.expanded = !entry.expanded;
+ this->SetWidgetDirty(WID_SV_WAITING);
+ this->SetWidgetDirty(WID_SV_SCROLLBAR);
+ }
+ }
+
+ if (entry.start_row < row) {
+ /* Test child entries. */
+ for (CargoDestEntry::List::iterator i = entry.children.begin(); i != entry.children.end(); ++i) {
+ if (!this->HandleCargoDestEntryClick(*i, row)) return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
void HandleCargoWaitingClick(int row)
{
if (row == 0) return;
+ bool dest_view = this->GetWidget<NWidgetCore>(WID_SV_CARGO_FROM_TO_VIA)->widget_data != STR_STATION_VIEW_WAITING_TO_BUTTON;
+
for (CargoID c = 0; c < NUM_CARGO; c++) {
+ /* Test for cargo type line. */
if (this->cargo_rows[c] == row) {
ToggleBit(this->cargo, c);
this->SetWidgetDirty(WID_SV_WAITING);
+ this->SetWidgetDirty(WID_SV_SCROLLBAR);
break;
}
+
+ if (dest_view) {
+ /* Test for dest view lines. */
+ for (CargoDestEntry::List::iterator i = this->cargodest_list[c].begin(); i != this->cargodest_list[c].end(); ++i) {
+ if (!this->HandleCargoDestEntryClick(*i, row)) break;
+ }
+ }
+ }
+ }
+
+ /** Clear the 'cargo by destination' list. */
+ void ClearCargodestList()
+ {
+ for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
+ this->cargodest_list[cid].clear();
}
}
@@ -1125,6 +1536,38 @@ struct StationViewWindow : public Window {
break;
}
+ case WID_SV_CARGO_FROM_TO_VIA: {
+ /* Swap between 'Source', 'Destination', 'Next hop' and 'Transfer' view.
+ * Store the new view so the next opened station window shows the same view. */
+ NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_SV_CARGO_FROM_TO_VIA);
+ switch (nwi->widget_data) {
+ case STR_STATION_VIEW_WAITING_BUTTON:
+ StationViewWindow::last_cargo_from_str = STR_STATION_VIEW_WAITING_TO_BUTTON;
+ StationViewWindow::last_cargo_from_tooltip = STR_STATION_VIEW_WAITING_TO_TOOLTIP;
+ break;
+ case STR_STATION_VIEW_WAITING_TO_BUTTON:
+ StationViewWindow::last_cargo_from_str = STR_STATION_VIEW_WAITING_VIA_BUTTON;
+ StationViewWindow::last_cargo_from_tooltip = STR_STATION_VIEW_WAITING_VIA_TOOLTIP;
+ break;
+ case STR_STATION_VIEW_WAITING_VIA_BUTTON:
+ StationViewWindow::last_cargo_from_str = STR_STATION_VIEW_WAITING_TRANSFER_BUTTON;
+ StationViewWindow::last_cargo_from_tooltip = STR_STATION_VIEW_WAITING_TRANSFER_TOOLTIP;
+ break;
+ case STR_STATION_VIEW_WAITING_TRANSFER_BUTTON:
+ StationViewWindow::last_cargo_from_str = STR_STATION_VIEW_WAITING_BUTTON;
+ StationViewWindow::last_cargo_from_tooltip = STR_STATION_VIEW_WAITING_TOOLTIP;
+ break;
+ default:
+ NOT_REACHED();
+ }
+ nwi->SetDataTip(StationViewWindow::last_cargo_from_str, StationViewWindow::last_cargo_from_tooltip);
+ this->ClearCargodestList();
+ this->SetWidgetDirty(WID_SV_CARGO_FROM_TO_VIA);
+ this->SetWidgetDirty(WID_SV_WAITING);
+ this->SetWidgetDirty(WID_SV_SCROLLBAR);
+ break;
+ }
+
case WID_SV_RENAME:
SetDParam(0, this->window_number);
ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
@@ -1142,7 +1585,11 @@ struct StationViewWindow : public Window {
Owner owner = Station::Get(this->window_number)->owner;
ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number);
break;
- }
+ }
+
+ case WID_SV_DEPARTURES:
+ ShowStationDepartures((StationID)this->window_number);
+ break;
}
}
@@ -1169,6 +1616,8 @@ struct StationViewWindow : public Window {
}
};
+StringID StationViewWindow::last_cargo_from_str = STR_STATION_VIEW_WAITING_VIA_BUTTON;
+StringID StationViewWindow::last_cargo_from_tooltip = STR_STATION_VIEW_WAITING_VIA_TOOLTIP;
static const WindowDesc _station_view_desc(
WDP_AUTO, 249, 110,
@@ -1254,8 +1703,15 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
_deleted_stations_nearby.Clear();
/* Check the inside, to return, if we sit on another station */
- TILE_AREA_LOOP(t, ta) {
- if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
+ FOR_ALL_LAYERS(layer) {
+ TILE_AREA_LOOP(tile, ta) {
+ TileIndex t = TopTile(tile) + layer * LayerSize();
+ if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t)))
+ {
+ if (t == tile) return T::GetByTile(t);
+ AddNearbyStation<T>(t, &ctx);
+ }
+ }
}
/* Look for deleted stations */
@@ -1263,14 +1719,14 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
FOR_ALL_BASE_STATIONS(st) {
if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
/* Include only within station spread (yes, it is strictly less than) */
- 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) {
+ if (max(DistanceMax(TopTile(ta.tile), TopTile(st->xy)), DistanceMax(TILE_ADDXY(TopTile(ta.tile), ta.w - 1, ta.h - 1), TopTile(st->xy))) < _settings_game.station.station_spread) {
TileAndStation *ts = _deleted_stations_nearby.Append();
ts->tile = st->xy;
ts->station = st->index;
/* Add the station when it's within where we're going to build */
- if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
- IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
+ if (IsInsideBS(LayerX(st->xy), LayerX(ctx.tile), ctx.w) &&
+ IsInsideBS(LayerY(st->xy), LayerY(ctx.tile), ctx.h)) {
AddNearbyStation<T>(st->xy, &ctx);
}
}
@@ -1283,8 +1739,11 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL;
uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1;
- TileIndex tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N));
- CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
+ FOR_ALL_LAYERS(layer) {
+ ctx.tile = TopTile(ctx.tile) + layer * LayerSize();
+ TileIndex tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N));
+ CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation<T>, &ctx);
+ }
return NULL;
}