1
0
Fork 0
Peter Nelson 2025-06-26 12:41:37 +01:00 committed by GitHub
commit fef283f9c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 381 additions and 176 deletions

View File

@ -63,7 +63,7 @@ void CcBuildAirport(Commands, const CommandCost &result, TileIndex tile)
* Place an airport.
* @param tile Position to put the new airport.
*/
static void PlaceAirport(TileIndex tile)
static void PlaceAirport(bool query, TileIndex tile)
{
if (_selected_airport_index == -1) return;
@ -71,9 +71,14 @@ static void PlaceAirport(TileIndex tile)
uint8_t layout = _selected_airport_layout;
bool adjacent = _ctrl_pressed;
if (query) {
HandleSelectionQuery(Command<CMD_BUILD_AIRPORT>::Query(tile, airport_type, layout, StationID::Invalid(), adjacent));
return;
}
auto proc = [=](bool test, StationID to_join) -> bool {
if (test) {
return Command<CMD_BUILD_AIRPORT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_AIRPORT>()), tile, airport_type, layout, StationID::Invalid(), adjacent).Succeeded();
return Command<CMD_BUILD_AIRPORT>::Query(tile, airport_type, layout, StationID::Invalid(), adjacent).Succeeded();
} else {
return Command<CMD_BUILD_AIRPORT>::Post(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE, CcBuildAirport, tile, airport_type, layout, to_join, adjacent);
}
@ -141,15 +146,15 @@ struct BuildAirToolbarWindow : Window {
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
switch (this->last_user_action) {
case WID_AT_AIRPORT:
PlaceAirport(tile);
PlaceAirport(query, tile);
break;
case WID_AT_DEMOLISH:
PlaceProc_DemolishArea(tile);
PlaceProc_DemolishArea(query, tile);
break;
default: NOT_REACHED();
@ -161,10 +166,10 @@ struct BuildAirToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
GUIPlaceProcDragXY(query, select_proc, start_tile, end_tile);
}
}

View File

@ -94,6 +94,8 @@ protected:
static void LogCommandExecution(Commands cmd, StringID err_message, const CommandDataBuffer &args, bool failed);
};
void HandleSelectionQuery(CommandCost &&res);
/**
* Templated wrapper that exposes the command parameter arguments
* for the various Command::Do/Post calls.
@ -164,6 +166,59 @@ public:
return res;
}
/**
* Shortcut to query a command with its flags to test if it will succeed.
* @param args Parameters for the command.
* @return cost of the command.
*/
static inline CommandCost Query(Targs... args)
{
Tret res = Do(CommandFlagsToDCFlags(GetCommandFlags<Tcmd>()), std::forward<Targs>(args)...);
return ExtractCommandCost(res);
}
/**
* Post or query a command.
* @param query Whether to query (for selection) or post the command.
* @param err_message Message prefix to show on error.
* @param callback A callback function to call after the command is finished.
* @param args Parameters for the command.
* @return \c true if the command was posted and succeeded, else \c false.
*/
template <typename Tcallback>
static inline bool PostOrQuery(bool query, StringID err_message, Tcallback *callback, Targs... args)
{
if (query) {
HandleSelectionQuery(Query(std::forward<Targs>(args)...));
return false;
} else {
return Post(err_message, callback, std::forward<Targs>(args)...);
}
}
/**
* Shortcut for the long PostOrQuery when not using a callback.
* @param query Whether to query (for selection) or post the command.
* @param err_message Message prefix to show on error.
* @param args Parameters for the command.
* @return \c true if the command was posted and succeeded, else \c false.
*/
static inline bool PostOrQuery(bool query, StringID err_message, Targs... args)
{
return PostOrQuery<CommandCallback>(query, err_message, nullptr, std::forward<Targs>(args)...);
}
/**
* Shortcut for the long PostOrQuery when not using a callback or an error message.
* @param query Whether to query (for selection) or post the command.
* @param args Parameters for the command.
* @return \c true if the command was posted and succeeded, else \c false.
*/
static inline bool PostOrQuery(bool query, Targs... args)
{
return PostOrQuery<CommandCallback>(query, static_cast<StringID>(0), nullptr, std::forward<Targs>(args)...);
}
/**
* Shortcut for the long Post when not using a callback.
* @param err_message Message prefix to show on error

View File

@ -2246,9 +2246,9 @@ struct CompanyWindow : Window
this->SetDirty();
}};
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
if (Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
if (Command<CMD_BUILD_OBJECT>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
ResetObjectToPlace();
this->RaiseButtons();
}

View File

@ -192,23 +192,23 @@ struct BuildDocksToolbarWindow : Window {
this->last_clicked_widget = (DockToolbarWidgets)widget;
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
switch (this->last_clicked_widget) {
case WID_DT_CANAL: // Build canal button
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_WATER);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_CREATE_WATER);
break;
case WID_DT_LOCK: // Build lock button
Command<CMD_BUILD_LOCK>::Post(STR_ERROR_CAN_T_BUILD_LOCKS, CcBuildDocks, tile);
Command<CMD_BUILD_LOCK>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_LOCKS, CcBuildDocks, tile);
break;
case WID_DT_DEMOLISH: // Demolish aka dynamite button
PlaceProc_DemolishArea(tile);
PlaceProc_DemolishArea(query, tile);
break;
case WID_DT_DEPOT: // Build depot button
Command<CMD_BUILD_SHIP_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT, CcBuildDocks, tile, _ship_depot_direction);
Command<CMD_BUILD_SHIP_DEPOT>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_SHIP_DEPOT, CcBuildDocks, tile, _ship_depot_direction);
break;
case WID_DT_STATION: { // Build station button
@ -217,9 +217,15 @@ struct BuildDocksToolbarWindow : Window {
TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile, ReverseDiagDir(dir)) : tile);
bool adjacent = _ctrl_pressed;
if (query) {
HandleSelectionQuery(Command<CMD_BUILD_DOCK>::Query(tile, StationID::Invalid(), adjacent));
break;
}
auto proc = [=](bool test, StationID to_join) -> bool {
if (test) {
return Command<CMD_BUILD_DOCK>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_DOCK>()), tile, StationID::Invalid(), adjacent).Succeeded();
return Command<CMD_BUILD_DOCK>::Query(tile, StationID::Invalid(), adjacent).Succeeded();
} else {
return Command<CMD_BUILD_DOCK>::Post(STR_ERROR_CAN_T_BUILD_DOCK_HERE, CcBuildDocks, tile, to_join, adjacent);
}
@ -230,15 +236,15 @@ struct BuildDocksToolbarWindow : Window {
}
case WID_DT_BUOY: // Build buoy button
Command<CMD_BUILD_BUOY>::Post(STR_ERROR_CAN_T_POSITION_BUOY_HERE, CcBuildDocks, tile);
Command<CMD_BUILD_BUOY>::PostOrQuery(query, STR_ERROR_CAN_T_POSITION_BUOY_HERE, CcBuildDocks, tile);
break;
case WID_DT_RIVER: // Build river button (in scenario editor)
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_RIVER);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_CREATE_RIVER);
break;
case WID_DT_BUILD_AQUEDUCT: // Build aqueduct button
Command<CMD_BUILD_BRIDGE>::Post(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE, CcBuildBridge, tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER, 0, 0);
Command<CMD_BUILD_BRIDGE>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE, CcBuildBridge, tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER, 0, 0);
break;
default: NOT_REACHED();
@ -250,22 +256,22 @@ struct BuildDocksToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (pt.x != -1) {
switch (select_proc) {
case DDSP_DEMOLISH_AREA:
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
GUIPlaceProcDragXY(query, select_proc, start_tile, end_tile);
break;
case DDSP_CREATE_WATER:
if (_game_mode == GM_EDITOR) {
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, _ctrl_pressed ? WATER_CLASS_SEA : WATER_CLASS_CANAL, false);
Command<CMD_BUILD_CANAL>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, _ctrl_pressed ? WATER_CLASS_SEA : WATER_CLASS_CANAL, false);
} else {
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_CANAL, _ctrl_pressed);
Command<CMD_BUILD_CANAL>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_CANAL, _ctrl_pressed);
}
break;
case DDSP_CREATE_RIVER:
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_RIVER, _ctrl_pressed);
Command<CMD_BUILD_CANAL>::PostOrQuery(query, STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_RIVER, _ctrl_pressed);
break;
default: break;

View File

@ -655,6 +655,30 @@ public:
MarkWholeScreenDirty();
}
Dimension GetIndustryLayoutSize(const IndustryTileLayout &layout) const
{
int max_x = 0;
int max_y = 0;
/* Finds dimensions of largest variant of this industry */
for (const IndustryTileLayoutTile &it : layout) {
if (it.gfx == GFX_WATERTILE_SPECIALCHECK) continue; // watercheck tiles don't count for footprint size
if (it.ti.x > max_x) max_x = it.ti.x;
if (it.ti.y > max_y) max_y = it.ti.y;
}
return Dimension(max_x + 1, max_y + 1);
}
Dimension GetMaxIndustryLayoutSize() const
{
Dimension d{};
for (const auto &layout : GetIndustrySpec(this->selected_type)->layouts) {
d = maxdim(d, GetIndustryLayoutSize(layout));
}
return d;
}
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
@ -697,6 +721,11 @@ public:
this->SetButtons();
if (this->enabled && click_count > 1) this->OnClick(pt, WID_DPI_FUND_WIDGET, 1);
if (_thd.GetCallbackWnd() == this) {
auto [x, y] = this->GetMaxIndustryLayoutSize();
SetTileSelectSize(x, y);
}
}
break;
}
@ -712,6 +741,8 @@ public:
this->HandleButtonClick(WID_DPI_FUND_WIDGET);
} else {
HandlePlacePushButton(this, WID_DPI_FUND_WIDGET, SPR_CURSOR_INDUSTRY, HT_RECT);
auto [x, y] = this->GetMaxIndustryLayoutSize();
SetTileSelectSize(x, y);
}
}
break;
@ -725,7 +756,7 @@ public:
this->vscroll->SetCapacityFromWidget(this, WID_DPI_MATRIX_WIDGET);
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
bool success = true;
/* We do not need to protect ourselves against "Random Many Industries" in this mode */
@ -735,7 +766,7 @@ public:
if (_game_mode == GM_EDITOR) {
/* Show error if no town exists at all */
if (Town::GetNumItems() == 0) {
if (!query && Town::GetNumItems() == 0) {
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_HERE, indsp->name),
GetEncodedString(STR_ERROR_MUST_FOUND_TOWN_FIRST), WL_INFO, pt.x, pt.y);
return;
@ -745,9 +776,9 @@ public:
AutoRestoreBackup backup_generating_world(_generating_world, true);
AutoRestoreBackup backup_ignore_industry_restritions(_ignore_industry_restrictions, true);
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, this->selected_type, layout_index, false, seed);
Command<CMD_BUILD_INDUSTRY>::PostOrQuery(query, STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, this->selected_type, layout_index, false, seed);
} else {
success = Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
success = Command<CMD_BUILD_INDUSTRY>::PostOrQuery(query, STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
}
/* If an industry has been built, just reset the cursor and the system */

View File

@ -329,14 +329,14 @@ public:
}
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
const ObjectSpec *spec = ObjectClass::Get(_object_gui.sel_class)->GetSpec(_object_gui.sel_type);
if (spec->size == OBJECT_SIZE_1X1) {
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_BUILD_OBJECT);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_BUILD_OBJECT);
} else {
Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_OBJECT, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), _object_gui.sel_view);
Command<CMD_BUILD_OBJECT>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_OBJECT, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), _object_gui.sel_view);
}
}
@ -345,7 +345,7 @@ public:
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, [[maybe_unused]] ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, [[maybe_unused]] ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (pt.x == -1) return;
@ -358,7 +358,8 @@ public:
if (TileY(end_tile) == Map::MaxY()) end_tile += TileDiffXY(0, -1);
}
const ObjectSpec *spec = ObjectClass::Get(_object_gui.sel_class)->GetSpec(_object_gui.sel_type);
Command<CMD_BUILD_OBJECT_AREA>::Post(STR_ERROR_CAN_T_BUILD_OBJECT, CcPlaySound_CONSTRUCTION_OTHER,
Command<CMD_BUILD_OBJECT_AREA>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_OBJECT, CcPlaySound_CONSTRUCTION_OTHER,
end_tile, start_tile, spec->Index(), _object_gui.sel_view, (_ctrl_pressed ? true : false));
}

View File

@ -1467,8 +1467,10 @@ public:
return ES_HANDLED;
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
if (query) return;
if (this->goto_type == OPOS_GOTO) {
const Order cmd = GetOrderCmdFromTile(this->vehicle, tile);
if (cmd.IsType(OT_NOTHING)) return;

View File

@ -75,7 +75,7 @@ struct StationPickerSelection {
static StationPickerSelection _station_gui; ///< Settings of the station picker.
static void HandleStationPlacement(TileIndex start, TileIndex end);
static void HandleStationPlacement(bool query, TileIndex start, TileIndex end);
static void ShowBuildTrainDepotPicker(Window *parent);
static void ShowBuildWaypointPicker(Window *parent);
static Window *ShowStationBuilder(Window *parent);
@ -166,18 +166,20 @@ void CcRailDepot(Commands, const CommandCost &result, TileIndex tile, RailType,
* Place a rail waypoint.
* @param tile Position to start dragging a waypoint.
*/
static void PlaceRail_Waypoint(TileIndex tile)
static void PlaceRail_Waypoint(bool query, TileIndex tile)
{
if (_remove_button_clicked) {
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_REMOVE_STATION);
return;
}
Axis axis = GetAxisForNewRailWaypoint(tile);
if (IsValidAxis(axis)) {
/* Valid tile for waypoints */
VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_STATION);
VpStartPlaceSizing(query, tile, axis == AXIS_X ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_STATION);
VpSetPlaceSizingLimit(_settings_game.station.station_spread);
} else if (query) {
SetSelectionRed(true);
} else {
/* Tile where we can't build rail waypoints. This is always going to fail,
* but provides the user with a proper error message. */
@ -198,13 +200,13 @@ void CcStation(Commands, const CommandCost &result, TileIndex tile)
* Place a rail station.
* @param tile Position to place or start dragging a station.
*/
static void PlaceRail_Station(TileIndex tile)
static void PlaceRail_Station(bool query, TileIndex tile)
{
if (_remove_button_clicked) {
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
VpSetPlaceSizingLimit(-1);
} else if (_settings_client.gui.station_dragdrop) {
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
VpSetPlaceSizingLimit(_settings_game.station.station_spread);
} else {
int w = _settings_client.gui.station_numtracks;
@ -217,9 +219,14 @@ static void PlaceRail_Station(TileIndex tile)
uint8_t platlength = _settings_client.gui.station_platlength;
bool adjacent = _ctrl_pressed;
if (query) {
HandleSelectionQuery(Command<CMD_BUILD_RAIL_STATION>::Query(tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, StationID::Invalid(), adjacent));
return;
}
auto proc = [=](bool test, StationID to_join) -> bool {
if (test) {
return Command<CMD_BUILD_RAIL_STATION>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_RAIL_STATION>()), tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, StationID::Invalid(), adjacent).Succeeded();
return Command<CMD_BUILD_RAIL_STATION>::Query(tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, StationID::Invalid(), adjacent).Succeeded();
} else {
return Command<CMD_BUILD_RAIL_STATION>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION, CcStation, tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, to_join, adjacent);
}
@ -292,14 +299,14 @@ static void GenericPlaceSignals(TileIndex tile)
* @param tile Position of the first tile of the bridge.
* @param w Rail toolbar window.
*/
static void PlaceRail_Bridge(TileIndex tile, Window *w)
static void PlaceRail_Bridge(bool query, TileIndex tile, Window *w)
{
if (IsBridgeTile(tile)) {
TileIndex other_tile = GetOtherTunnelBridgeEnd(tile);
Point pt = {0, 0};
w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile);
if (!query) w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile, query);
} else {
VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
VpStartPlaceSizing(query, tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
}
}
@ -662,59 +669,59 @@ struct BuildRailToolbarWindow : Window {
return Window::OnHotkey(hotkey);
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
switch (this->last_user_action) {
case WID_RAT_BUILD_NS:
VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
VpStartPlaceSizing(query, tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
break;
case WID_RAT_BUILD_X:
VpStartPlaceSizing(tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL);
VpStartPlaceSizing(query, tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL);
break;
case WID_RAT_BUILD_EW:
VpStartPlaceSizing(tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
VpStartPlaceSizing(query, tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
break;
case WID_RAT_BUILD_Y:
VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL);
VpStartPlaceSizing(query, tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL);
break;
case WID_RAT_AUTORAIL:
VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL);
VpStartPlaceSizing(query, tile, VPM_RAILDIRS, DDSP_PLACE_RAIL);
break;
case WID_RAT_DEMOLISH:
PlaceProc_DemolishArea(tile);
PlaceProc_DemolishArea(query, tile);
break;
case WID_RAT_BUILD_DEPOT:
Command<CMD_BUILD_TRAIN_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT, CcRailDepot, tile, _cur_railtype, _build_depot_direction);
Command<CMD_BUILD_TRAIN_DEPOT>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT, CcRailDepot, tile, _cur_railtype, _build_depot_direction);
break;
case WID_RAT_BUILD_WAYPOINT:
PlaceRail_Waypoint(tile);
PlaceRail_Waypoint(query, tile);
break;
case WID_RAT_BUILD_STATION:
PlaceRail_Station(tile);
PlaceRail_Station(query, tile);
break;
case WID_RAT_BUILD_SIGNALS:
VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
VpStartPlaceSizing(query, tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
break;
case WID_RAT_BUILD_BRIDGE:
PlaceRail_Bridge(tile, this);
PlaceRail_Bridge(query, tile, this);
break;
case WID_RAT_BUILD_TUNNEL:
Command<CMD_BUILD_TUNNEL>::Post(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRailTunnel, tile, TRANSPORT_RAIL, _cur_railtype);
Command<CMD_BUILD_TUNNEL>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRailTunnel, tile, TRANSPORT_RAIL, _cur_railtype);
break;
case WID_RAT_CONVERT_RAIL:
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
break;
default: NOT_REACHED();
@ -729,30 +736,31 @@ struct BuildRailToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (pt.x != -1) {
switch (select_proc) {
default: NOT_REACHED();
case DDSP_BUILD_BRIDGE:
if (query) return;
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype);
break;
case DDSP_PLACE_RAIL:
HandleAutodirPlacement();
if (!query) HandleAutodirPlacement();
break;
case DDSP_BUILD_SIGNALS:
HandleAutoSignalPlacement();
if (!query) HandleAutoSignalPlacement();
break;
case DDSP_DEMOLISH_AREA:
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
GUIPlaceProcDragXY(query, select_proc, start_tile, end_tile);
break;
case DDSP_CONVERT_RAIL:
Command<CMD_CONVERT_RAIL>::Post(STR_ERROR_CAN_T_CONVERT_RAIL, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _cur_railtype, _ctrl_pressed);
Command<CMD_CONVERT_RAIL>::PostOrQuery(query, STR_ERROR_CAN_T_CONVERT_RAIL, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _cur_railtype, _ctrl_pressed);
break;
case DDSP_REMOVE_STATION:
@ -761,23 +769,28 @@ struct BuildRailToolbarWindow : Window {
/* Station */
if (_remove_button_clicked) {
bool keep_rail = !_ctrl_pressed;
Command<CMD_REMOVE_FROM_RAIL_STATION>::Post(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, keep_rail);
Command<CMD_REMOVE_FROM_RAIL_STATION>::PostOrQuery(query, STR_ERROR_CAN_T_REMOVE_PART_OF_STATION, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, keep_rail);
} else {
HandleStationPlacement(start_tile, end_tile);
HandleStationPlacement(query, start_tile, end_tile);
}
} else {
/* Waypoint */
if (_remove_button_clicked) {
bool keep_rail = !_ctrl_pressed;
Command<CMD_REMOVE_FROM_RAIL_WAYPOINT>::Post(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, keep_rail);
Command<CMD_REMOVE_FROM_RAIL_WAYPOINT>::PostOrQuery(query, STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, keep_rail);
} else {
TileArea ta(start_tile, end_tile);
Axis axis = select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y;
bool adjacent = _ctrl_pressed;
if (query) {
HandleSelectionQuery(Command<CMD_BUILD_RAIL_WAYPOINT>::Query(ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, StationID::Invalid(), adjacent));
return;
}
auto proc = [=](bool test, StationID to_join) -> bool {
if (test) {
return Command<CMD_BUILD_RAIL_WAYPOINT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_RAIL_WAYPOINT>()), ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, StationID::Invalid(), adjacent).Succeeded();
return Command<CMD_BUILD_RAIL_WAYPOINT>::Query(ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, StationID::Invalid(), adjacent).Succeeded();
} else {
return Command<CMD_BUILD_RAIL_WAYPOINT>::Post(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT, CcPlaySound_CONSTRUCTION_RAIL, ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, to_join, adjacent);
}
@ -930,7 +943,7 @@ Window *ShowBuildRailToolbar(RailType railtype)
/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
* --pasky */
static void HandleStationPlacement(TileIndex start, TileIndex end)
static void HandleStationPlacement(bool query, TileIndex start, TileIndex end)
{
TileArea ta(start, end);
uint numtracks = ta.w;
@ -942,9 +955,14 @@ static void HandleStationPlacement(TileIndex start, TileIndex end)
RailType rt = _cur_railtype;
bool adjacent = _ctrl_pressed;
if (query) {
HandleSelectionQuery(Command<CMD_BUILD_RAIL_STATION>::Query(ta.tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, StationID::Invalid(), adjacent));
return;
}
auto proc = [=](bool test, StationID to_join) -> bool {
if (test) {
return Command<CMD_BUILD_RAIL_STATION>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_RAIL_STATION>()), ta.tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, StationID::Invalid(), adjacent).Succeeded();
return Command<CMD_BUILD_RAIL_STATION>::Query(ta.tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, StationID::Invalid(), adjacent).Succeeded();
} else {
return Command<CMD_BUILD_RAIL_STATION>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION, CcStation, ta.tile, rt, params.axis, numtracks, platlength, params.sel_class, params.sel_type, to_join, adjacent);
}

View File

@ -121,14 +121,14 @@ void CcPlaySound_CONSTRUCTION_OTHER(Commands, const CommandCost &result, TileInd
* Callback to start placing a bridge.
* @param tile Start tile of the bridge.
*/
static void PlaceRoad_Bridge(TileIndex tile, Window *w)
static void PlaceRoad_Bridge(bool query, TileIndex tile, Window *w)
{
if (IsBridgeTile(tile)) {
TileIndex other_tile = GetOtherTunnelBridgeEnd(tile);
Point pt = {0, 0};
w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile);
if (!query) w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile, query);
} else {
VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
VpStartPlaceSizing(query, tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
}
}
@ -226,7 +226,7 @@ void CcRoadStop(Commands, const CommandCost &result, TileIndex tile, uint8_t wid
* @param err_msg Error message to show.
* @see CcRoadStop()
*/
static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, RoadStopType stop_type, bool adjacent, RoadType rt, StringID err_msg)
static void PlaceRoadStop(bool query, TileIndex start_tile, TileIndex end_tile, RoadStopType stop_type, bool adjacent, RoadType rt, StringID err_msg)
{
TileArea ta(start_tile, end_tile);
DiagDirection ddir = _roadstop_gui.orientation;
@ -235,9 +235,15 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, RoadStopType
RoadStopClassID spec_class = _roadstop_gui.sel_class;
uint16_t spec_index = _roadstop_gui.sel_type;
if (query) {
HandleSelectionQuery(Command<CMD_BUILD_ROAD_STOP>::Query(ta.tile, ta.w, ta.h, stop_type, drive_through,
ddir, rt, spec_class, spec_index, StationID::Invalid(), adjacent));
return;
}
auto proc = [=](bool test, StationID to_join) -> bool {
if (test) {
return Command<CMD_BUILD_ROAD_STOP>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_ROAD_STOP>()), ta.tile, ta.w, ta.h, stop_type, drive_through,
return Command<CMD_BUILD_ROAD_STOP>::Query(ta.tile, ta.w, ta.h, stop_type, drive_through,
ddir, rt, spec_class, spec_index, StationID::Invalid(), adjacent).Succeeded();
} else {
return Command<CMD_BUILD_ROAD_STOP>::Post(err_msg, CcRoadStop, ta.tile, ta.w, ta.h, stop_type, drive_through,
@ -252,18 +258,20 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, RoadStopType
* Place a road waypoint.
* @param tile Position to start dragging a waypoint.
*/
static void PlaceRoad_Waypoint(TileIndex tile)
static void PlaceRoad_Waypoint(bool query, TileIndex tile)
{
if (_remove_button_clicked) {
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_ROAD_WAYPOINT);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_REMOVE_ROAD_WAYPOINT);
return;
}
Axis axis = GetAxisForNewRoadWaypoint(tile);
if (IsValidAxis(axis)) {
/* Valid tile for waypoints */
VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_ROAD_WAYPOINT);
VpStartPlaceSizing(query, tile, axis == AXIS_X ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_ROAD_WAYPOINT);
VpSetPlaceSizingLimit(_settings_game.station.station_spread);
} else if (query) {
SetSelectionRed(true);
} else {
/* Tile where we can't build road waypoints. This is always going to fail,
* but provides the user with a proper error message. */
@ -275,15 +283,15 @@ static void PlaceRoad_Waypoint(TileIndex tile)
* Callback for placing a bus station.
* @param tile Position to place the station.
*/
static void PlaceRoad_BusStation(TileIndex tile)
static void PlaceRoad_BusStation(bool query, TileIndex tile)
{
if (_remove_button_clicked) {
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP);
} else {
if (_roadstop_gui.orientation < DIAGDIR_END) { // Not a drive-through stop.
VpStartPlaceSizing(tile, (DiagDirToAxis(_roadstop_gui.orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP);
VpStartPlaceSizing(query, tile, (DiagDirToAxis(_roadstop_gui.orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP);
} else {
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP);
}
VpSetPlaceSizingLimit(_settings_game.station.station_spread);
}
@ -293,15 +301,15 @@ static void PlaceRoad_BusStation(TileIndex tile)
* Callback for placing a truck station.
* @param tile Position to place the station.
*/
static void PlaceRoad_TruckStation(TileIndex tile)
static void PlaceRoad_TruckStation(bool query, TileIndex tile)
{
if (_remove_button_clicked) {
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP);
} else {
if (_roadstop_gui.orientation < DIAGDIR_END) { // Not a drive-through stop.
VpStartPlaceSizing(tile, (DiagDirToAxis(_roadstop_gui.orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
VpStartPlaceSizing(query, tile, (DiagDirToAxis(_roadstop_gui.orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
} else {
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
}
VpSetPlaceSizingLimit(_settings_game.station.station_spread);
}
@ -602,7 +610,7 @@ struct BuildRoadToolbarWindow : Window {
return Window::OnHotkey(hotkey);
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
_remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE);
_one_way_button_clicked = RoadTypeIsRoad(this->roadtype) ? this->IsWidgetLowered(WID_ROT_ONE_WAY) : false;
@ -610,54 +618,54 @@ struct BuildRoadToolbarWindow : Window {
case WID_ROT_ROAD_X:
_place_road_dir = AXIS_X;
_place_road_start_half_x = _tile_fract_coords.x >= 8;
VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_ROAD_X_DIR);
VpStartPlaceSizing(query, tile, VPM_FIX_Y, DDSP_PLACE_ROAD_X_DIR);
break;
case WID_ROT_ROAD_Y:
_place_road_dir = AXIS_Y;
_place_road_start_half_y = _tile_fract_coords.y >= 8;
VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_ROAD_Y_DIR);
VpStartPlaceSizing(query, tile, VPM_FIX_X, DDSP_PLACE_ROAD_Y_DIR);
break;
case WID_ROT_AUTOROAD:
_place_road_dir = INVALID_AXIS;
_place_road_start_half_x = _tile_fract_coords.x >= 8;
_place_road_start_half_y = _tile_fract_coords.y >= 8;
VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD);
VpStartPlaceSizing(query, tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD);
break;
case WID_ROT_DEMOLISH:
PlaceProc_DemolishArea(tile);
PlaceProc_DemolishArea(query, tile);
break;
case WID_ROT_DEPOT:
Command<CMD_BUILD_ROAD_DEPOT>::Post(GetRoadTypeInfo(this->roadtype)->strings.err_depot, CcRoadDepot,
Command<CMD_BUILD_ROAD_DEPOT>::PostOrQuery(query, GetRoadTypeInfo(this->roadtype)->strings.err_depot, CcRoadDepot,
tile, _cur_roadtype, _road_depot_orientation);
break;
case WID_ROT_BUILD_WAYPOINT:
PlaceRoad_Waypoint(tile);
PlaceRoad_Waypoint(query, tile);
break;
case WID_ROT_BUS_STATION:
PlaceRoad_BusStation(tile);
PlaceRoad_BusStation(query, tile);
break;
case WID_ROT_TRUCK_STATION:
PlaceRoad_TruckStation(tile);
PlaceRoad_TruckStation(query, tile);
break;
case WID_ROT_BUILD_BRIDGE:
PlaceRoad_Bridge(tile, this);
PlaceRoad_Bridge(query, tile, this);
break;
case WID_ROT_BUILD_TUNNEL:
Command<CMD_BUILD_TUNNEL>::Post(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRoadTunnel,
Command<CMD_BUILD_TUNNEL>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRoadTunnel,
tile, TRANSPORT_ROAD, _cur_roadtype);
break;
case WID_ROT_CONVERT_ROAD:
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_ROAD);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_CONVERT_ROAD);
break;
default: NOT_REACHED();
@ -724,18 +732,19 @@ struct BuildRoadToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (pt.x != -1) {
switch (select_proc) {
default: NOT_REACHED();
case DDSP_BUILD_BRIDGE:
if (query) break;
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, _cur_roadtype);
break;
case DDSP_DEMOLISH_AREA:
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
GUIPlaceProcDragXY(query, select_proc, start_tile, end_tile);
break;
case DDSP_PLACE_ROAD_X_DIR:
@ -744,10 +753,10 @@ struct BuildRoadToolbarWindow : Window {
bool start_half = _place_road_dir == AXIS_Y ? _place_road_start_half_y : _place_road_start_half_x;
if (_remove_button_clicked) {
Command<CMD_REMOVE_LONG_ROAD>::Post(GetRoadTypeInfo(this->roadtype)->strings.err_remove_road, CcPlaySound_CONSTRUCTION_OTHER,
Command<CMD_REMOVE_LONG_ROAD>::PostOrQuery(query, GetRoadTypeInfo(this->roadtype)->strings.err_remove_road, CcPlaySound_CONSTRUCTION_OTHER,
end_tile, start_tile, _cur_roadtype, _place_road_dir, start_half, _place_road_end_half);
} else {
Command<CMD_BUILD_LONG_ROAD>::Post(GetRoadTypeInfo(this->roadtype)->strings.err_build_road, CcPlaySound_CONSTRUCTION_OTHER,
Command<CMD_BUILD_LONG_ROAD>::PostOrQuery(query, GetRoadTypeInfo(this->roadtype)->strings.err_build_road, CcPlaySound_CONSTRUCTION_OTHER,
end_tile, start_tile, _cur_roadtype, _place_road_dir, _one_way_button_clicked ? DRD_NORTHBOUND : DRD_NONE, start_half, _place_road_end_half, false);
}
break;
@ -757,15 +766,20 @@ struct BuildRoadToolbarWindow : Window {
case DDSP_REMOVE_ROAD_WAYPOINT:
if (this->IsWidgetLowered(WID_ROT_BUILD_WAYPOINT)) {
if (_remove_button_clicked) {
Command<CMD_REMOVE_FROM_ROAD_WAYPOINT>::Post(STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile);
Command<CMD_REMOVE_FROM_ROAD_WAYPOINT>::PostOrQuery(query, STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile);
} else {
TileArea ta(start_tile, end_tile);
Axis axis = select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y;
bool adjacent = _ctrl_pressed;
if (query) {
HandleSelectionQuery(Command<CMD_BUILD_ROAD_WAYPOINT>::Query(ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, StationID::Invalid(), adjacent));
return;
}
auto proc = [=](bool test, StationID to_join) -> bool {
if (test) {
return Command<CMD_BUILD_ROAD_WAYPOINT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_ROAD_WAYPOINT>()), ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, StationID::Invalid(), adjacent).Succeeded();
return Command<CMD_BUILD_ROAD_WAYPOINT>::Query(ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, StationID::Invalid(), adjacent).Succeeded();
} else {
return Command<CMD_BUILD_ROAD_WAYPOINT>::Post(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT, CcPlaySound_CONSTRUCTION_OTHER, ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, to_join, adjacent);
}
@ -782,10 +796,10 @@ struct BuildRoadToolbarWindow : Window {
if (_remove_button_clicked) {
TileArea ta(start_tile, end_tile);
StringID str = GetRoadTypeInfo(this->roadtype)->strings.err_remove_station[to_underlying(RoadStopType::Bus)];
Command<CMD_REMOVE_ROAD_STOP>::Post(str, CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w, ta.h, RoadStopType::Bus, _ctrl_pressed);
Command<CMD_REMOVE_ROAD_STOP>::PostOrQuery(query, str, CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w, ta.h, RoadStopType::Bus, _ctrl_pressed);
} else {
StringID str = GetRoadTypeInfo(this->roadtype)->strings.err_build_station[to_underlying(RoadStopType::Bus)];
PlaceRoadStop(start_tile, end_tile, RoadStopType::Bus, _ctrl_pressed, _cur_roadtype, str);
PlaceRoadStop(query, start_tile, end_tile, RoadStopType::Bus, _ctrl_pressed, _cur_roadtype, str);
}
}
break;
@ -796,16 +810,16 @@ struct BuildRoadToolbarWindow : Window {
if (_remove_button_clicked) {
TileArea ta(start_tile, end_tile);
StringID str = GetRoadTypeInfo(this->roadtype)->strings.err_remove_station[to_underlying(RoadStopType::Truck)];
Command<CMD_REMOVE_ROAD_STOP>::Post(str, CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w, ta.h, RoadStopType::Truck, _ctrl_pressed);
Command<CMD_REMOVE_ROAD_STOP>::PostOrQuery(query, str, CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w, ta.h, RoadStopType::Truck, _ctrl_pressed);
} else {
StringID str = GetRoadTypeInfo(this->roadtype)->strings.err_build_station[to_underlying(RoadStopType::Truck)];
PlaceRoadStop(start_tile, end_tile, RoadStopType::Truck, _ctrl_pressed, _cur_roadtype, str);
PlaceRoadStop(query, start_tile, end_tile, RoadStopType::Truck, _ctrl_pressed, _cur_roadtype, str);
}
}
break;
case DDSP_CONVERT_ROAD:
Command<CMD_CONVERT_ROAD>::Post(GetRoadTypeInfo(this->roadtype)->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype, _ctrl_pressed);
Command<CMD_CONVERT_ROAD>::PostOrQuery(query, GetRoadTypeInfo(this->roadtype)->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype, _ctrl_pressed);
break;
}
}

View File

@ -114,7 +114,8 @@ void CcPlaceSign(Commands, const CommandCost &result, SignID new_sign)
* sign-tool is selected
* @param tile on which to place the sign
*/
void PlaceProc_Sign(TileIndex tile)
void PlaceProc_Sign(bool query, TileIndex tile)
{
if (query) return;
Command<CMD_PLACE_SIGN>::Post(STR_ERROR_CAN_T_PLACE_SIGN_HERE, CcPlaceSign, tile, {});
}

View File

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

View File

@ -888,8 +888,10 @@ public:
this->SetWidgetDirty(WID_SB_PAGE_PANEL);
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
if (query) return;
const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
if (pe == nullptr || pe->type != SPET_BUTTON_TILE) {
ResetObjectToPlace();

View File

@ -109,7 +109,7 @@ static void GenerateRockyArea(TileIndex end, TileIndex start)
* allows for additional implements that are more local. For example X_Y drag
* of convertrail which belongs in rail_gui.cpp and not terraform_gui.cpp
*/
bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile)
bool GUIPlaceProcDragXY(bool query, ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile)
{
if (!_settings_game.construction.freeform_edges) {
/* When end_tile is MP_VOID, the error tile will not be visible to the
@ -120,22 +120,22 @@ bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_t
switch (proc) {
case DDSP_DEMOLISH_AREA:
Command<CMD_CLEAR_AREA>::Post(STR_ERROR_CAN_T_CLEAR_THIS_AREA, CcPlaySound_EXPLOSION, end_tile, start_tile, _ctrl_pressed);
Command<CMD_CLEAR_AREA>::PostOrQuery(query, STR_ERROR_CAN_T_CLEAR_THIS_AREA, CcPlaySound_EXPLOSION, end_tile, start_tile, _ctrl_pressed);
break;
case DDSP_RAISE_AND_LEVEL_AREA:
Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_RAISE_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_RAISE);
Command<CMD_LEVEL_LAND>::PostOrQuery(query, STR_ERROR_CAN_T_RAISE_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_RAISE);
break;
case DDSP_LOWER_AND_LEVEL_AREA:
Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_LOWER_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_LOWER);
Command<CMD_LEVEL_LAND>::PostOrQuery(query, STR_ERROR_CAN_T_LOWER_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_LOWER);
break;
case DDSP_LEVEL_AREA:
Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_LEVEL_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_LEVEL);
Command<CMD_LEVEL_LAND>::PostOrQuery(query, STR_ERROR_CAN_T_LEVEL_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_LEVEL);
break;
case DDSP_CREATE_ROCKS:
GenerateRockyArea(end_tile, start_tile);
if (!query) GenerateRockyArea(end_tile, start_tile);
break;
case DDSP_CREATE_DESERT:
GenerateDesertArea(end_tile, start_tile);
if (!query) GenerateDesertArea(end_tile, start_tile);
break;
default:
return false;
@ -148,9 +148,9 @@ bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_t
* Start a drag for demolishing an area.
* @param tile Position of one corner.
*/
void PlaceProc_DemolishArea(TileIndex tile)
void PlaceProc_DemolishArea(bool query, TileIndex tile)
{
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_DEMOLISH_AREA);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_DEMOLISH_AREA);
}
/** Terra form toolbar managing class. */
@ -218,31 +218,31 @@ struct TerraformToolbarWindow : Window {
}
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
switch (this->last_user_action) {
case WID_TT_LOWER_LAND: // Lower land button
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LOWER_AND_LEVEL_AREA);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_LOWER_AND_LEVEL_AREA);
break;
case WID_TT_RAISE_LAND: // Raise land button
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_RAISE_AND_LEVEL_AREA);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_RAISE_AND_LEVEL_AREA);
break;
case WID_TT_LEVEL_LAND: // Level land button
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_LEVEL_AREA);
break;
case WID_TT_DEMOLISH: // Demolish aka dynamite button
PlaceProc_DemolishArea(tile);
PlaceProc_DemolishArea(query, tile);
break;
case WID_TT_BUY_LAND: // Buy land button
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_BUILD_OBJECT);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_BUILD_OBJECT);
break;
case WID_TT_PLACE_SIGN: // Place sign button
PlaceProc_Sign(tile);
PlaceProc_Sign(query, tile);
break;
default: NOT_REACHED();
@ -261,7 +261,7 @@ struct TerraformToolbarWindow : Window {
return pt;
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (pt.x != -1) {
switch (select_proc) {
@ -270,7 +270,7 @@ struct TerraformToolbarWindow : Window {
case DDSP_RAISE_AND_LEVEL_AREA:
case DDSP_LOWER_AND_LEVEL_AREA:
case DDSP_LEVEL_AREA:
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
GUIPlaceProcDragXY(query, select_proc, start_tile, end_tile);
break;
case DDSP_BUILD_OBJECT:
if (!_settings_game.construction.freeform_edges) {
@ -279,7 +279,7 @@ struct TerraformToolbarWindow : Window {
if (TileX(end_tile) == Map::MaxX()) end_tile += TileDiffXY(-1, 0);
if (TileY(end_tile) == Map::MaxY()) end_tile += TileDiffXY(0, -1);
}
Command<CMD_BUILD_OBJECT_AREA>::Post(STR_ERROR_CAN_T_PURCHASE_THIS_LAND, CcPlaySound_CONSTRUCTION_RAIL,
Command<CMD_BUILD_OBJECT_AREA>::PostOrQuery(query, STR_ERROR_CAN_T_PURCHASE_THIS_LAND, CcPlaySound_CONSTRUCTION_RAIL,
end_tile, start_tile, OBJECT_OWNED_LAND, 0, (_ctrl_pressed ? true : false));
break;
}
@ -650,31 +650,31 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
}
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
switch (this->last_user_action) {
case WID_ETT_DEMOLISH: // Demolish aka dynamite button
PlaceProc_DemolishArea(tile);
PlaceProc_DemolishArea(query, tile);
break;
case WID_ETT_LOWER_LAND: // Lower land button
CommonRaiseLowerBigLand(tile, false);
if (!query) CommonRaiseLowerBigLand(tile, false);
break;
case WID_ETT_RAISE_LAND: // Raise land button
CommonRaiseLowerBigLand(tile, true);
if (!query) CommonRaiseLowerBigLand(tile, true);
break;
case WID_ETT_LEVEL_LAND: // Level land button
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_LEVEL_AREA);
break;
case WID_ETT_PLACE_ROCKS: // Place rocks button
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_ROCKS);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_CREATE_ROCKS);
break;
case WID_ETT_PLACE_DESERT: // Place desert button (in tropical climate)
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_DESERT);
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_CREATE_DESERT);
break;
default: NOT_REACHED();
@ -686,7 +686,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (pt.x != -1) {
switch (select_proc) {
@ -697,7 +697,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
case DDSP_LOWER_AND_LEVEL_AREA:
case DDSP_LEVEL_AREA:
case DDSP_DEMOLISH_AREA:
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
GUIPlaceProcDragXY(query, select_proc, start_tile, end_tile);
break;
}
}

View File

@ -126,8 +126,8 @@ void DrawTextEffects(DrawPixelInfo *dpi)
for (const TextEffect &te : _text_effects) {
if (!te.IsValid()) continue;
if (te.mode == TE_RISING || _settings_client.gui.loading_indicators) {
std::string *str = ViewportAddString(dpi, &te, flags, INVALID_COLOUR);
if (te.mode == TE_RISING || te.mode == TE_ERROR || _settings_client.gui.loading_indicators) {
std::string *str = ViewportAddString(dpi, &te, te.mode == TE_ERROR ? flags | ViewportStringFlag::TextColour | ViewportStringFlag::TransparentRect : flags, te.mode == TE_ERROR ? COLOUR_RED : INVALID_COLOUR);
if (str == nullptr) continue;
*str = te.msg.GetDecodedString();

View File

@ -21,6 +21,7 @@ enum TextEffectMode : uint8_t {
TE_INVALID, ///< Text effect is invalid.
TE_RISING, ///< Make the text effect slowly go upwards
TE_STATIC, ///< Keep the text effect static
TE_ERROR, ///< Error text effect.
};
using TextEffectID = uint16_t;

View File

@ -13,8 +13,8 @@
#include "gfx_type.h"
#include "tilehighlight_type.h"
void PlaceProc_DemolishArea(TileIndex tile);
bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile);
void PlaceProc_DemolishArea(bool query, TileIndex tile);
bool GUIPlaceProcDragXY(bool query, ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile);
bool HandlePlacePushButton(Window *w, WidgetID widget, CursorID cursor, HighLightStyle mode);
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w);
@ -23,7 +23,7 @@ void ResetObjectToPlace();
void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method);
void VpStartDragging(ViewportDragDropSelectionProcess process);
void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process);
void VpStartPlaceSizing(bool query, TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process);
void VpSetPresizeRange(TileIndex from, TileIndex to);
void VpSetPlaceSizingLimit(int limit);

View File

@ -11,6 +11,7 @@
#define TILEHIGHLIGHT_TYPE_H
#include "core/geometry_type.hpp"
#include "texteff.hpp"
#include "window_type.h"
#include "tile_type.h"
#include "viewport_type.h"
@ -74,6 +75,8 @@ struct TileHighlightData {
ViewportPlaceMethod select_method; ///< The method which governs how tiles are selected.
ViewportDragDropSelectionProcess select_proc; ///< The procedure that has to be called when the selection is done.
TextEffectID error = INVALID_TE_ID;
void Reset();
bool IsDraggingDiagonal();

View File

@ -2083,15 +2083,15 @@ struct MainToolbarWindow : Window {
return ES_HANDLED;
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
switch (_last_started_action) {
case CBF_PLACE_SIGN:
PlaceProc_Sign(tile);
PlaceProc_Sign(query, tile);
break;
case CBF_PLACE_LANDINFO:
ShowLandInfo(tile);
if (!query) ShowLandInfo(tile);
break;
default: NOT_REACHED();
@ -2443,15 +2443,15 @@ struct ScenarioEditorToolbarWindow : Window {
return ES_HANDLED;
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
switch (_last_started_action) {
case CBF_PLACE_SIGN:
PlaceProc_Sign(tile);
PlaceProc_Sign(query, tile);
break;
case CBF_PLACE_LANDINFO:
ShowLandInfo(tile);
if (!query) ShowLandInfo(tile);
break;
default: NOT_REACHED();

View File

@ -1378,7 +1378,7 @@ static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDi
/* Can we actually build the bridge? */
RoadType rt = GetTownRoadType();
if (Command<CMD_BUILD_BRIDGE>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_BRIDGE>()), tile, bridge_tile, TRANSPORT_ROAD, bridge_type, rt).Succeeded()) {
if (Command<CMD_BUILD_BRIDGE>::Query(tile, bridge_tile, TRANSPORT_ROAD, bridge_type, rt).Succeeded()) {
Command<CMD_BUILD_BRIDGE>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_BRIDGE>()).Set(DoCommandFlag::Execute), tile, bridge_tile, TRANSPORT_ROAD, bridge_type, rt);
return true;
}
@ -1448,7 +1448,7 @@ static bool GrowTownWithTunnel(const Town *t, const TileIndex tile, const DiagDi
/* Attempt to build the tunnel. Return false if it fails to let the town build a road instead. */
RoadType rt = GetTownRoadType();
if (Command<CMD_BUILD_TUNNEL>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_TUNNEL>()), tile, TRANSPORT_ROAD, rt).Succeeded()) {
if (Command<CMD_BUILD_TUNNEL>::Query(tile, TRANSPORT_ROAD, rt).Succeeded()) {
Command<CMD_BUILD_TUNNEL>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_TUNNEL>()).Set(DoCommandFlag::Execute), tile, TRANSPORT_ROAD, rt);
return true;
}

View File

@ -1306,8 +1306,10 @@ public:
old_generating_world.Restore();
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
if (query) return;
this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown);
}
@ -1773,10 +1775,11 @@ struct BuildHouseWindow : public PickerWindow {
this->SetWidgetDisabledState(WID_BH_PROTECT_ON, hasflag);
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
const HouseSpec *spec = HouseSpec::Get(HousePickerCallbacks::sel_type);
Command<CMD_PLACE_HOUSE>::Post(STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), this->house_protected);
Command<CMD_PLACE_HOUSE>::PostOrQuery(query, STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), this->house_protected);
}
const IntervalTimer<TimerWindow> view_refresh_interval = {std::chrono::milliseconds(2500), [this](auto) {

View File

@ -20,6 +20,7 @@
#include "zoom_func.h"
#include "tree_map.h"
#include "tree_cmd.h"
#include "viewport_func.h"
#include "widgets/tree_widget.h"
@ -212,11 +213,11 @@ public:
}
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile, bool query) override
{
if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL) {
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES);
} else {
VpStartPlaceSizing(query, tile, VPM_X_AND_Y, DDSP_PLANT_TREES);
} else if (!query) {
VpStartDragging(DDSP_PLANT_TREES);
}
}
@ -236,10 +237,10 @@ public:
}
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile, bool query) override
{
if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL && pt.x != -1 && select_proc == DDSP_PLANT_TREES) {
Command<CMD_PLANT_TREE>::Post(STR_ERROR_CAN_T_PLANT_TREE_HERE, end_tile, start_tile, this->tree_to_plant, _ctrl_pressed);
Command<CMD_PLANT_TREE>::PostOrQuery(query, STR_ERROR_CAN_T_PLANT_TREE_HERE, end_tile, start_tile, this->tree_to_plant, _ctrl_pressed);
}
}

View File

@ -1761,7 +1761,7 @@ static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *
}
if (ss.flags.Test(ViewportStringFlag::TextColour)) {
if (ss.colour != INVALID_COLOUR) colour = static_cast<TextColour>(GetColourGradient(ss.colour, SHADE_LIGHTER) | TC_IS_PALETTE_COLOUR);
if (ss.colour != INVALID_COLOUR) colour = static_cast<TextColour>(GetColourGradient(ss.colour, SHADE_LIGHTER) | TC_IS_PALETTE_COLOUR | TC_FORCED);
}
int left = x + WidgetDimensions::scaled.fullbevel.left;
@ -2226,10 +2226,32 @@ static void SetSelectionTilesDirty()
void SetSelectionRed(bool b)
{
if (_thd.make_square_red == b) return;
_thd.make_square_red = b;
SetSelectionTilesDirty();
}
/**
* Update tile highlight selection to reflect the command cost.
* @param cost CommandCost.
*/
void HandleSelectionQuery(CommandCost &&cost)
{
SetSelectionRed(cost.Failed());
if (cost.Failed()) {
if (_thd.error != INVALID_TE_ID) RemoveTextEffect(_thd.error);
Point pt = RemapCoords(_thd.new_pos.x, _thd.new_pos.y, GetTilePixelZ(TileXY(_thd.new_pos.x / TILE_SIZE, _thd.new_pos.y / TILE_SIZE)));
EncodedString error = std::move(cost.GetEncodedMessage());
if (error.empty()) error = GetEncodedStringIfValid(cost.GetErrorMessage());
_thd.error = AddTextEffect(std::move(error), pt.x, pt.y, 0, TextEffectMode::TE_ERROR);
} else {
if (_thd.error != INVALID_TE_ID) RemoveTextEffect(_thd.error);
_thd.error = INVALID_TE_ID;
}
}
/**
* Test whether a sign is below the mouse
* @param vp the clicked viewport
@ -2442,7 +2464,7 @@ static bool CheckClickOnLandscape(const Viewport &vp, int x, int y)
return true;
}
static void PlaceObject()
static void PlaceObject(bool query)
{
Point pt;
Window *w;
@ -2459,24 +2481,35 @@ static void PlaceObject()
_tile_fract_coords.y = pt.y & TILE_UNIT_MASK;
w = _thd.GetCallbackWnd();
if (w != nullptr) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y));
if (w != nullptr) {
TileIndex tile = TileVirtXY(pt.x, pt.y);
if (query) {
/* Query only if moved to a new tile. */
static TileIndex last_tile = INVALID_TILE;
if (tile == last_tile) return;
last_tile = tile;
}
w->OnPlaceObject(pt, tile, query);
}
}
bool HandleViewportClicked(const Viewport &vp, int x, int y)
bool HandleViewportClicked(const Viewport &vp, int x, int y, bool query)
{
const Vehicle *v = CheckClickOnVehicle(vp, x, y);
if (_thd.place_mode & HT_VEHICLE) {
if (v != nullptr && VehicleClicked(v)) return true;
if (!query && v != nullptr && VehicleClicked(v)) return true;
}
/* Vehicle placement mode already handled above. */
if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
PlaceObject();
PlaceObject(query);
return true;
}
if (query) return false;
if (CheckClickOnViewportSign(vp, x, y)) return true;
bool result = CheckClickOnLandscape(vp, x, y);
@ -2618,6 +2651,9 @@ void TileHighlightData::Reset()
this->pos.y = 0;
this->new_pos.x = 0;
this->new_pos.y = 0;
if (this->error != INVALID_TE_ID) RemoveTextEffect(this->error);
this->error = INVALID_TE_ID;
}
/**
@ -2766,8 +2802,10 @@ static void HideMeasurementTooltips()
}
/** highlighting tiles while only going over them with the mouse */
void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
void VpStartPlaceSizing(bool query, TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
{
if (_thd.select_method != method || _thd.select_proc != process) SetSelectionRed(false);
_thd.select_method = method;
_thd.select_proc = process;
_thd.selend.x = TileX(tile) * TILE_SIZE;
@ -2785,6 +2823,8 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag
_thd.selstart.y += TILE_SIZE / 2;
}
if (query) return;
HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) {
_thd.place_mode = HT_SPECIAL | others;
@ -3426,6 +3466,20 @@ calc_heightdiff_single_direction:;
*/
EventState VpHandlePlaceSizingDrag()
{
if (_thd.window_class != WC_INVALID && _thd.select_proc != DDSP_NONE) {
static TileIndex last_start, last_end;
Point selend = _special_mouse_mode == WSM_NONE ? _thd.new_pos : _thd.selend;
TileIndex start = TileVirtXY(_thd.new_pos.x, _thd.new_pos.y);
TileIndex end = TileVirtXY(selend.x, selend.y);
if (start != last_start || end != last_end) {
last_start = start;
last_end = end;
if (Window *w = _thd.GetCallbackWnd(); w != nullptr) {
w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, selend, start, end, true);
}
}
}
if (_special_mouse_mode != WSM_SIZING && _special_mouse_mode != WSM_DRAGGING) return ES_NOT_HANDLED;
/* stop drag mode if the window has been closed */
@ -3466,7 +3520,7 @@ EventState VpHandlePlaceSizingDrag()
SetTileSelectSize(1, 1);
HideMeasurementTooltips();
w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), false);
return ES_HANDLED;
}
@ -3524,10 +3578,14 @@ void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowC
_special_mouse_mode = WSM_NONE;
}
_thd.select_proc = DDSP_NONE;
_thd.place_mode = mode;
_thd.window_class = window_class;
_thd.window_number = window_num;
if (_thd.error != INVALID_TE_ID) RemoveTextEffect(_thd.error);
_thd.error = INVALID_TE_ID;
if ((mode & HT_DRAG_MASK) == HT_SPECIAL) { // special tools, like tunnels or docks start with presizing mode
VpStartPreSizing();
}

View File

@ -59,7 +59,7 @@ std::string *ViewportAddString(const DrawPixelInfo *dpi, const ViewportSign *sig
void StartSpriteCombine();
void EndSpriteCombine();
bool HandleViewportClicked(const Viewport &vp, int x, int y);
bool HandleViewportClicked(const Viewport &vp, int x, int y, bool query);
void SetRedErrorSquare(TileIndex tile);
void SetTileSelectSize(int w, int h);
void SetTileSelectBigSize(int ox, int oy, int sx, int sy);

View File

@ -113,6 +113,8 @@ DECLARE_ENUM_AS_BIT_SET(ViewportPlaceMethod)
* you've selected it.
*/
enum ViewportDragDropSelectionProcess : uint8_t {
DDSP_NONE,
DDSP_DEMOLISH_AREA, ///< Clear area
DDSP_RAISE_AND_LEVEL_AREA, ///< Raise / level area
DDSP_LOWER_AND_LEVEL_AREA, ///< Lower / level area

View File

@ -2841,14 +2841,14 @@ static void MouseLoop(MouseClick click, int mousewheel)
HandleMouseOver();
bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == SWS_SCROLL_MAP && _cursor.wheel_moved;
if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return;
if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling && (_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return;
int x = _cursor.pos.x;
int y = _cursor.pos.y;
Window *w = FindWindowFromPt(x, y);
if (w == nullptr) return;
if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return;
if (click != MC_NONE && click != MC_HOVER && !MaybeBringWindowToFront(w)) return;
Viewport *vp = IsPtInWindowViewport(w, x, y);
/* Don't allow any action in a viewport if either in menu or when having a modal progress window */
@ -2876,7 +2876,7 @@ static void MouseLoop(MouseClick click, int mousewheel)
switch (click) {
case MC_DOUBLE_LEFT:
case MC_LEFT:
if (HandleViewportClicked(*vp, x, y)) return;
if (HandleViewportClicked(*vp, x, y, false)) return;
if (!w->flags.Test(WindowFlag::DisableVpScroll) &&
_settings_client.gui.scroll_mode == VSM_MAP_LMB) {
_scrolling_viewport = true;
@ -2897,6 +2897,7 @@ static void MouseLoop(MouseClick click, int mousewheel)
break;
default:
HandleViewportClicked(*vp, x, y, true);
break;
}
}

View File

@ -796,8 +796,9 @@ public:
* has been set.
* @param pt the exact point on the map that has been clicked.
* @param tile the tile on the map that has been clicked.
* @param query set if the tile was not actually clicked.
*/
virtual void OnPlaceObject([[maybe_unused]] Point pt, [[maybe_unused]] TileIndex tile) {}
virtual void OnPlaceObject([[maybe_unused]] Point pt, [[maybe_unused]] TileIndex tile, [[maybe_unused]] bool query) {}
/**
* The user clicked on a vehicle while HT_VEHICLE has been set.
@ -839,7 +840,7 @@ public:
* @param start_tile the begin tile of the drag.
* @param end_tile the end tile of the drag.
*/
virtual void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, [[maybe_unused]] ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, [[maybe_unused]] TileIndex start_tile, [[maybe_unused]] TileIndex end_tile) {}
virtual void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, [[maybe_unused]] ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, [[maybe_unused]] TileIndex start_tile, [[maybe_unused]] TileIndex end_tile, [[maybe_unused]] bool query) {}
/**
* The user moves over the map when a tile highlight mode has been set