diff options
Diffstat (limited to 'src/station_gui.cpp')
-rw-r--r-- | src/station_gui.cpp | 503 |
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; } |