diff --git a/src/depot_func.h b/src/depot_func.h index d4d5ab69aa..f214e6d848 100644 --- a/src/depot_func.h +++ b/src/depot_func.h @@ -41,4 +41,7 @@ CommandCost FindJoiningDepot(TileArea ta, VehicleType veh_type, DepotID &join_to using DepotPickerCmdProc = std::function; void ShowSelectDepotIfNeeded(TileArea ta, DepotPickerCmdProc proc, VehicleType veh_type); +struct Window; +void CheckRedrawDepotHighlight(const Window *w, VehicleType veh_type); + #endif /* DEPOT_FUNC_H */ diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index bd85a59458..511099bcd1 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -80,6 +80,7 @@ static constexpr NWidgetPart _nested_train_depot_widgets[] = { NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_D_BUILD), SetDataTip(0x0, STR_NULL), SetFill(1, 1), SetResize(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_D_CLONE), SetDataTip(0x0, STR_NULL), SetFill(1, 1), SetResize(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_D_HIGHLIGHT), SetDataTip(STR_BUTTON_HIGHLIGHT_DEPOT, STR_TOOLTIP_HIGHLIGHT_DEPOT), SetFill(1, 1), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_D_VEHICLE_LIST), SetDataTip(0x0, STR_NULL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_ICON), SetFill(0, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_STOP_ALL), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_NULL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG), SetFill(0, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_START_ALL), SetDataTip(SPR_FLAG_VEH_RUNNING, STR_NULL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG), SetFill(0, 1), @@ -303,6 +304,7 @@ struct DepotWindow : Window { CloseWindowById(WC_BUILD_VEHICLE, this->window_number); CloseWindowById(GetWindowClassForVehicleType(this->type), VehicleListIdentifier(VL_DEPOT_LIST, this->type, this->owner, this->window_number).Pack(), false); OrderBackup::Reset(this->window_number); + SetViewportHighlightDepot(this->window_number, false); this->Window::Close(); } @@ -712,6 +714,9 @@ struct DepotWindow : Window { void OnPaint() override { + extern DepotID _viewport_highlight_depot; + this->SetWidgetLoweredState(WID_D_HIGHLIGHT, _viewport_highlight_depot == this->window_number); + if (this->generate_list) { /* Generate the vehicle list * It's ok to use the wagon pointers for non-trains as they will be ignored */ @@ -804,6 +809,11 @@ struct DepotWindow : Window { ShowQueryString(STR_DEPOT_NAME, STR_DEPOT_RENAME_DEPOT_CAPTION, MAX_LENGTH_DEPOT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); break; + case WID_D_HIGHLIGHT: + this->SetWidgetDirty(WID_D_HIGHLIGHT); + SetViewportHighlightDepot(this->window_number, !this->IsWidgetLowered(WID_D_HIGHLIGHT)); + break; + case WID_D_STOP_ALL: case WID_D_START_ALL: { VehicleListIdentifier vli(VL_DEPOT_LIST, this->type, this->owner); @@ -1286,6 +1296,15 @@ struct SelectDepotWindow : Window { this->vscroll = this->GetScrollbar(WID_JD_SCROLLBAR); this->FinishInitNested(veh_type); this->OnInvalidateData(0); + + _thd.freeze = true; + } + + ~SelectDepotWindow() + { + SetViewportHighlightDepot(INVALID_DEPOT, true); + + _thd.freeze = false; } void UpdateWidgetSize(int widget, Dimension &size, const Dimension &padding, [[maybe_unused]] Dimension &fill, Dimension &resize) override @@ -1370,6 +1389,19 @@ struct SelectDepotWindow : Window { this->vscroll->SetCount((uint)_depots_nearby_list.size()); this->SetDirty(); } + + void OnMouseOver(Point pt, int widget) override + { + if (widget != WID_JD_PANEL) { + SetViewportHighlightDepot(INVALID_DEPOT, true); + return; + } + + /* Highlight depot under cursor */ + auto it = this->vscroll->GetScrolledItemFromWidget(_depots_nearby_list, pt.y, this, WID_JD_PANEL, WidgetDimensions::scaled.framerect.top); + SetViewportHighlightDepot(*it, true); + } + }; static const NWidgetPart _nested_select_depot_widgets[] = { @@ -1409,3 +1441,76 @@ void ShowSelectDepotIfNeeded(TileArea ta, DepotPickerCmdProc proc, VehicleType v proc(INVALID_DEPOT); } } + +/** + * Find depots adjacent to the current tile highlight area, so that all depot tiles + * can be highlighted. + * @param v_type Vehicle type to check. + */ +static void HighlightSingleAdjacentDepot(VehicleType v_type) +{ + /* With distant join we don't know which depot will be selected, so don't show any */ + if (_ctrl_pressed) { + SetViewportHighlightDepot(INVALID_DEPOT, true); + return; + } + + /* Tile area for TileHighlightData */ + TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1); + + /* If the current tile is already a depot, then it must be the nearest depot. */ + if (IsDepotTypeTile(location.tile, (TransportType)v_type) && + GetTileOwner(location.tile) == _local_company) { + SetViewportHighlightDepot(GetDepotIndex(location.tile), true); + return; + } + + /* Extended area by one tile */ + uint x = TileX(location.tile); + uint y = TileY(location.tile); + + int max_c = 1; + TileArea ta(TileXY(std::max(0, x - max_c), std::max(0, y - max_c)), TileXY(std::min(Map::MaxX(), x + location.w + max_c), std::min(Map::MaxY(), y + location.h + max_c))); + + DepotID adjacent = INVALID_DEPOT; + + for (TileIndex tile : ta) { + if (IsDepotTile(tile) && GetTileOwner(tile) == _local_company) { + Depot *depot = Depot::GetByTile(tile); + if (depot == nullptr) continue; + if (depot->veh_type != v_type) continue; + if (adjacent != INVALID_DEPOT && depot->index != adjacent) { + /* Multiple nearby, distant join is required. */ + adjacent = INVALID_DEPOT; + break; + } + adjacent = depot->index; + } + } + SetViewportHighlightDepot(adjacent, true); +} + +/** + * Check whether we need to redraw the depot highlight. + * If it is needed actually make the window for redrawing. + * @param w the window to check. + * @param veh_type vehicle type to check. + */ +void CheckRedrawDepotHighlight(const Window *w, VehicleType veh_type) +{ + /* Test if ctrl state changed */ + static bool _last_ctrl_pressed; + if (_ctrl_pressed != _last_ctrl_pressed) { + _thd.dirty = 0xff; + _last_ctrl_pressed = _ctrl_pressed; + } + + if (_thd.dirty & 1) { + _thd.dirty &= ~1; + w->SetDirty(); + + if (_thd.drawstyle == HT_RECT) { + HighlightSingleAdjacentDepot(veh_type); + } + } +} diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index ccf35c3e44..7ba951d141 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -32,6 +32,7 @@ #include "waypoint_cmd.h" #include "timer/timer.h" #include "timer/timer_game_calendar.h" +#include "depot_func.h" #include "widgets/dock_widget.h" @@ -112,6 +113,8 @@ struct BuildDocksToolbarWindow : Window { { if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_DT_STATION)) SetViewportCatchmentStation(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WC_SCEN_LAND_GEN, 0, false); + if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_DT_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true); + this->Window::Close(); } @@ -270,6 +273,8 @@ struct BuildDocksToolbarWindow : Window { { if (_game_mode != GM_EDITOR && this->IsWidgetLowered(WID_DT_STATION)) SetViewportCatchmentStation(nullptr, true); + if (_game_mode != GM_EDITOR && this->IsWidgetLowered(WID_DT_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true); + this->RaiseButtons(); CloseWindowById(WC_BUILD_STATION, TRANSPORT_WATER); @@ -586,6 +591,11 @@ public: break; } } + + void OnRealtimeTick([[maybe_unused]] uint delta_ms) override + { + CheckRedrawDepotHighlight(this, VEH_SHIP); + } }; static constexpr NWidgetPart _nested_build_docks_depot_widgets[] = { diff --git a/src/lang/english.txt b/src/lang/english.txt index 34c296c15f..a07296d36e 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -278,6 +278,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Select f STR_BUTTON_SORT_BY :{BLACK}Sort by STR_BUTTON_CATCHMENT :{BLACK}Coverage STR_TOOLTIP_CATCHMENT :{BLACK}Toggle coverage area display +STR_BUTTON_HIGHLIGHT_DEPOT :{BLACK}Highlight +STR_TOOLTIP_HIGHLIGHT_DEPOT :{BLACK}Toggle highlight on viewport for this depot STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Close window STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Window title - drag this to move window diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 016ad51c59..dcb0780919 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -41,6 +41,7 @@ #include "timer/timer.h" #include "timer/timer_game_calendar.h" #include "picker_gui.h" +#include "depot_func.h" #include "station_map.h" #include "tunnelbridge_map.h" @@ -454,6 +455,7 @@ struct BuildRailToolbarWindow : Window { if (this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT)) SetViewportCatchmentWaypoint(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WC_SCEN_LAND_GEN, 0, false); CloseWindowById(WC_SELECT_STATION, 0); + if (this->IsWidgetLowered(WID_RAT_BUILD_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true); this->Window::Close(); } @@ -795,6 +797,8 @@ struct BuildRailToolbarWindow : Window { if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) SetViewportCatchmentStation(nullptr, true); if (this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT)) SetViewportCatchmentWaypoint(nullptr, true); + if (this->IsWidgetLowered(WID_RAT_BUILD_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true); + this->RaiseButtons(); this->DisableWidget(WID_RAT_REMOVE); this->SetWidgetDirty(WID_RAT_REMOVE); @@ -1750,6 +1754,11 @@ struct BuildRailDepotWindow : public PickerWindowBase { break; } } + + void OnRealtimeTick([[maybe_unused]] uint delta_ms) override + { + CheckRedrawDepotHighlight(this, VEH_TRAIN); + } }; /** Nested widget definition of the build rail depot window */ diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 3f9b9251cf..14764444b8 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -43,6 +43,7 @@ #include "picker_gui.h" #include "timer/timer.h" #include "timer/timer_game_calendar.h" +#include "depot_func.h" #include "widgets/road_widget.h" @@ -368,6 +369,7 @@ struct BuildRoadToolbarWindow : Window { { if (_game_mode == GM_NORMAL && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WC_SCEN_LAND_GEN, 0, false); + if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_ROT_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true); this->Window::Close(); } @@ -673,6 +675,8 @@ struct BuildRoadToolbarWindow : Window { { if (_game_mode != GM_EDITOR && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true); + if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_ROT_DEPOT)) SetViewportHighlightDepot(INVALID_DEPOT, true); + this->RaiseButtons(); this->SetWidgetDisabledState(WID_ROT_REMOVE, true); this->SetWidgetDirty(WID_ROT_REMOVE); @@ -1154,6 +1158,11 @@ struct BuildRoadDepotWindow : public PickerWindowBase { break; } } + + void OnRealtimeTick([[maybe_unused]] uint delta_ms) override + { + CheckRedrawDepotHighlight(this, VEH_ROAD); + } }; static constexpr NWidgetPart _nested_build_road_depot_widgets[] = { diff --git a/src/viewport.cpp b/src/viewport.cpp index 1aa848058e..fbe06c45e3 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -90,6 +90,7 @@ #include "network/network_func.h" #include "framerate_type.h" #include "viewport_cmd.h" +#include "depot_map.h" #include #include @@ -1002,6 +1003,7 @@ enum TileHighlightType { const Station *_viewport_highlight_station; ///< Currently selected station for coverage area highlight const Waypoint *_viewport_highlight_waypoint; ///< Currently selected waypoint for coverage area highlight const Town *_viewport_highlight_town; ///< Currently selected town for coverage area highlight +DepotID _viewport_highlight_depot = INVALID_DEPOT; ///< Currently selected depot for depot highlight /** * Get tile highlight type of coverage area for a given tile. @@ -1010,6 +1012,10 @@ const Town *_viewport_highlight_town; ///< Currently selected town for coverage */ static TileHighlightType GetTileHighlightType(TileIndex t) { + if (_viewport_highlight_depot != INVALID_DEPOT) { + if (IsDepotTile(t) && GetDepotIndex(t) == _viewport_highlight_depot) return THT_WHITE; + } + if (_viewport_highlight_station != nullptr) { if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station->index) return THT_WHITE; if (_viewport_highlight_station->TileIsInCatchment(t)) return THT_BLUE; @@ -3589,6 +3595,9 @@ void MarkCatchmentTilesDirty() } MarkWholeScreenDirty(); } + if (_viewport_highlight_depot != INVALID_DEPOT) { + MarkWholeScreenDirty(); + } } static void SetWindowDirtyForViewportCatchment() @@ -3596,6 +3605,7 @@ static void SetWindowDirtyForViewportCatchment() if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index); if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index); if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index); + if (_viewport_highlight_depot != INVALID_DEPOT) SetWindowDirty(WC_VEHICLE_DEPOT, _viewport_highlight_depot); } static void ClearViewportCatchment() @@ -3604,6 +3614,7 @@ static void ClearViewportCatchment() _viewport_highlight_station = nullptr; _viewport_highlight_waypoint = nullptr; _viewport_highlight_town = nullptr; + _viewport_highlight_depot = INVALID_DEPOT; } /** @@ -3665,3 +3676,30 @@ void SetViewportCatchmentTown(const Town *t, bool sel) } if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index); } + +static void MarkDepotTilesDirty() +{ + if (_viewport_highlight_depot != INVALID_DEPOT) { + MarkWholeScreenDirty(); + return; + } +} + +/** + * Select or deselect depot to highlight. + * @param *dep Depot in question + * @param sel Select or deselect given depot + */ +void SetViewportHighlightDepot(const DepotID dep, bool sel) +{ + SetWindowDirtyForViewportCatchment(); + if (sel && _viewport_highlight_depot != dep) { + ClearViewportCatchment(); + _viewport_highlight_depot = dep; + MarkDepotTilesDirty(); + } else if (!sel && _viewport_highlight_depot == dep) { + MarkDepotTilesDirty(); + _viewport_highlight_depot = INVALID_DEPOT; + } + if (_viewport_highlight_depot != INVALID_DEPOT) SetWindowDirty(WC_VEHICLE_DEPOT, _viewport_highlight_depot); +} diff --git a/src/viewport_func.h b/src/viewport_func.h index 5b1537478c..94e132f88a 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -16,6 +16,7 @@ #include "tile_map.h" #include "station_type.h" #include "vehicle_type.h" +#include "depot_type.h" static const int TILE_HEIGHT_STEP = 50; ///< One Z unit tile height difference is displayed as 50m. @@ -102,6 +103,8 @@ struct Town; void SetViewportCatchmentStation(const Station *st, bool sel); void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel); void SetViewportCatchmentTown(const Town *t, bool sel); +void SetViewportHighlightDepot(const DepotID dep, bool sel); + void MarkCatchmentTilesDirty(); template diff --git a/src/widgets/depot_widget.h b/src/widgets/depot_widget.h index 5c98203a03..8797fb36ff 100644 --- a/src/widgets/depot_widget.h +++ b/src/widgets/depot_widget.h @@ -27,6 +27,7 @@ enum DepotWidgets : WidgetID { WID_D_LOCATION, ///< Location button. WID_D_SHOW_RENAME, ///< Show rename panel. WID_D_RENAME, ///< Rename button. + WID_D_HIGHLIGHT, ///< Highlight button. WID_D_VEHICLE_LIST, ///< List of vehicles. WID_D_STOP_ALL, ///< Stop all button. WID_D_START_ALL, ///< Start all button.