Update to 15.0-beta1

This commit is contained in:
dP
2024-12-25 20:34:06 +05:00
parent 46dc456049
commit a86fd7c621
963 changed files with 38070 additions and 33798 deletions

View File

@@ -20,7 +20,9 @@
#include "string_func.h"
#include "window_func.h"
#include "viewport_func.h"
#include "widgets/dropdown_func.h"
#include "dropdown_type.h"
#include "dropdown_common_type.h"
#include "dropdown_func.h"
#include "station_base.h"
#include "waypoint_base.h"
#include "tilehighlight_func.h"
@@ -39,6 +41,29 @@
#include "safeguards.h"
struct StationTypeFilter
{
using StationType = Station;
static bool IsValidID(StationID id) { return Station::IsValidID(id); }
static bool IsValidBaseStation(const BaseStation *st) { return Station::IsExpected(st); }
static bool IsAcceptableWaypointTile(TileIndex) { return false; }
static constexpr bool IsWaypoint() { return false; }
};
template <bool ROAD, TileType TILE_TYPE>
struct GenericWaypointTypeFilter
{
using StationType = Waypoint;
static bool IsValidID(StationID id) { return Waypoint::IsValidID(id) && HasBit(Waypoint::Get(id)->waypoint_flags, WPF_ROAD) == ROAD; }
static bool IsValidBaseStation(const BaseStation *st) { return Waypoint::IsExpected(st) && HasBit(Waypoint::From(st)->waypoint_flags, WPF_ROAD) == ROAD; }
static bool IsAcceptableWaypointTile(TileIndex tile) { return IsTileType(tile, TILE_TYPE); }
static constexpr bool IsWaypoint() { return true; }
};
using RailWaypointTypeFilter = GenericWaypointTypeFilter<false, MP_RAILWAY>;
using RoadWaypointTypeFilter = GenericWaypointTypeFilter<true, MP_ROAD>;
/**
* Calculates and draws the accepted or supplied cargo around the selected tile(s)
* @param left x position where the string is to be drawn
@@ -85,28 +110,37 @@ void FindStationsAroundSelection()
{
/* With distant join we don't know which station will be selected, so don't show any */
if (_ctrl_pressed) {
SetViewportCatchmentSpecializedStation<T>(nullptr, true);
SetViewportCatchmentSpecializedStation<typename T::StationType>(nullptr, true);
return;
}
/* Tile area for TileHighlightData */
TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1);
/* If the current tile is already a station, then it must be the nearest station. */
if (IsTileType(location.tile, MP_STATION) && GetTileOwner(location.tile) == _local_company) {
typename T::StationType *st = T::StationType::GetByTile(location.tile);
if (st != nullptr && T::IsValidBaseStation(st)) {
SetViewportCatchmentSpecializedStation<typename T::StationType>(st, true);
return;
}
}
/* Extended area by one tile */
uint x = TileX(location.tile);
uint y = TileY(location.tile);
/* Waypoints can only be built on existing rail tiles, so don't extend area if not highlighting a rail tile. */
int max_c = T::EXPECTED_FACIL == FACIL_WAYPOINT && !IsTileType(location.tile, MP_RAILWAY) ? 0 : 1;
/* Waypoints can only be built on existing rail/road tiles, so don't extend area if not highlighting a rail tile. */
int max_c = T::IsWaypoint() && !T::IsAcceptableWaypointTile(location.tile) ? 0 : 1;
TileArea ta(TileXY(std::max<int>(0, x - max_c), std::max<int>(0, y - max_c)), TileXY(std::min<int>(Map::MaxX(), x + location.w + max_c), std::min<int>(Map::MaxY(), y + location.h + max_c)));
T *adjacent = nullptr;
typename T::StationType *adjacent = nullptr;
/* Direct loop instead of ForAllStationsAroundTiles as we are not interested in catchment area */
for (TileIndex tile : ta) {
if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) {
T *st = T::GetByTile(tile);
if (st == nullptr) continue;
typename T::StationType *st = T::StationType::GetByTile(tile);
if (st == nullptr || !T::IsValidBaseStation(st)) continue;
if (adjacent != nullptr && st != adjacent) {
/* Multiple nearby, distant join is required. */
adjacent = nullptr;
@@ -115,7 +149,7 @@ void FindStationsAroundSelection()
adjacent = st;
}
}
SetViewportCatchmentSpecializedStation<T>(adjacent, true);
SetViewportCatchmentSpecializedStation<typename T::StationType>(adjacent, true);
}
/**
@@ -137,12 +171,13 @@ void CheckRedrawStationCoverage(const Window *w)
w->SetDirty();
if (_settings_client.gui.station_show_coverage && _thd.drawstyle == HT_RECT) {
FindStationsAroundSelection<Station>();
FindStationsAroundSelection<StationTypeFilter>();
}
}
}
void CheckRedrawWaypointCoverage(const Window *)
template <typename T>
void CheckRedrawWaypointCoverage()
{
/* Test if ctrl state changed */
static bool _last_ctrl_pressed;
@@ -155,11 +190,21 @@ void CheckRedrawWaypointCoverage(const Window *)
_thd.dirty &= ~1;
if (_thd.drawstyle == HT_RECT) {
FindStationsAroundSelection<Waypoint>();
FindStationsAroundSelection<T>();
}
}
}
void CheckRedrawRailWaypointCoverage(const Window *)
{
CheckRedrawWaypointCoverage<RailWaypointTypeFilter>();
}
void CheckRedrawRoadWaypointCoverage(const Window *)
{
CheckRedrawWaypointCoverage<RoadWaypointTypeFilter>();
}
/**
* Draw small boxes of cargo amount and ratings data at the given
* coordinates. If amount exceeds 576 units, it is shown 'full', same
@@ -172,7 +217,7 @@ void CheckRedrawWaypointCoverage(const Window *)
* @param amount Cargo amount
* @param rating ratings data for that particular cargo
*/
static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating)
static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, uint8_t rating)
{
static const uint units_full = 576; ///< number of units to show station as 'full'
static const uint rating_full = 224; ///< rating needed so it is shown as 'full'
@@ -220,7 +265,7 @@ protected:
/* Runtime saved values */
struct FilterState {
Listing last_sorting;
byte facilities; ///< types of stations of interest
uint8_t facilities; ///< types of stations of interest
bool include_no_rating; ///< Whether we should include stations with no cargo rating.
CargoTypes cargoes; ///< bitmap of cargo types to include
};
@@ -233,8 +278,15 @@ protected:
};
/* Constants for sorting stations */
static const StringID sorter_names[];
static GUIStationList::SortFunction * const sorter_funcs[];
static inline const StringID sorter_names[] = {
STR_SORT_BY_NAME,
STR_SORT_BY_FACILITY,
STR_SORT_BY_WAITING_TOTAL,
STR_SORT_BY_WAITING_AVAILABLE,
STR_SORT_BY_RATING_MAX,
STR_SORT_BY_RATING_MIN,
};
static const std::initializer_list<GUIStationList::SortFunction * const> sorter_funcs;
FilterState filter;
GUIStationList stations{filter.cargoes};
@@ -260,8 +312,8 @@ protected:
this->stations_per_cargo_type_no_rating = 0;
for (const Station *st : Station::Iterate()) {
if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
if (this->filter.facilities & st->facilities) { // only stations with selected facilities
if ((this->filter.facilities & st->facilities) != 0) { // only stations with selected facilities
if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) {
bool has_rating = false;
/* Add to the station/cargo counts. */
for (CargoID j = 0; j < NUM_CARGO; j++) {
@@ -285,7 +337,6 @@ protected:
}
}
this->stations.shrink_to_fit();
this->stations.RebuildDone();
this->vscroll->SetCount(this->stations.size()); // Update the scrollbar
@@ -332,8 +383,8 @@ protected:
/** Sort stations by their rating */
static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
{
byte maxr1 = 0;
byte maxr2 = 0;
uint8_t maxr1 = 0;
uint8_t maxr2 = 0;
for (CargoID j : SetCargoBitIterator(cargo_filter)) {
if (a->goods[j].HasRating()) maxr1 = std::max(maxr1, a->goods[j].rating);
@@ -346,8 +397,8 @@ protected:
/** Sort stations by their rating */
static bool StationRatingMinSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
{
byte minr1 = 255;
byte minr2 = 255;
uint8_t minr1 = 255;
uint8_t minr2 = 255;
for (CargoID j : SetCargoBitIterator(cargo_filter)) {
if (a->goods[j].HasRating()) minr1 = std::min(minr1, a->goods[j].rating);
@@ -367,7 +418,7 @@ protected:
}
public:
CompanyStationsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
CompanyStationsWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
{
/* Load initial filter state. */
this->filter = CompanyStationsWindow::initial_state;
@@ -390,7 +441,7 @@ public:
if (HasBit(this->filter.facilities, i)) this->LowerWidget(i + WID_STL_TRAIN);
}
this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = CompanyStationsWindow::sorter_names[this->stations.SortType()];
}
~CompanyStationsWindow()
@@ -400,31 +451,28 @@ public:
CompanyStationsWindow::initial_state = this->filter;
}
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
{
switch (widget) {
case WID_STL_SORTBY: {
Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
d.height += padding.height;
*size = maxdim(*size, d);
size = maxdim(size, d);
break;
}
case WID_STL_SORTDROPBTN: {
Dimension d = {0, 0};
for (int i = 0; CompanyStationsWindow::sorter_names[i] != INVALID_STRING_ID; i++) {
d = maxdim(d, GetStringBoundingBox(CompanyStationsWindow::sorter_names[i]));
}
Dimension d = GetStringListBoundingBox(CompanyStationsWindow::sorter_names);
d.width += padding.width;
d.height += padding.height;
*size = maxdim(*size, d);
size = maxdim(size, d);
break;
}
case WID_STL_LIST:
resize->height = std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL) + ScaleGUITrad(3));
size->height = padding.height + 5 * resize->height;
resize.height = std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL) + ScaleGUITrad(3));
size.height = padding.height + 5 * resize.height;
/* Determine appropriate width for mini station rating graph */
this->rating_width = 0;
@@ -455,7 +503,6 @@ public:
case WID_STL_LIST: {
bool rtl = _current_text_dir == TD_RTL;
size_t max = std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.size());
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
uint line_height = this->GetWidget<NWidgetBase>(widget)->resize_y;
/* Spacing between station name and first rating graph. */
@@ -463,8 +510,9 @@ public:
/* Spacing between additional rating graphs. */
int rating_spacing = WidgetDimensions::scaled.hsep_normal;
for (size_t i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner
const Station *st = this->stations[i];
auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->stations);
for (auto it = first; it != last; ++it) {
const Station *st = *it;
assert(st->xy != INVALID_TILE);
/* Do not do the complex check HasStationInUse here, it may be even false
@@ -533,8 +581,8 @@ public:
using DropDownListCargoItem = DropDownCheck<DropDownString<DropDownListIconItem, FS_SMALL, true>>;
DropDownList list;
list.push_back(std::make_unique<DropDownListStringItem>(STR_STATION_LIST_CARGO_FILTER_SELECT_ALL, CargoFilterCriteria::CF_SELECT_ALL));
list.push_back(std::make_unique<DropDownListDividerItem>(-1));
list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_SELECT_ALL, CargoFilterCriteria::CF_SELECT_ALL));
list.push_back(MakeDropDownListDividerItem());
bool any_hidden = false;
@@ -556,8 +604,8 @@ public:
}
if (!expanded && any_hidden) {
if (list.size() > 2) list.push_back(std::make_unique<DropDownListDividerItem>(-1));
list.push_back(std::make_unique<DropDownListStringItem>(STR_STATION_LIST_CARGO_FILTER_EXPAND, CargoFilterCriteria::CF_EXPAND_LIST));
if (list.size() > 2) list.push_back(MakeDropDownListDividerItem());
list.push_back(MakeDropDownListStringItem(STR_STATION_LIST_CARGO_FILTER_EXPAND, CargoFilterCriteria::CF_EXPAND_LIST));
}
return list;
@@ -567,7 +615,7 @@ public:
{
switch (widget) {
case WID_STL_LIST: {
auto it = this->vscroll->GetScrolledItemFromWidget(this->stations, pt.y, this, WID_STL_LIST);
auto it = this->vscroll->GetScrolledItemFromWidget(this->stations, pt.y, this, WID_STL_LIST, WidgetDimensions::scaled.framerect.top);
if (it == this->stations.end()) return; // click out of list bound
const Station *st = *it;
@@ -617,7 +665,7 @@ public:
break;
case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu
ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0);
ShowDropDownMenu(this, CompanyStationsWindow::sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0);
break;
case WID_STL_CARGODROPDOWN:
@@ -634,7 +682,7 @@ public:
this->stations.SetSortType(index);
/* Display the current sort variant */
this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()];
this->GetWidget<NWidgetCore>(WID_STL_SORTDROPBTN)->widget_data = CompanyStationsWindow::sorter_names[this->stations.SortType()];
this->SetDirty();
}
@@ -709,7 +757,7 @@ public:
};
/* Available station sorting functions */
GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
const std::initializer_list<GUIStationList::SortFunction * const> CompanyStationsWindow::sorter_funcs = {
&StationNameSorter,
&StationTypeSorter,
&StationWaitingTotalSorter,
@@ -718,17 +766,6 @@ GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
&StationRatingMinSorter
};
/* Names of the sorting functions */
const StringID CompanyStationsWindow::sorter_names[] = {
STR_SORT_BY_NAME,
STR_SORT_BY_FACILITY,
STR_SORT_BY_WAITING_TOTAL,
STR_SORT_BY_WAITING_AVAILABLE,
STR_SORT_BY_RATING_MAX,
STR_SORT_BY_RATING_MIN,
INVALID_STRING_ID
};
static constexpr NWidgetPart _nested_company_stations_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
@@ -738,12 +775,12 @@ static constexpr NWidgetPart _nested_company_stations_widgets[] = {
NWidget(WWT_STICKYBOX, COLOUR_GREY),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 0), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 0), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 0), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 0), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 0), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 0), SetDataTip(STR_ABBREV_ALL, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetTextStyle(TC_BLACK, FS_SMALL), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_FACILALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetDataTip(STR_ABBREV_ALL, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetTextStyle(TC_BLACK, FS_SMALL), SetFill(0, 1),
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 0), SetFill(0, 1), EndContainer(),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_CARGODROPDOWN), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE),
NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
@@ -762,11 +799,11 @@ static constexpr NWidgetPart _nested_company_stations_widgets[] = {
EndContainer(),
};
static WindowDesc _company_stations_desc(__FILE__, __LINE__,
static WindowDesc _company_stations_desc(
WDP_AUTO, "list_stations", 358, 162,
WC_STATION_LIST, WC_NONE,
0,
std::begin(_nested_company_stations_widgets), std::end(_nested_company_stations_widgets)
_nested_company_stations_widgets
);
/**
@@ -778,15 +815,15 @@ void ShowCompanyStations(CompanyID company)
{
if (!Company::IsValidID(company)) return;
AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
AllocateWindowDescFront<CompanyStationsWindow>(_company_stations_desc, company);
}
static constexpr NWidgetPart _nested_station_view_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_RENAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetDataTip(SPR_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(12, 14), SetDataTip(SPR_GOTO_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_LOCATION), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetDataTip(SPR_GOTO_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
NWidget(WWT_SHADEBOX, COLOUR_GREY),
NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
NWidget(WWT_STICKYBOX, COLOUR_GREY),
@@ -810,10 +847,10 @@ static constexpr NWidgetPart _nested_station_view_widgets[] = {
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1),
SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CATCHMENT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
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),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP),
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
EndContainer(),
};
@@ -849,7 +886,7 @@ enum SortOrder {
class CargoDataEntry;
enum class CargoSortType : byte {
enum class CargoSortType : uint8_t {
AsGrouping, ///< by the same principle the entries are being grouped
Count, ///< by amount of cargo
StationString, ///< by station name
@@ -1275,14 +1312,26 @@ struct StationViewWindow : public Window {
int accepts_lines; ///< Number of lines in the accepted cargo view.
Scrollbar *vscroll;
/** Height of the #WID_SV_ACCEPT_RATING_LIST widget for different views. */
enum AcceptListHeight {
ALH_RATING = 13, ///< Height of the cargo ratings view.
ALH_ACCEPTS = 3, ///< Height of the accepted cargo view.
};
/* Height of the #WID_SV_ACCEPT_RATING_LIST widget for different views. */
static constexpr uint RATING_LINES = 13; ///< Height in lines of the cargo ratings view.
static constexpr uint ACCEPTS_LINES = 3; ///< Height in lines of the accepted cargo view.
static const StringID _sort_names[]; ///< Names of the sorting options in the dropdown.
static const StringID _group_names[]; ///< Names of the grouping options in the dropdown.
/** Names of the sorting options in the dropdown. */
static inline const StringID sort_names[] = {
STR_STATION_VIEW_WAITING_STATION,
STR_STATION_VIEW_WAITING_AMOUNT,
STR_STATION_VIEW_PLANNED_STATION,
STR_STATION_VIEW_PLANNED_AMOUNT,
};
/** Names of the grouping options in the dropdown. */
static inline const StringID group_names[] = {
STR_STATION_VIEW_GROUP_S_V_D,
STR_STATION_VIEW_GROUP_S_D_V,
STR_STATION_VIEW_GROUP_V_S_D,
STR_STATION_VIEW_GROUP_V_D_S,
STR_STATION_VIEW_GROUP_D_S_V,
STR_STATION_VIEW_GROUP_D_V_S,
};
/**
* Sort types of the different 'columns'.
@@ -1304,11 +1353,11 @@ struct StationViewWindow : public Window {
CargoDataEntry cached_destinations; ///< Cache for the flows passing through this station.
CargoDataVector displayed_rows; ///< Parent entry of currently displayed rows (including collapsed ones).
StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc),
StationViewWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc),
scroll_to_row(INT_MAX), grouping_index(0)
{
this->rating_lines = ALH_RATING;
this->accepts_lines = ALH_ACCEPTS;
this->rating_lines = RATING_LINES;
this->accepts_lines = ACCEPTS_LINES;
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR);
@@ -1381,25 +1430,25 @@ struct StationViewWindow : public Window {
data->Update(count);
}
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
{
switch (widget) {
case WID_SV_WAITING:
resize->height = GetCharacterHeight(FS_NORMAL);
size->height = 4 * resize->height + padding.height;
resize.height = GetCharacterHeight(FS_NORMAL);
size.height = 4 * resize.height + padding.height;
this->expand_shrink_width = std::max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width);
break;
case WID_SV_ACCEPT_RATING_LIST:
size->height = ((this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) ? this->accepts_lines : this->rating_lines) * GetCharacterHeight(FS_NORMAL) + padding.height;
size.height = ((this->GetWidget<NWidgetCore>(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) ? this->accepts_lines : this->rating_lines) * GetCharacterHeight(FS_NORMAL) + padding.height;
break;
case WID_SV_CLOSE_AIRPORT:
if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) {
/* Hide 'Close Airport' button if no airport present. */
size->width = 0;
resize->width = 0;
fill->width = 0;
size.width = 0;
resize.width = 0;
fill.width = 0;
}
break;
}
@@ -1967,14 +2016,14 @@ struct StationViewWindow : public Window {
* sorting criteria for columns 1, 2, and 3. Column 0 is always
* sorted by cargo ID. The others can theoretically be sorted
* by different things but there is no UI for that. */
ShowDropDownMenu(this, _sort_names,
ShowDropDownMenu(this, StationViewWindow::sort_names,
this->current_mode * 2 + (this->sortings[1] == CargoSortType::Count ? 1 : 0),
WID_SV_SORT_BY, 0, 0);
break;
}
case WID_SV_GROUP_BY: {
ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
ShowDropDownMenu(this, StationViewWindow::group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0);
break;
}
@@ -2005,7 +2054,7 @@ struct StationViewWindow : public Window {
void SelectSortBy(int index)
{
_settings_client.gui.station_gui_sort_by = index;
switch (_sort_names[index]) {
switch (StationViewWindow::sort_names[index]) {
case STR_STATION_VIEW_WAITING_STATION:
this->current_mode = MODE_WAITING;
this->sortings[1] = this->sortings[2] = this->sortings[3] = CargoSortType::AsGrouping;
@@ -2026,7 +2075,7 @@ struct StationViewWindow : public Window {
NOT_REACHED();
}
/* Display the current sort variant */
this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->widget_data = _sort_names[index];
this->GetWidget<NWidgetCore>(WID_SV_SORT_BY)->widget_data = StationViewWindow::sort_names[index];
this->SetDirty();
}
@@ -2038,8 +2087,8 @@ struct StationViewWindow : public Window {
{
this->grouping_index = index;
_settings_client.gui.station_gui_group_order = index;
this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->widget_data = _group_names[index];
switch (_group_names[index]) {
this->GetWidget<NWidgetCore>(WID_SV_GROUP_BY)->widget_data = StationViewWindow::group_names[index];
switch (StationViewWindow::group_names[index]) {
case STR_STATION_VIEW_GROUP_S_V_D:
this->groupings[1] = GR_SOURCE;
this->groupings[2] = GR_NEXT;
@@ -2083,11 +2132,11 @@ struct StationViewWindow : public Window {
}
}
void OnQueryTextFinished(char *str) override
void OnQueryTextFinished(std::optional<std::string> str) override
{
if (str == nullptr) return;
if (!str.has_value()) return;
Command<CMD_RENAME_STATION>::Post(STR_ERROR_CAN_T_RENAME_STATION, this->window_number, str);
Command<CMD_RENAME_STATION>::Post(STR_ERROR_CAN_T_RENAME_STATION, this->window_number, *str);
}
void OnResize() override
@@ -2112,29 +2161,11 @@ struct StationViewWindow : public Window {
}
};
const StringID StationViewWindow::_sort_names[] = {
STR_STATION_VIEW_WAITING_STATION,
STR_STATION_VIEW_WAITING_AMOUNT,
STR_STATION_VIEW_PLANNED_STATION,
STR_STATION_VIEW_PLANNED_AMOUNT,
INVALID_STRING_ID
};
const StringID StationViewWindow::_group_names[] = {
STR_STATION_VIEW_GROUP_S_V_D,
STR_STATION_VIEW_GROUP_S_D_V,
STR_STATION_VIEW_GROUP_V_S_D,
STR_STATION_VIEW_GROUP_V_D_S,
STR_STATION_VIEW_GROUP_D_S_V,
STR_STATION_VIEW_GROUP_D_V_S,
INVALID_STRING_ID
};
static WindowDesc _station_view_desc(__FILE__, __LINE__,
static WindowDesc _station_view_desc(
WDP_AUTO, "view_station", 249, 117,
WC_STATION_VIEW, WC_NONE,
0,
std::begin(_nested_station_view_widgets), std::end(_nested_station_view_widgets)
_nested_station_view_widgets
);
/**
@@ -2144,7 +2175,7 @@ static WindowDesc _station_view_desc(__FILE__, __LINE__,
*/
void ShowStationViewWindow(StationID station)
{
AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
AllocateWindowDescFront<StationViewWindow>(_station_view_desc, station);
}
/** Struct containing TileIndex and StationID */
@@ -2161,7 +2192,7 @@ static std::vector<StationID> _stations_nearby_list;
* station spread.
* @param tile Tile just being checked
* @param user_data Pointer to TileArea context
* @tparam T the type of station to look for
* @tparam T the station filter type
*/
template <class T>
static bool AddNearbyStation(TileIndex tile, void *user_data)
@@ -2186,8 +2217,8 @@ static bool AddNearbyStation(TileIndex tile, void *user_data)
/* This station is (likely) a waypoint */
if (!T::IsValidID(sid)) return false;
T *st = T::Get(sid);
if (st->owner != _local_company || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false;
BaseStation *st = BaseStation::Get(sid);
if (st->owner != _local_company || std::ranges::find(_stations_nearby_list, sid) != _stations_nearby_list.end()) return false;
if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
_stations_nearby_list.push_back(sid);
@@ -2203,10 +2234,10 @@ static bool AddNearbyStation(TileIndex tile, void *user_data)
* @param ta Base tile area of the to-be-built station
* @param distant_join Search for adjacent stations (false) or stations fully
* within station spread
* @tparam T the type of station to look for
* @tparam T the station filter type, for stations to look for
*/
template <class T>
static const T *FindStationsNearby(TileArea ta, bool distant_join)
static const BaseStation *FindStationsNearby(TileArea ta, bool distant_join)
{
TileArea ctx = ta;
@@ -2216,14 +2247,14 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join)
/* Check the inside, to return, if we sit on another station */
for (TileIndex t : ta) {
if (t < Map::Size() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t);
if (t < Map::Size() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return BaseStation::GetByTile(t);
}
/* Look for deleted stations */
for (const BaseStation *st : BaseStation::Iterate()) {
if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) {
if (T::IsValidBaseStation(st) && !st->IsInUse() && st->owner == _local_company) {
/* Include only within station spread (yes, it is strictly less than) */
if (std::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 (std::max(DistanceMax(ta.tile, st->xy), DistanceMax(TileAddXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) {
_deleted_stations_nearby.push_back({st->xy, st->index});
/* Add the station when it's within where we're going to build */
@@ -2264,7 +2295,7 @@ static constexpr NWidgetPart _nested_select_station_widgets[] = {
/**
* Window for selecting stations/waypoints to (distant) join to.
* @tparam T The type of station to join with
* @tparam T The station filter type, for stations to join with
*/
template <class T>
struct SelectStationWindow : Window {
@@ -2272,14 +2303,14 @@ struct SelectStationWindow : Window {
TileArea area; ///< Location of new station
Scrollbar *vscroll;
SelectStationWindow(WindowDesc *desc, TileArea ta, StationPickerCmdProc&& proc) :
SelectStationWindow(WindowDesc &desc, TileArea ta, StationPickerCmdProc&& proc) :
Window(desc),
select_station_proc(std::move(proc)),
area(ta)
{
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR);
this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
this->GetWidget<NWidgetCore>(WID_JS_CAPTION)->widget_data = T::IsWaypoint() ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION;
this->FinishInitNested(0);
this->OnInvalidateData(0);
@@ -2288,31 +2319,31 @@ struct SelectStationWindow : Window {
void Close([[maybe_unused]] int data = 0) override
{
SetViewportCatchmentSpecializedStation<T>(nullptr, true);
SetViewportCatchmentSpecializedStation<typename T::StationType>(nullptr, true);
_thd.freeze = false;
this->Window::Close();
}
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
{
if (widget != WID_JS_PANEL) return;
/* Determine the widest string */
Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
Dimension d = GetStringBoundingBox(T::IsWaypoint() ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
for (const auto &station : _stations_nearby_list) {
if (station == NEW_STATION) continue;
const T *st = T::Get(station);
const BaseStation *st = BaseStation::Get(station);
SetDParam(0, st->index);
SetDParam(1, st->facilities);
d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION));
d = maxdim(d, GetStringBoundingBox(T::IsWaypoint() ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION));
}
resize->height = d.height;
resize.height = d.height;
d.height *= 5;
d.width += padding.width;
d.height += padding.height;
*size = d;
size = d;
}
void DrawWidget(const Rect &r, WidgetID widget) const override
@@ -2320,14 +2351,15 @@ struct SelectStationWindow : Window {
if (widget != WID_JS_PANEL) return;
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
for (uint i = this->vscroll->GetPosition(); i < _stations_nearby_list.size(); ++i, tr.top += this->resize.step_height) {
if (_stations_nearby_list[i] == NEW_STATION) {
DrawString(tr, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
auto [first, last] = this->vscroll->GetVisibleRangeIterators(_stations_nearby_list);
for (auto it = first; it != last; ++it, tr.top += this->resize.step_height) {
if (*it == NEW_STATION) {
DrawString(tr, T::IsWaypoint() ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION);
} else {
const T *st = T::Get(_stations_nearby_list[i]);
const BaseStation *st = BaseStation::Get(*it);
SetDParam(0, st->index);
SetDParam(1, st->facilities);
DrawString(tr, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION);
DrawString(tr, T::IsWaypoint() ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION);
}
}
@@ -2376,22 +2408,22 @@ struct SelectStationWindow : Window {
void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
{
if (widget != WID_JS_PANEL) {
SetViewportCatchmentSpecializedStation<T>(nullptr, true);
SetViewportCatchmentSpecializedStation<typename T::StationType>(nullptr, true);
return;
}
/* Show coverage area of station under cursor */
auto it = this->vscroll->GetScrolledItemFromWidget(_stations_nearby_list, pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top);
const T *st = it == _stations_nearby_list.end() || *it == NEW_STATION ? nullptr : T::Get(*it);
SetViewportCatchmentSpecializedStation<T>(st, true);
const typename T::StationType *st = it == _stations_nearby_list.end() || *it == NEW_STATION ? nullptr : T::StationType::Get(*it);
SetViewportCatchmentSpecializedStation<typename T::StationType>(st, true);
}
};
static WindowDesc _select_station_desc(__FILE__, __LINE__,
static WindowDesc _select_station_desc(
WDP_AUTO, "build_station_join", 200, 180,
WC_SELECT_STATION, WC_NONE,
WDF_CONSTRUCTION,
std::begin(_nested_select_station_widgets), std::end(_nested_select_station_widgets)
_nested_select_station_widgets
);
@@ -2399,7 +2431,7 @@ static WindowDesc _select_station_desc(__FILE__, __LINE__,
* Check whether we need to show the station selection window.
* @param cmd Command to build the station.
* @param ta Tile area of the to-be-built station
* @tparam T the type of station
* @tparam T the station filter type
* @return whether we need to show the station selection window.
*/
template <class T>
@@ -2423,11 +2455,7 @@ static bool StationJoinerNeeded(TileArea ta, const StationPickerCmdProc &proc)
/* Now check if we could build there */
if (!proc(true, INVALID_STATION)) return false;
/* Test for adjacent station or station below selection.
* If adjacent-stations is disabled and we are building next to a station, do not show the selection window.
* but join the other station immediately. */
const T *st = FindStationsNearby<T>(ta, false);
return st == nullptr && (_settings_game.station.adjacent_stations || std::any_of(std::begin(_stations_nearby_list), std::end(_stations_nearby_list), [](StationID s) { return s != NEW_STATION; }));
return FindStationsNearby<T>(ta, false) == nullptr;
}
/**
@@ -2441,7 +2469,7 @@ void ShowSelectBaseStationIfNeeded(TileArea ta, StationPickerCmdProc&& proc)
{
if (StationJoinerNeeded<T>(ta, proc)) {
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
new SelectStationWindow<T>(&_select_station_desc, ta, std::move(proc));
new SelectStationWindow<T>(_select_station_desc, ta, std::move(proc));
} else {
proc(false, INVALID_STATION);
}
@@ -2454,15 +2482,25 @@ void ShowSelectBaseStationIfNeeded(TileArea ta, StationPickerCmdProc&& proc)
*/
void ShowSelectStationIfNeeded(TileArea ta, StationPickerCmdProc proc)
{
ShowSelectBaseStationIfNeeded<Station>(ta, std::move(proc));
ShowSelectBaseStationIfNeeded<StationTypeFilter>(ta, std::move(proc));
}
/**
* Show the waypoint selection window when needed. If not, build the waypoint.
* Show the rail waypoint selection window when needed. If not, build the waypoint.
* @param ta Area to build the waypoint in
* @param proc Function called to execute the build command.
*/
void ShowSelectWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
void ShowSelectRailWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
{
ShowSelectBaseStationIfNeeded<Waypoint>(ta, std::move(proc));
ShowSelectBaseStationIfNeeded<RailWaypointTypeFilter>(ta, std::move(proc));
}
/**
* Show the road waypoint selection window when needed. If not, build the waypoint.
* @param ta Area to build the waypoint in
* @param proc Function called to execute the build command.
*/
void ShowSelectRoadWaypointIfNeeded(TileArea ta, StationPickerCmdProc proc)
{
ShowSelectBaseStationIfNeeded<RoadWaypointTypeFilter>(ta, std::move(proc));
}