Feature: Signs, waypoint and station names may be moved (#14744)

This commit is contained in:
mmtunligit
2025-11-24 20:56:19 +01:00
committed by dP
parent f5a6604482
commit c34a433a07
19 changed files with 380 additions and 28 deletions

View File

@@ -214,6 +214,7 @@ enum Commands : uint8_t {
CMD_BUILD_RAIL_WAYPOINT, ///< build a waypoint
CMD_RENAME_WAYPOINT, ///< rename a waypoint
CMD_MOVE_WAYPOINT_NAME, ///< move a waypoint name
CMD_REMOVE_FROM_RAIL_WAYPOINT, ///< remove a (rectangle of) tiles from a rail waypoint
CMD_BUILD_ROAD_WAYPOINT, ///< build a road waypoint
@@ -275,10 +276,12 @@ enum Commands : uint8_t {
CMD_RENAME_COMPANY, ///< change the company name
CMD_RENAME_PRESIDENT, ///< change the president name
CMD_RENAME_STATION, ///< rename a station
CMD_MOVE_STATION_NAME, ///< move a station name
CMD_RENAME_DEPOT, ///< rename a depot
CMD_PLACE_SIGN, ///< place a sign
CMD_RENAME_SIGN, ///< rename a sign
CMD_MOVE_SIGN, ///< move a sign
CMD_TURN_ROADVEH, ///< turn a road vehicle around

View File

@@ -312,6 +312,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}By enabl
STR_BUTTON_DEFAULT :{BLACK}Default
STR_BUTTON_CANCEL :{BLACK}Cancel
STR_BUTTON_OK :{BLACK}OK
STR_BUTTON_MOVE :{BLACK}Move
# On screen keyboard window
STR_OSK_KEYBOARD_LAYOUT :`1234567890-= qwertyuiop[]asdfghjkl;'#\zxcvbnm,./ .
@@ -3687,7 +3688,7 @@ STR_SIGN_LIST_MATCH_CASE :{BLACK}Match ca
STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing sign names against the filter string
# Sign window
STR_EDIT_SIGN_CAPTION :{WHITE}Edit sign text
STR_EDIT_SIGN_CAPTION :{WHITE}Edit sign
STR_EDIT_SIGN_LOCATION_TOOLTIP :{BLACK}Centre the main view on sign location. Ctrl+Click to open a new viewport on sign location
STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Go to next sign
STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Go to previous sign
@@ -3904,14 +3905,14 @@ STR_CARGO_RATING_EXCELLENT :Excellent
STR_CARGO_RATING_OUTSTANDING :Outstanding
STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on station location. Ctrl+Click to open a new viewport on station location
STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Change name of station
STR_STATION_VIEW_EDIT_TOOLTIP :{BLACK}Rename station or move sign
STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Show all trains which have this station on their schedule
STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Show all road vehicles which have this station on their schedule
STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Show all aircraft which have this station on their schedule
STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Show all ships which have this station on their schedule
STR_STATION_VIEW_RENAME_STATION_CAPTION :Rename station/loading area
STR_STATION_VIEW_EDIT_STATION_SIGN :{WHITE}Edit station sign
STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Close airport
STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Prevent aircraft from landing on this airport
@@ -3919,11 +3920,11 @@ STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Prevent
# Waypoint/buoy view window
STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT}
STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on waypoint location. Ctrl+Click to open a new viewport on waypoint location
STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Change waypoint name
STR_WAYPOINT_VIEW_EDIT_TOOLTIP :{BLACK}Rename waypoint or move sign
STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on buoy location. Ctrl+Click to open a new viewport on buoy location
STR_BUOY_VIEW_RENAME_TOOLTIP :{BLACK}Change buoy name
STR_EDIT_WAYPOINT_NAME :{WHITE}Edit waypoint name
STR_WAYPOINT_VIEW_EDIT_WAYPOINT_SIGN :{WHITE}Edit waypoint sign
# Finances window
STR_FINANCES_CAPTION :{WHITE}{COMPANY} Finances {BLACK}{COMPANY_NUM}
@@ -5137,6 +5138,7 @@ STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Too many
STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Too close to another dock
STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Too close to another airport
STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Can't rename station...
STR_ERROR_CAN_T_MOVE_STATION_NAME :{WHITE}Can't move station sign...
STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... road owned by a town
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... road facing in the wrong direction
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... drive through stops can't have corners
@@ -5168,6 +5170,7 @@ STR_ERROR_CAN_T_BUILD_RAIL_WAYPOINT :{WHITE}Can't bu
STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT :{WHITE}Can't build road waypoint here...
STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Can't place buoy here...
STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Can't change waypoint name...
STR_ERROR_CAN_T_MOVE_WAYPOINT_NAME :{WHITE}Can't move waypoint sign...
STR_ERROR_CAN_T_REMOVE_RAIL_WAYPOINT :{WHITE}Can't remove rail waypoint here...
STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT :{WHITE}Can't remove road waypoint here...

View File

@@ -13,11 +13,14 @@
#include "error.h"
#include "gui.h"
#include "gfx_layout.h"
#include "tilehighlight_func.h"
#include "command_func.h"
#include "company_func.h"
#include "town.h"
#include "string_func.h"
#include "company_base.h"
#include "station_base.h"
#include "waypoint_base.h"
#include "texteff.hpp"
#include "strings_func.h"
#include "window_func.h"
@@ -27,6 +30,8 @@
#include "zoom_func.h"
#include "viewport_func.h"
#include "landscape_cmd.h"
#include "station_cmd.h"
#include "waypoint_cmd.h"
#include "rev.h"
#include "timer/timer.h"
#include "timer/timer_window.h"
@@ -899,6 +904,8 @@ struct QueryStringWindow : public Window
QueryString editbox; ///< Editbox.
QueryStringFlags flags{}; ///< Flags controlling behaviour of the window.
WidgetID last_user_action = INVALID_WIDGET; ///< Last started user action.
QueryStringWindow(std::string_view str, StringID caption, uint max_bytes, uint max_chars, WindowDesc &desc, Window *parent, CharSetFilter afilter, QueryStringFlags flags) :
Window(desc), editbox(max_bytes, max_chars)
{
@@ -913,7 +920,9 @@ struct QueryStringWindow : public Window
this->editbox.text.afilter = afilter;
this->flags = flags;
this->InitNested(WN_QUERY_STRING);
this->CreateNestedTree();
this->GetWidget<NWidgetStacked>(WID_QS_MOVE_SEL)->SetDisplayedPlane((this->flags.Test(QueryStringFlag::EnableMove)) ? 0 : SZSP_NONE);
this->FinishInitNested(WN_QUERY_STRING);
this->parent = parent;
@@ -961,16 +970,64 @@ struct QueryStringWindow : public Window
case WID_QS_CANCEL:
this->Close();
break;
case WID_QS_MOVE:
this->last_user_action = widget;
if (Station::IsExpected(Station::Get(this->parent->window_number))) {
/* this is a station */
SetViewportStationRect(Station::Get(this->parent->window_number), !this->IsWidgetLowered(WID_QS_MOVE));
} else {
/* this is a waypoint */
SetViewportWaypointRect(Waypoint::Get(this->parent->window_number), !this->IsWidgetLowered(WID_QS_MOVE));
}
HandlePlacePushButton(this, WID_QS_MOVE, SPR_CURSOR_SIGN, HT_RECT);
break;
}
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
{
switch (this->last_user_action) {
case WID_QS_MOVE: // Move name button
if (Station::IsExpected(Station::Get(this->parent->window_number))) {
/* this is a station */
Command<CMD_MOVE_STATION_NAME>::Post(STR_ERROR_CAN_T_MOVE_STATION_NAME, CcMoveStationName, this->parent->window_number, tile);
} else {
/* this is a waypoint */
Command<CMD_MOVE_WAYPOINT_NAME>::Post(STR_ERROR_CAN_T_MOVE_WAYPOINT_NAME, CcMoveWaypointName, this->parent->window_number, tile);
}
break;
default: NOT_REACHED();
}
}
void OnPlaceObjectAbort() override
{
if (Station::IsExpected(Station::Get(this->parent->window_number))) {
/* this is a station */
SetViewportStationRect(Station::Get(this->parent->window_number), false);
} else {
/* this is a waypoint */
SetViewportWaypointRect(Waypoint::Get(this->parent->window_number), false);
}
this->RaiseButtons();
}
void Close([[maybe_unused]] int data = 0) override
{
if (this->parent->window_class == WC_STATION_VIEW) SetViewportStationRect(Station::Get(this->parent->window_number), false);
if (this->parent->window_class == WC_WAYPOINT_VIEW) SetViewportWaypointRect(Waypoint::Get(this->parent->window_number), false);
if (!this->editbox.handled && this->parent != nullptr) {
Window *parent = this->parent;
this->parent = nullptr; // so parent doesn't try to close us again
parent->OnQueryTextFinished(std::nullopt);
}
this->Window::Close();
}
};
@@ -984,9 +1041,12 @@ static constexpr std::initializer_list<NWidgetPart> _nested_query_string_widgets
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_QS_TEXT), SetMinimalSize(256, 0), SetFill(1, 0), SetPadding(2, 2, 2, 2),
EndContainer(),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_DEFAULT), SetMinimalSize(87, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_DEFAULT),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_CANCEL), SetMinimalSize(86, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_CANCEL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_OK), SetMinimalSize(87, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_OK),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_DEFAULT), SetMinimalSize(65, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_DEFAULT),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_CANCEL), SetMinimalSize(65, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_CANCEL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_OK), SetMinimalSize(65, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_OK),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_QS_MOVE_SEL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_MOVE), SetMinimalSize(65, 12), SetFill(1, 1), SetStringTip(STR_BUTTON_MOVE),
EndContainer(),
EndContainer(),
};

View File

@@ -55,11 +55,11 @@ void UpdateAllSignVirtCoords()
}
/**
* Check if the current company can rename a given sign.
* Check if the current company can rename or move a given sign.
* @param *si The sign in question.
* @return true if the sign can be renamed, else false.
* @return true if the sign can be renamed or moved, else false.
*/
bool CompanyCanRenameSign(const Sign *si)
bool CompanyCanEditSign(const Sign *si)
{
if (si->owner == OWNER_DEITY && _current_company != OWNER_DEITY && _game_mode != GM_EDITOR) return false;
return true;

View File

@@ -68,7 +68,7 @@ CommandCost CmdRenameSign(DoCommandFlags flags, SignID sign_id, const std::strin
{
Sign *si = Sign::GetIfValid(sign_id);
if (si == nullptr) return CMD_ERROR;
if (!CompanyCanRenameSign(si)) return CMD_ERROR;
if (!CompanyCanEditSign(si)) return CMD_ERROR;
/* Rename the signs when empty, otherwise remove it */
if (!text.empty()) {
@@ -95,6 +95,36 @@ CommandCost CmdRenameSign(DoCommandFlags flags, SignID sign_id, const std::strin
return CommandCost();
}
/**
* Move a sign to the given coordinates. Ownership of signs
* has no meaning/effect whatsoever except for eyecandy.
* @param flags type of operation
* @param sign_id index of the sign to be moved
* @param tile tile to place the sign at
* @return the cost of this operation or an error
*/
CommandCost CmdMoveSign(DoCommandFlags flags, SignID sign_id, TileIndex tile)
{
Sign *si = Sign::GetIfValid(sign_id);
if (si == nullptr) return CMD_ERROR;
if (!CompanyCanEditSign(si)) return CMD_ERROR;
/* Move the sign */
if (flags.Test(DoCommandFlag::Execute)) {
int x = TileX(tile) * TILE_SIZE;
int y = TileY(tile) * TILE_SIZE;
si->x = x;
si->y = y;
si->z = GetSlopePixelZ(x, y);
if (_game_mode != GM_EDITOR) si->owner = _current_company;
si->UpdateVirtCoord();
}
return CommandCost();
}
/**
* Callback function that is called after a sign is placed
* @param result of the operation

View File

@@ -15,9 +15,11 @@
std::tuple<CommandCost, SignID> CmdPlaceSign(DoCommandFlags flags, TileIndex tile, const std::string &text);
CommandCost CmdRenameSign(DoCommandFlags flags, SignID sign_id, const std::string &text);
CommandCost CmdMoveSign(DoCommandFlags flags, SignID sign_id, TileIndex tile);
DEF_CMD_TRAIT(CMD_PLACE_SIGN, CmdPlaceSign, CommandFlag::Deity, CommandType::OtherManagement)
DEF_CMD_TRAIT(CMD_RENAME_SIGN, CmdRenameSign, CommandFlag::Deity, CommandType::OtherManagement)
DEF_CMD_TRAIT(CMD_MOVE_SIGN, CmdMoveSign, CommandFlag::Deity, CommandType::OtherManagement)
void CcPlaceSign(Commands cmd, const CommandCost &result, SignID new_sign);

View File

@@ -17,7 +17,7 @@ struct Window;
void UpdateAllSignVirtCoords();
void PlaceProc_Sign(TileIndex tile);
bool CompanyCanRenameSign(const Sign *si);
bool CompanyCanEditSign(const Sign *si);
/* signs_gui.cpp */
void ShowRenameSignWindow(const Sign *si);

View File

@@ -20,6 +20,7 @@
#include "viewport_func.h"
#include "querystring_gui.h"
#include "sortlist_type.h"
#include "tilehighlight_func.h"
#include "stringfilter_type.h"
#include "string_func.h"
#include "core/geometry_func.hpp"
@@ -387,9 +388,20 @@ static bool RenameSign(SignID index, std::string_view text)
return remove;
}
/**
* Actually move the sign.
* @param index the sign to move.
* @param tile on which to move the sign to.
*/
void MoveSign(SignID index, TileIndex tile)
{
Command<CMD_MOVE_SIGN>::Post(STR_ERROR_CAN_T_PLACE_SIGN_HERE, index, tile);
}
struct SignWindow : Window, SignList {
QueryString name_editbox;
SignID cur_sign{};
WidgetID last_user_action = INVALID_WIDGET; ///< Last started user action.
SignWindow(WindowDesc &desc, const Sign *si) : Window(desc), name_editbox(MAX_LENGTH_SIGN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_SIGN_NAME_CHARS)
{
@@ -487,12 +499,6 @@ struct SignWindow : Window, SignList {
break;
}
case WID_QES_DELETE:
/* Only need to set the buffer to null, the rest is handled as the OK button */
RenameSign(this->cur_sign, "");
/* don't delete this, we are deleted in Sign::~Sign() -> DeleteRenameSignWindow() */
break;
case WID_QES_OK:
if (RenameSign(this->cur_sign, this->name_editbox.text.GetText())) break;
[[fallthrough]];
@@ -500,8 +506,37 @@ struct SignWindow : Window, SignList {
case WID_QES_CANCEL:
this->Close();
break;
case WID_QES_DELETE:
/* Only need to set the buffer to null, the rest is handled as the OK button */
RenameSign(this->cur_sign, "");
/* don't delete this, we are deleted in Sign::~Sign() -> DeleteRenameSignWindow() */
break;
case WID_QES_MOVE:
HandlePlacePushButton(this, WID_QES_MOVE, SPR_CURSOR_SIGN, HT_RECT);
this->last_user_action = widget;
break;
}
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
{
switch (this->last_user_action) {
case WID_QES_MOVE: // Place sign button
RenameSign(this->cur_sign, this->name_editbox.text.GetText());
MoveSign(this->cur_sign, tile);
this->Close();
break;
default: NOT_REACHED();
}
}
void OnPlaceObjectAbort() override
{
this->RaiseButtons();
}
};
static constexpr std::initializer_list<NWidgetPart> _nested_query_sign_edit_widgets = {
@@ -517,7 +552,7 @@ static constexpr std::initializer_list<NWidgetPart> _nested_query_sign_edit_widg
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_QES_OK), SetMinimalSize(61, 12), SetStringTip(STR_BUTTON_OK),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_QES_CANCEL), SetMinimalSize(60, 12), SetStringTip(STR_BUTTON_CANCEL),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_QES_DELETE), SetMinimalSize(60, 12), SetStringTip(STR_TOWN_VIEW_DELETE_BUTTON),
NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QES_MOVE), SetMinimalSize(60, 12), SetStringTip(STR_BUTTON_MOVE),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_QES_PREVIOUS), SetMinimalSize(11, 12), SetArrowWidgetTypeTip(AWV_DECREASE, STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_QES_NEXT), SetMinimalSize(11, 12), SetArrowWidgetTypeTip(AWV_INCREASE, STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP),
EndContainer(),
@@ -536,8 +571,8 @@ static WindowDesc _query_sign_edit_desc(
*/
void HandleClickOnSign(const Sign *si)
{
/* If we can't rename the sign, don't even open the rename GUI. */
if (!CompanyCanRenameSign(si)) return;
/* If we can't edit the sign, don't even open the rename GUI. */
if (!CompanyCanEditSign(si)) return;
if (_ctrl_pressed && (si->owner == _local_company || (si->owner == OWNER_DEITY && _game_mode == GM_EDITOR))) {
RenameSign(si->index, "");

View File

@@ -29,6 +29,7 @@
#include "road_internal.h" /* For drawing catenary/checking road removal */
#include "autoslope.h"
#include "water.h"
#include "tilehighlight_func.h"
#include "strings_func.h"
#include "clear_func.h"
#include "timer/timer_game_calendar.h"
@@ -71,6 +72,7 @@
#include "station_layout_type.h"
#include "widgets/station_widget.h"
#include "widgets/misc_widget.h"
#include "table/strings.h"
#include "table/station_land.h"
@@ -4475,6 +4477,59 @@ CommandCost CmdRenameStation(DoCommandFlags flags, StationID station_id, const s
return CommandCost();
}
/**
* Move a station name.
* @param flags type of operation
* @param station_id id of the station
* @param tile to move the station name to
* @return the cost of this operation or an error and the station ID
*/
std::tuple<CommandCost, StationID> CmdMoveStationName(DoCommandFlags flags, StationID station_id, TileIndex tile)
{
Station *st = Station::GetIfValid(station_id);
if (st == nullptr) return { CMD_ERROR, StationID::Invalid() };
if (st->owner != OWNER_NONE) {
CommandCost ret = CheckOwnership(st->owner);
if (ret.Failed()) return { ret, StationID::Invalid() };
}
const StationRect *r = &st->rect;
if (!r->PtInExtendedRect(TileX(tile), TileY(tile))) {
return { CommandCost(STR_ERROR_SITE_UNSUITABLE), StationID::Invalid() };
}
bool other_station = false;
/* Check if the tile is the base tile of another station */
ForAllStationsRadius(tile, 0, [&](BaseStation *s) {
if (s != nullptr) {
if (s != st && s->xy == tile) other_station = true;
}
});
if (other_station) return { CommandCost(STR_ERROR_SITE_UNSUITABLE), StationID::Invalid() };
if (flags.Test(DoCommandFlag::Execute)) {
st->MoveSign(tile);
st->UpdateVirtCoord();
}
return { CommandCost(), station_id };
}
/**
* Callback function that is called after a name is moved
* @param result of the operation
* @param station_id ID of the changed station
*/
void CcMoveStationName(Commands, const CommandCost &result, StationID station_id)
{
if (result.Failed()) return;
ResetObjectToPlace();
Station *st = Station::Get(station_id);
SetViewportStationRect(st, false);
}
static void AddNearbyStationsByCatchment(TileIndex tile, StationList &stations, StationList &nearby)
{
for (Station *st : nearby) {

View File

@@ -30,6 +30,7 @@ CommandCost CmdRemoveFromRailStation(DoCommandFlags flags, TileIndex start, Tile
CommandCost CmdBuildRoadStop(DoCommandFlags flags, TileIndex tile, uint8_t width, uint8_t length, RoadStopType stop_type, bool is_drive_through, DiagDirection ddir, RoadType rt, RoadStopClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent);
CommandCost CmdRemoveRoadStop(DoCommandFlags flags, TileIndex tile, uint8_t width, uint8_t height, RoadStopType stop_type, bool remove_road);
CommandCost CmdRenameStation(DoCommandFlags flags, StationID station_id, const std::string &text);
std::tuple<CommandCost, StationID> CmdMoveStationName(DoCommandFlags flags, StationID station_id, TileIndex tile);
CommandCost CmdOpenCloseAirport(DoCommandFlags flags, StationID station_id);
DEF_CMD_TRAIT(CMD_BUILD_AIRPORT, CmdBuildAirport, CommandFlags({CommandFlag::Auto, CommandFlag::NoWater}), CommandType::LandscapeConstruction)
@@ -39,6 +40,9 @@ DEF_CMD_TRAIT(CMD_REMOVE_FROM_RAIL_STATION, CmdRemoveFromRailStation, {},
DEF_CMD_TRAIT(CMD_BUILD_ROAD_STOP, CmdBuildRoadStop, CommandFlags({CommandFlag::Auto, CommandFlag::NoWater}), CommandType::LandscapeConstruction)
DEF_CMD_TRAIT(CMD_REMOVE_ROAD_STOP, CmdRemoveRoadStop, {}, CommandType::LandscapeConstruction)
DEF_CMD_TRAIT(CMD_RENAME_STATION, CmdRenameStation, {}, CommandType::OtherManagement)
DEF_CMD_TRAIT(CMD_MOVE_STATION_NAME, CmdMoveStationName, {}, CommandType::OtherManagement)
DEF_CMD_TRAIT(CMD_OPEN_CLOSE_AIRPORT, CmdOpenCloseAirport, {}, CommandType::RouteManagement)
void CcMoveStationName(Commands cmd, const CommandCost &result, StationID station_id);
#endif /* STATION_CMD_H */

View File

@@ -35,6 +35,7 @@
#include "station_cmd.h"
#include "widgets/station_widget.h"
#include "widgets/misc_widget.h"
#include "table/strings.h"
@@ -814,7 +815,7 @@ void ShowCompanyStations(CompanyID company)
static constexpr std::initializer_list<NWidgetPart> _nested_station_view_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_RENAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_RENAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_STATION_VIEW_EDIT_TOOLTIP),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SV_LOCATION), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetSpriteTip(SPR_GOTO_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP),
NWidget(WWT_SHADEBOX, COLOUR_GREY),
@@ -1957,6 +1958,8 @@ struct StationViewWindow : public Window {
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
Window *w = FindWindowByClass(WC_QUERY_STRING);
switch (widget) {
case WID_SV_WAITING:
this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WidgetDimensions::scaled.framerect.top) - this->vscroll->GetPosition());
@@ -1964,6 +1967,11 @@ struct StationViewWindow : public Window {
case WID_SV_CATCHMENT:
SetViewportCatchmentStation(Station::Get(this->window_number), !this->IsWidgetLowered(WID_SV_CATCHMENT));
if (w != nullptr && this->IsWidgetLowered(WID_SV_CATCHMENT)) {
if (w->parent->window_class == WC_STATION_VIEW && w->IsWidgetLowered(WID_QS_MOVE)) SetViewportStationRect(Station::Get(w->parent->window_number), true);
if (w->parent->window_class == WC_WAYPOINT_VIEW && w->IsWidgetLowered(WID_QS_MOVE)) SetViewportWaypointRect(Waypoint::Get(w->parent->window_number), true);
}
break;
case WID_SV_LOCATION:
@@ -1990,8 +1998,8 @@ struct StationViewWindow : public Window {
}
case WID_SV_RENAME:
ShowQueryString(GetString(STR_STATION_NAME, this->window_number), STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
this, CS_ALPHANUMERAL, {QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars});
ShowQueryString(GetString(STR_STATION_NAME, this->window_number), STR_STATION_VIEW_EDIT_STATION_SIGN, MAX_LENGTH_STATION_NAME_CHARS,
this, CS_ALPHANUMERAL, {QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars, QueryStringFlag::EnableMove});
break;
case WID_SV_CLOSE_AIRPORT:

View File

@@ -19,6 +19,7 @@ enum class QueryStringFlag : uint8_t {
AcceptUnchanged, ///< return success even when the text didn't change
EnableDefault, ///< enable the 'Default' button ("\0" is returned)
LengthIsInChars, ///< the length of the string is counted in characters
EnableMove, ///< enable the 'Move' button
};
using QueryStringFlags = EnumBitSet<QueryStringFlag, uint8_t>;

View File

@@ -1009,7 +1009,9 @@ enum TileHighlightType : uint8_t {
};
const Station *_viewport_highlight_station; ///< Currently selected station for coverage area highlight
const Station *_viewport_highlight_station_rect; ///< Currently selected station for rectangle highlight
const Waypoint *_viewport_highlight_waypoint; ///< Currently selected waypoint for coverage area highlight
const Waypoint *_viewport_highlight_waypoint_rect; ///< Currently selected waypoint for rectangle highlight
const Town *_viewport_highlight_town; ///< Currently selected town for coverage area highlight
/**
@@ -1023,10 +1025,23 @@ static TileHighlightType GetTileHighlightType(TileIndex t)
if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station->index) return THT_WHITE;
if (_viewport_highlight_station->TileIsInCatchment(t)) return THT_BLUE;
}
if (_viewport_highlight_station_rect != nullptr) {
if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station_rect->index) return THT_WHITE;
const StationRect *r = &_viewport_highlight_station_rect->rect;
if (r->PtInExtendedRect(TileX(t), TileY(t))) return THT_BLUE;
}
if (_viewport_highlight_waypoint != nullptr) {
if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_waypoint->index) return THT_BLUE;
}
if (_viewport_highlight_waypoint_rect != nullptr) {
if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_waypoint_rect->index) return THT_WHITE;
const StationRect *r = &_viewport_highlight_waypoint_rect->rect;
if (r->PtInExtendedRect(TileX(t), TileY(t))) return THT_BLUE;
}
if (_viewport_highlight_town != nullptr) {
if (IsTileType(t, MP_HOUSE)) {
if (GetTownIndex(t) == _viewport_highlight_town->index) {
@@ -3635,6 +3650,7 @@ void MarkCatchmentTilesDirty()
MarkWholeScreenDirty();
return;
}
if (_viewport_highlight_station != nullptr) {
if (_viewport_highlight_station->catchment_tiles.tile == INVALID_TILE) {
MarkWholeScreenDirty();
@@ -3646,18 +3662,35 @@ void MarkCatchmentTilesDirty()
}
}
}
if (_viewport_highlight_station_rect != nullptr) {
if (!_viewport_highlight_station_rect->IsInUse()) {
_viewport_highlight_station_rect = nullptr;
}
MarkWholeScreenDirty();
}
if (_viewport_highlight_waypoint != nullptr) {
if (!_viewport_highlight_waypoint->IsInUse()) {
_viewport_highlight_waypoint = nullptr;
}
MarkWholeScreenDirty();
}
if (_viewport_highlight_waypoint_rect != nullptr) {
if (!_viewport_highlight_waypoint_rect->IsInUse()) {
_viewport_highlight_waypoint_rect = nullptr;
}
MarkWholeScreenDirty();
}
}
static void SetWindowDirtyForViewportCatchment()
{
if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index);
if (_viewport_highlight_station_rect != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station_rect->index);
if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index);
if (_viewport_highlight_waypoint_rect != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint_rect->index);
if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index);
}
@@ -3665,7 +3698,9 @@ static void ClearViewportCatchment()
{
MarkCatchmentTilesDirty();
_viewport_highlight_station = nullptr;
_viewport_highlight_station_rect = nullptr;
_viewport_highlight_waypoint = nullptr;
_viewport_highlight_waypoint_rect = nullptr;
_viewport_highlight_town = nullptr;
}
@@ -3689,6 +3724,26 @@ void SetViewportCatchmentStation(const Station *st, bool sel)
if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index);
}
/**
* Select or deselect station for rectangle area highlight.
* Selecting a station will deselect a town.
* @param *st Station in question
* @param sel Select or deselect given station
*/
void SetViewportStationRect(const Station *st, bool sel)
{
SetWindowDirtyForViewportCatchment();
if (sel && _viewport_highlight_station_rect != st) { // mark tiles dirty for redrawing and update selected station if a different station is already highlighted
ClearViewportCatchment();
_viewport_highlight_station_rect = st;
MarkCatchmentTilesDirty();
} else if (!sel && _viewport_highlight_station_rect == st) { // mark tiles dirty for redrawing and clear station selection if deselecting highlight
MarkCatchmentTilesDirty();
_viewport_highlight_station_rect = nullptr;
}
if (_viewport_highlight_station_rect != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station_rect->index); // redraw the currently selected station window
}
/**
* Select or deselect waypoint for coverage area highlight.
* Selecting a waypoint will deselect a town.
@@ -3709,6 +3764,26 @@ void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel)
if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index);
}
/**
* Select or deselect waypoint for rectangle area highlight.
* Selecting a waypoint will deselect a town.
* @param *wp Waypoint in question
* @param sel Select or deselect given waypoint
*/
void SetViewportWaypointRect(const Waypoint *wp, bool sel)
{
SetWindowDirtyForViewportCatchment();
if (sel && _viewport_highlight_waypoint_rect != wp) { // mark tiles dirty for redrawing and update selected waypoint if a different waypoint is already highlighted
ClearViewportCatchment();
_viewport_highlight_waypoint_rect = wp;
MarkCatchmentTilesDirty();
} else if (!sel && _viewport_highlight_waypoint_rect == wp) { // mark tiles dirty for redrawing and clear waypoint selection if deselecting highlight
MarkCatchmentTilesDirty();
_viewport_highlight_waypoint_rect = nullptr;
}
if (_viewport_highlight_waypoint_rect != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint_rect->index); // redraw the currently selected waypoint window
}
/**
* Select or deselect town for coverage area highlight.
* Selecting a town will deselect a station.

View File

@@ -104,7 +104,9 @@ struct Waypoint;
struct Town;
void SetViewportCatchmentStation(const Station *st, bool sel);
void SetViewportStationRect(const Station *st, bool sel);
void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel);
void SetViewportWaypointRect(const Waypoint *wp, bool sel);
void SetViewportCatchmentTown(const Town *t, bool sel);
void MarkCatchmentTilesDirty();

View File

@@ -16,9 +16,11 @@
#include "waypoint_base.h"
#include "pathfinder/yapf/yapf_cache.h"
#include "pathfinder/water_regions.h"
#include "tilehighlight_func.h"
#include "strings_func.h"
#include "viewport_func.h"
#include "viewport_kdtree.h"
#include "station_kdtree.h"
#include "window_func.h"
#include "timer/timer_game_calendar.h"
#include "vehicle_func.h"
@@ -33,6 +35,8 @@
#include "landscape_cmd.h"
#include "station_layout_type.h"
#include "widgets/misc_widget.h"
#include "table/strings.h"
#include "safeguards.h"
@@ -603,3 +607,56 @@ CommandCost CmdRenameWaypoint(DoCommandFlags flags, StationID waypoint_id, const
}
return CommandCost();
}
/**
* Move a waypoint name.
* @param flags type of operation
* @param waypoint_id id of waypoint
* @param tile to move the waypoint name to
* @return the cost of this operation or an error and the waypoint ID
*/
std::tuple<CommandCost, StationID> CmdMoveWaypointName(DoCommandFlags flags, StationID waypoint_id, TileIndex tile)
{
Waypoint *wp = Waypoint::GetIfValid(waypoint_id);
if (wp == nullptr) return { CMD_ERROR, StationID::Invalid() };
if (wp->owner != OWNER_NONE) {
CommandCost ret = CheckOwnership(wp->owner);
if (ret.Failed()) return { ret, StationID::Invalid() };
}
const StationRect *r = &wp->rect;
if (!r->PtInExtendedRect(TileX(tile), TileY(tile))) {
return { CommandCost(STR_ERROR_SITE_UNSUITABLE), StationID::Invalid() };
}
bool other_station = false;
/* Check if the tile is the base tile of another station */
ForAllStationsRadius(tile, 0, [&](BaseStation *st) {
if (st != nullptr) {
if (st != wp && st->xy == tile) other_station = true;
}
});
if (other_station) return { CommandCost(STR_ERROR_SITE_UNSUITABLE), StationID::Invalid() };
if (flags.Test(DoCommandFlag::Execute)) {
wp->MoveSign(tile);
wp->UpdateVirtCoord();
}
return { CommandCost(), waypoint_id };
}
/**
* Callback function that is called after a name is moved
* @param result of the operation
* @param waypoint_id ID of the changed waypoint
*/
void CcMoveWaypointName(Commands, const CommandCost &result, StationID waypoint_id)
{
if (result.Failed()) return;
ResetObjectToPlace();
Waypoint *wp = Waypoint::Get(waypoint_id);
SetViewportCatchmentWaypoint(wp, false);
}

View File

@@ -22,6 +22,7 @@ CommandCost CmdBuildRoadWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
CommandCost CmdRemoveFromRoadWaypoint(DoCommandFlags flags, TileIndex start, TileIndex end);
CommandCost CmdBuildBuoy(DoCommandFlags flags, TileIndex tile);
CommandCost CmdRenameWaypoint(DoCommandFlags flags, StationID waypoint_id, const std::string &text);
std::tuple<CommandCost, StationID> CmdMoveWaypointName(DoCommandFlags flags, StationID waypoint_id, TileIndex tile);
DEF_CMD_TRAIT(CMD_BUILD_RAIL_WAYPOINT, CmdBuildRailWaypoint, {}, CommandType::LandscapeConstruction)
DEF_CMD_TRAIT(CMD_REMOVE_FROM_RAIL_WAYPOINT, CmdRemoveFromRailWaypoint, {}, CommandType::LandscapeConstruction)
@@ -29,5 +30,8 @@ DEF_CMD_TRAIT(CMD_BUILD_ROAD_WAYPOINT, CmdBuildRoadWaypoint, {},
DEF_CMD_TRAIT(CMD_REMOVE_FROM_ROAD_WAYPOINT, CmdRemoveFromRoadWaypoint, {}, CommandType::LandscapeConstruction)
DEF_CMD_TRAIT(CMD_BUILD_BUOY, CmdBuildBuoy, CommandFlag::Auto, CommandType::LandscapeConstruction)
DEF_CMD_TRAIT(CMD_RENAME_WAYPOINT, CmdRenameWaypoint, {}, CommandType::OtherManagement)
DEF_CMD_TRAIT(CMD_MOVE_WAYPOINT_NAME, CmdMoveWaypointName, {}, CommandType::OtherManagement)
void CcMoveWaypointName(Commands cmd, const CommandCost &result, StationID waypoint_id);
#endif /* WAYPOINT_CMD_H */

View File

@@ -20,10 +20,12 @@
#include "company_base.h"
#include "window_func.h"
#include "waypoint_base.h"
#include "station_base.h"
#include "waypoint_cmd.h"
#include "zoom_func.h"
#include "widgets/waypoint_widget.h"
#include "widgets/misc_widget.h"
#include "table/strings.h"
@@ -87,7 +89,7 @@ public:
}
if (this->vt != VEH_SHIP) {
this->GetWidget<NWidgetCore>(WID_W_CENTER_VIEW)->SetToolTip(STR_WAYPOINT_VIEW_CENTER_TOOLTIP);
this->GetWidget<NWidgetCore>(WID_W_RENAME)->SetToolTip(STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME);
this->GetWidget<NWidgetCore>(WID_W_RENAME)->SetToolTip(STR_WAYPOINT_VIEW_EDIT_TOOLTIP);
}
this->FinishInitNested(window_number);
@@ -125,6 +127,8 @@ public:
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
Window *w = FindWindowByClass(WC_QUERY_STRING);
switch (widget) {
case WID_W_CENTER_VIEW: // scroll to location
if (_ctrl_pressed) {
@@ -135,7 +139,8 @@ public:
break;
case WID_W_RENAME: // rename
ShowQueryString(GetString(STR_WAYPOINT_NAME, this->wp->index), STR_EDIT_WAYPOINT_NAME, MAX_LENGTH_STATION_NAME_CHARS, this, CS_ALPHANUMERAL, {QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars});
ShowQueryString(GetString(STR_WAYPOINT_NAME, this->wp->index), STR_WAYPOINT_VIEW_EDIT_WAYPOINT_SIGN, MAX_LENGTH_STATION_NAME_CHARS, this, CS_ALPHANUMERAL,
{QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars, QueryStringFlag::EnableMove});
break;
case WID_W_SHOW_VEHICLES: // show list of vehicles having this waypoint in their orders
@@ -144,6 +149,11 @@ public:
case WID_W_CATCHMENT:
SetViewportCatchmentWaypoint(Waypoint::Get(this->window_number), !this->IsWidgetLowered(WID_W_CATCHMENT));
if (w != nullptr && this->IsWidgetLowered(WID_W_CATCHMENT)) {
if (w->parent->window_class == WC_STATION_VIEW && w->IsWidgetLowered(WID_QS_MOVE)) SetViewportStationRect(Station::Get(w->parent->window_number), true);
if (w->parent->window_class == WC_WAYPOINT_VIEW && w->IsWidgetLowered(WID_QS_MOVE)) SetViewportWaypointRect(Waypoint::Get(w->parent->window_number), true);
}
break;
}
}

View File

@@ -35,6 +35,8 @@ enum QueryStringWidgets : WidgetID {
WID_QS_DEFAULT, ///< Default button.
WID_QS_CANCEL, ///< Cancel button.
WID_QS_OK, ///< OK button.
WID_QS_MOVE, ///< Move button.
WID_QS_MOVE_SEL, ///< Container for move button, which can be hidden.
};
/** Widgets of the #QueryWindow class. */

View File

@@ -28,6 +28,7 @@ enum QueryEditSignWidgets : WidgetID {
WID_QES_OK, ///< OK button.
WID_QES_CANCEL, ///< Cancel button.
WID_QES_DELETE, ///< Delete button.
WID_QES_MOVE, ///< Move Sign button.
WID_QES_PREVIOUS, ///< Previous button.
WID_QES_NEXT, ///< Next button.
};