From d219a99b5676db2f4c169a8220febad2758b82bb Mon Sep 17 00:00:00 2001 From: Duncan Date: Fri, 4 Mar 2022 07:17:20 +0000 Subject: [PATCH] Convert scenery window to class (#16729) * Convert scenery window to class Close #13799 * Move static's into class * Simplify eyedropper setting code --- src/openrct2-ui/windows/Scenery.cpp | 2430 ++++++++++++------------ src/openrct2-ui/windows/TopToolbar.cpp | 44 +- src/openrct2-ui/windows/Window.h | 4 +- 3 files changed, 1207 insertions(+), 1271 deletions(-) diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index 14dfcb8957..71d2442e8e 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -35,42 +35,8 @@ constexpr int32_t SCENERY_BUTTON_HEIGHT = 80; constexpr uint8_t SceneryContentScrollIndex = 0; -// clang-format off -static void WindowSceneryClose(rct_window *w); -static void WindowSceneryMouseup(rct_window *w, rct_widgetindex widgetIndex); -static void WindowSceneryResize(rct_window *w); -static void WindowSceneryMousedown(rct_window *w, rct_widgetindex widgetIndex, rct_widget* widget); -static void WindowSceneryDropdown(rct_window *w, rct_widgetindex widgetIndex, int32_t dropdownIndex); -static void WindowSceneryUpdate(rct_window *w); -static void WindowSceneryPeriodicUpdate(rct_window *w); -static void WindowSceneryScrollgetsize(rct_window *w, int32_t scrollIndex, int32_t *width, int32_t *height); -static void WindowSceneryScrollmousedown(rct_window *w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords); -static void WindowSceneryScrollmouseover(rct_window *w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords); -static OpenRCT2String WindowSceneryTooltip(rct_window* w, const rct_widgetindex widgetIndex, const rct_string_id fallback); -static void WindowSceneryInvalidate(rct_window *w); -static void WindowSceneryPaint(rct_window *w, rct_drawpixelinfo *dpi); -static void WindowSceneryScrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int32_t scrollIndex); - -static rct_window_event_list window_scenery_events([](auto& events) +enum WindowSceneryListWidgetIdx { - events.close = &WindowSceneryClose; - events.mouse_up = &WindowSceneryMouseup; - events.resize = &WindowSceneryResize; - events.mouse_down = &WindowSceneryMousedown; - events.dropdown = &WindowSceneryDropdown; - events.update = &WindowSceneryUpdate; - events.periodic_update = &WindowSceneryPeriodicUpdate; - events.get_scroll_size = &WindowSceneryScrollgetsize; - events.scroll_mousedown = &WindowSceneryScrollmousedown; - events.scroll_mouseover = &WindowSceneryScrollmouseover; - events.tooltip = &WindowSceneryTooltip; - events.invalidate = &WindowSceneryInvalidate; - events.paint = &WindowSceneryPaint; - events.scroll_paint = &WindowSceneryScrollpaint; -}); - - -enum WindowSceneryListWidgetIdx { WIDX_SCENERY_BACKGROUND, WIDX_SCENERY_TITLE, WIDX_SCENERY_CLOSE, @@ -90,6 +56,7 @@ validate_global_widx(WC_SCENERY, WIDX_SCENERY_TAB_1); validate_global_widx(WC_SCENERY, WIDX_SCENERY_ROTATE_OBJECTS_BUTTON); validate_global_widx(WC_SCENERY, WIDX_SCENERY_EYEDROPPER_BUTTON); +// clang-format off static rct_widget WindowSceneryBaseWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WINDOW_SCENERY_WIDTH, WINDOW_SCENERY_HEIGHT), MakeWidget ({ 0, 43}, {634, 99}, WindowWidgetType::Resize, WindowColour::Secondary ), // 8 0x009DE2C8 @@ -105,37 +72,6 @@ static rct_widget WindowSceneryBaseWidgets[] = { }; // clang-format on -void WindowSceneryUpdateScroll(rct_window* w); - -struct SceneryTabInfo -{ - ObjectEntryIndex SceneryGroupIndex = OBJECT_ENTRY_INDEX_NULL; - std::vector Entries; - - bool IsMisc() const - { - return SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL; - } - - bool Contains(const ScenerySelection& entry) const - { - return std::find(std::begin(Entries), std::end(Entries), entry) != std::end(Entries); - } - - void AddEntry(const ScenerySelection& entry) - { - if (!Contains(entry)) - { - Entries.push_back(entry); - } - } - - const rct_scenery_group_entry* GetSceneryGroupEntry() const - { - return get_scenery_group_entry(SceneryGroupIndex); - } -}; - std::vector gWindowSceneryTabSelections; size_t gWindowSceneryActiveTabIndex; uint8_t gWindowSceneryPaintEnabled; @@ -145,1307 +81,1319 @@ colour_t gWindowScenerySecondaryColour; colour_t gWindowSceneryTertiaryColour; bool gWindowSceneryEyedropperEnabled; -static std::vector _tabEntries; -static std::vector _widgets; -static ScenerySelection _selectedScenery; -static int16_t _hoverCounter; - -static const ScenerySelection GetSelectedScenery(const size_t tabIndex) +class SceneryWindow final : public Window { - if (gWindowSceneryTabSelections.size() > tabIndex) +private: + struct SceneryItem { - return gWindowSceneryTabSelections[tabIndex]; - } - return {}; -} + int32_t allRows; + int32_t selected_item; + ScenerySelection scenerySelection; + }; -static void SetSelectedScenery(const size_t tabIndex, const ScenerySelection& value) -{ - if (gWindowSceneryTabSelections.size() <= tabIndex) + struct SceneryTabInfo { - gWindowSceneryTabSelections.resize(tabIndex + 1); - } - gWindowSceneryTabSelections[tabIndex] = value; -} + ObjectEntryIndex SceneryGroupIndex = OBJECT_ENTRY_INDEX_NULL; + std::vector Entries; -static SceneryTabInfo* GetSceneryTabInfoForGroup(const ObjectEntryIndex sceneryGroupIndex) -{ - if (sceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) - { - return &_tabEntries[_tabEntries.size() - 1]; - } - - for (auto& tabEntry : _tabEntries) - { - if (tabEntry.SceneryGroupIndex == sceneryGroupIndex) - return &tabEntry; - } - - return nullptr; -} - -static std::optional WindowSceneryFindTabWithScenery(const ScenerySelection& scenery) -{ - for (size_t i = 0; i < _tabEntries.size(); i++) - { - const auto& tabInfo = _tabEntries[i]; - if (tabInfo.Contains(scenery)) + bool IsMisc() const { - return i; + return SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL; } - } - return std::nullopt; -} -static void InitSceneryEntry(const ScenerySelection& selection, const ObjectEntryIndex sceneryGroupIndex) -{ - Guard::ArgumentInRange(selection.EntryIndex, 0, OBJECT_ENTRY_INDEX_NULL); - - if (IsSceneryAvailableToBuild(selection)) - { - // Get current tab - const auto tabIndex = WindowSceneryFindTabWithScenery(selection); - - // Add scenery to primary group (usually trees or path additions) - if (sceneryGroupIndex != OBJECT_ENTRY_INDEX_NULL) + bool Contains(const ScenerySelection& entry) const { - auto* tabInfo = GetSceneryTabInfoForGroup(sceneryGroupIndex); - if (tabInfo != nullptr) + return std::find(std::begin(Entries), std::end(Entries), entry) != std::end(Entries); + } + + void AddEntry(const ScenerySelection& entry) + { + if (!Contains(entry)) { - tabInfo->AddEntry(selection); - return; + Entries.push_back(entry); } } - // If scenery is no tab, add it to misc - if (!tabIndex.has_value()) + const rct_scenery_group_entry* GetSceneryGroupEntry() const { - auto* tabInfo = GetSceneryTabInfoForGroup(OBJECT_ENTRY_INDEX_NULL); - if (tabInfo != nullptr) - { - tabInfo->AddEntry(selection); - } + return get_scenery_group_entry(SceneryGroupIndex); } - } -} + }; -static void WindowScenerySortTabs() -{ - std::sort(_tabEntries.begin(), _tabEntries.end(), [](const SceneryTabInfo& a, const SceneryTabInfo& b) { - if (a.SceneryGroupIndex == b.SceneryGroupIndex) - return false; + std::vector _tabEntries; + std::vector _widgets; + ScenerySelection _selectedScenery; + int16_t _hoverCounter; - if (a.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) - return false; - if (b.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) - return true; - - const auto* entryA = a.GetSceneryGroupEntry(); - const auto* entryB = b.GetSceneryGroupEntry(); - return entryA->priority < entryB->priority; - }); -} - -static void WindowSceneryPrepareWidgets(rct_window* w) -{ - // Add the base widgets - _widgets.clear(); - for (const auto& widget : WindowSceneryBaseWidgets) +public: + void OnOpen() override { - _widgets.push_back(widget); - } + Init(); - // Remove WWT_LAST - auto lastWidget = _widgets.back(); - _widgets.pop_back(); - - // Add tabs - ScreenCoordsXY pos = { 3, 17 }; - for (const auto& tabInfo : _tabEntries) - { - auto widget = MakeTab(pos, STR_STRING_DEFINED_TOOLTIP); - pos.x += 31; - - if (tabInfo.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) - { - widget.image = SPR_TAB_QUESTION | IMAGE_TYPE_REMAP; - } - - _widgets.push_back(widget); - } - - _widgets.push_back(lastWidget); - - w->widgets = _widgets.data(); -} - -/** - * - * rct2: 0x006DFA00 - */ -static void WindowSceneryInit(rct_window* w) -{ - _tabEntries.clear(); - - auto maxTabs = 32; - for (ObjectEntryIndex scenerySetIndex = 0; scenerySetIndex < maxTabs - 1; scenerySetIndex++) - { - const auto* sceneryGroupEntry = get_scenery_group_entry(scenerySetIndex); - if (sceneryGroupEntry != nullptr && scenery_group_is_invented(scenerySetIndex)) - { - SceneryTabInfo tabInfo; - tabInfo.SceneryGroupIndex = scenerySetIndex; - for (size_t i = 0; i < sceneryGroupEntry->entry_count; i++) - { - const auto& sceneryEntry = sceneryGroupEntry->scenery_entries[i]; - if (IsSceneryAvailableToBuild(sceneryEntry)) - { - tabInfo.Entries.push_back(sceneryEntry); - } - } - if (tabInfo.Entries.size() > 0) - { - _tabEntries.push_back(std::move(tabInfo)); - } - } - } - - // Add misc tab - _tabEntries.emplace_back(); - - // small scenery - for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_SMALL_SCENERY_OBJECTS; sceneryId++) - { - const auto* sceneryEntry = get_small_scenery_entry(sceneryId); - if (sceneryEntry != nullptr) - { - InitSceneryEntry({ SCENERY_TYPE_SMALL, sceneryId }, sceneryEntry->scenery_tab_id); - } - } - - // large scenery - for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_LARGE_SCENERY_OBJECTS; sceneryId++) - { - const auto* sceneryEntry = get_large_scenery_entry(sceneryId); - if (sceneryEntry != nullptr) - { - InitSceneryEntry({ SCENERY_TYPE_LARGE, sceneryId }, sceneryEntry->scenery_tab_id); - } - } - - // walls - for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_WALL_SCENERY_OBJECTS; sceneryId++) - { - const auto* sceneryEntry = get_wall_entry(sceneryId); - if (sceneryEntry != nullptr) - { - InitSceneryEntry({ SCENERY_TYPE_WALL, sceneryId }, sceneryEntry->scenery_tab_id); - } - } - - // banners - for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_BANNER_OBJECTS; sceneryId++) - { - const auto* sceneryEntry = get_banner_entry(sceneryId); - if (sceneryEntry != nullptr) - { - InitSceneryEntry({ SCENERY_TYPE_BANNER, sceneryId }, sceneryEntry->scenery_tab_id); - } - } - - // path bits - for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_PATH_ADDITION_OBJECTS; sceneryId++) - { - const auto* sceneryEntry = get_footpath_item_entry(sceneryId); - if (sceneryEntry != nullptr) - { - InitSceneryEntry({ SCENERY_TYPE_PATH_ITEM, sceneryId }, sceneryEntry->scenery_tab_id); - } - } - - // Remove misc tab if empty - if (_tabEntries.back().Entries.size() == 0) - { - _tabEntries.pop_back(); - } - - WindowScenerySortTabs(); - WindowSceneryPrepareWidgets(w); - window_invalidate_by_class(WC_SCENERY); -} - -void WindowSceneryInit() -{ - auto* w = window_find_by_class(WC_SCENERY); - if (w != nullptr) - { - WindowSceneryInit(w); - } -} - -/** - * - * rct2: 0x006DFEE4 - */ -void WindowScenerySetDefaultPlacementConfiguration() -{ - gWindowSceneryRotation = 3; - gWindowSceneryPrimaryColour = COLOUR_BORDEAUX_RED; - gWindowScenerySecondaryColour = COLOUR_YELLOW; - gWindowSceneryTertiaryColour = COLOUR_DARK_BROWN; - - WindowSceneryInit(); - - gWindowSceneryTabSelections.clear(); - gWindowSceneryActiveTabIndex = 0; -} - -/** - * - * rct2: 0x006E0FEF - */ -rct_window* WindowSceneryOpen() -{ - // Check if window is already open - auto* window = window_bring_to_front_by_class(WC_SCENERY); - if (window != nullptr) - return window; - - window = WindowCreate( - ScreenCoordsXY(context_get_width() - WINDOW_SCENERY_WIDTH, 0x1D), WINDOW_SCENERY_WIDTH, WINDOW_SCENERY_HEIGHT, - &window_scenery_events, WC_SCENERY, WF_NO_SCROLLING); - - WindowSceneryInit(window); - - WindowInitScrollWidgets(window); - WindowSceneryUpdateScroll(window); - show_gridlines(); - gWindowSceneryRotation = 3; - gSceneryCtrlPressed = false; - gSceneryShiftPressed = false; - _selectedScenery = {}; - _hoverCounter = 0; - window_push_others_below(window); - gSceneryGhostType = 0; - gSceneryPlaceCost = MONEY32_UNDEFINED; - gSceneryPlaceRotation = 0; - gWindowSceneryPaintEnabled = 0; // repaint coloured scenery tool state - gWindowSceneryEyedropperEnabled = false; - - window->min_width = WINDOW_SCENERY_WIDTH; - window->max_width = WINDOW_SCENERY_WIDTH; - window->min_height = WINDOW_SCENERY_HEIGHT; - window->max_height = WINDOW_SCENERY_HEIGHT; - - return window; -} - -static int32_t WindowSceneryGetNumColumns(const rct_window* w) -{ - const auto* listWidget = &w->widgets[WIDX_SCENERY_LIST]; - const auto contentWidth = listWidget->width() - SCROLLBAR_WIDTH; - return contentWidth / SCENERY_BUTTON_WIDTH; -} - -/* - * - * rct2: 0x006E1A73 - */ -void WindowSceneryClose(rct_window* w) -{ - scenery_remove_ghost_tool_placement(); - hide_gridlines(); - viewport_set_visibility(0); - - if (gWindowSceneryScatterEnabled) - window_close_by_class(WC_SCENERY_SCATTER); - - if (scenery_tool_is_active()) - tool_cancel(); -} - -template constexpr static T WindowSceneryCountRows(const rct_window* w, T items) -{ - const auto rows = items / WindowSceneryGetNumColumns(w); - return rows; -} - -static size_t WindowSceneryCountRows(const rct_window* w) -{ - const auto tabIndex = gWindowSceneryActiveTabIndex; - if (tabIndex >= _tabEntries.size()) - { - return 0; - } - - const auto totalItems = _tabEntries[tabIndex].Entries.size(); - const auto numColumns = WindowSceneryGetNumColumns(w); - const auto rows = WindowSceneryCountRows(w, totalItems + numColumns - 1); - return rows; -} - -struct SceneryItem -{ - int32_t allRows; - int32_t selected_item; - ScenerySelection scenerySelection; -}; - -static SceneryItem WindowSceneryCountRowsWithSelectedItem(rct_window* w, const size_t tabIndex) -{ - SceneryItem sceneryItem = { 0, 0, ScenerySelection() }; - const auto scenerySelection = GetSelectedScenery(tabIndex); - const auto& tabInfo = _tabEntries[tabIndex]; - for (size_t i = 0; i < tabInfo.Entries.size(); i++) - { - const auto& currentEntry = tabInfo.Entries[i]; - if (currentEntry == scenerySelection) - { - sceneryItem.selected_item = static_cast(i); - sceneryItem.scenerySelection = scenerySelection; - } - } - sceneryItem.allRows = static_cast(WindowSceneryCountRows(w, tabInfo.Entries.size() + 8)); - return sceneryItem; -} - -static int32_t WindowSceneryRowsHeight(const size_t rows) -{ - return static_cast(rows * SCENERY_BUTTON_HEIGHT); -} - -/** - * - * rct2: 0x006BD94C - */ -static void WindowSceneryMouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - switch (widgetIndex) - { - case WIDX_SCENERY_CLOSE: - if (gWindowSceneryScatterEnabled) - window_close_by_class(WC_SCENERY_SCATTER); - window_close(w); - break; - case WIDX_SCENERY_ROTATE_OBJECTS_BUTTON: - gWindowSceneryRotation++; - gWindowSceneryRotation = gWindowSceneryRotation % 4; - scenery_remove_ghost_tool_placement(); - w->Invalidate(); - break; - case WIDX_SCENERY_REPAINT_SCENERY_BUTTON: - gWindowSceneryPaintEnabled ^= 1; - gWindowSceneryEyedropperEnabled = false; - if (gWindowSceneryScatterEnabled) - window_close_by_class(WC_SCENERY_SCATTER); - w->Invalidate(); - break; - case WIDX_SCENERY_EYEDROPPER_BUTTON: - gWindowSceneryPaintEnabled = 0; - gWindowSceneryEyedropperEnabled = !gWindowSceneryEyedropperEnabled; - if (gWindowSceneryScatterEnabled) - window_close_by_class(WC_SCENERY_SCATTER); - scenery_remove_ghost_tool_placement(); - w->Invalidate(); - break; - case WIDX_SCENERY_BUILD_CLUSTER_BUTTON: - gWindowSceneryPaintEnabled = 0; - gWindowSceneryEyedropperEnabled = false; - if (gWindowSceneryScatterEnabled) - window_close_by_class(WC_SCENERY_SCATTER); - else if ( - network_get_mode() != NETWORK_MODE_CLIENT - || network_can_perform_command(network_get_current_player_group_index(), -2)) - { - WindowSceneryScatterOpen(); - } - else - { - context_show_error(STR_CANT_DO_THIS, STR_PERMISSION_DENIED, {}); - } - w->Invalidate(); - break; - } -} - -/** - * - * rct2: 0x006E1EB4 - */ -void WindowSceneryUpdateScroll(rct_window* w) -{ - const auto tabIndex = gWindowSceneryActiveTabIndex; - if (tabIndex >= _tabEntries.size()) - { - return; - } - - const int32_t listHeight = w->height - 14 - w->widgets[WIDX_SCENERY_LIST].top - 1; - - const auto sceneryItem = WindowSceneryCountRowsWithSelectedItem(w, tabIndex); - w->scrolls[SceneryContentScrollIndex].v_bottom = WindowSceneryRowsHeight(sceneryItem.allRows) + 1; - - const int32_t maxTop = std::max(0, w->scrolls[SceneryContentScrollIndex].v_bottom - listHeight); - auto rowSelected = WindowSceneryCountRows(w, sceneryItem.selected_item); - if (sceneryItem.scenerySelection.IsUndefined()) - { - rowSelected = 0; - const auto& scenery = _tabEntries[tabIndex].Entries[0]; - if (!scenery.IsUndefined()) - { - SetSelectedScenery(tabIndex, scenery); - } - } - - w->scrolls[SceneryContentScrollIndex].v_top = WindowSceneryRowsHeight(rowSelected); - w->scrolls[SceneryContentScrollIndex].v_top = std::min(maxTop, w->scrolls[SceneryContentScrollIndex].v_top); - - WidgetScrollUpdateThumbs(w, WIDX_SCENERY_LIST); -} - -/** - * - * rct2: 0x006E1E48 - */ -static void WindowSceneryResize(rct_window* w) -{ - if (w->width < w->min_width) - { - w->Invalidate(); - w->width = w->min_width; - w->Invalidate(); - } - - if (w->width > w->max_width) - { - w->Invalidate(); - w->width = w->max_width; - w->Invalidate(); - } - - if (w->height < w->min_height) - { - w->Invalidate(); - w->height = w->min_height; - w->Invalidate(); - // HACK: For some reason invalidate has not been called - window_event_invalidate_call(w); - WindowSceneryUpdateScroll(w); - } - - if (w->height > w->max_height) - { - w->Invalidate(); - w->height = w->max_height; - w->Invalidate(); - // HACK: For some reason invalidate has not been called - window_event_invalidate_call(w); - WindowSceneryUpdateScroll(w); - } -} - -/** - * - * rct2: 0x006E1A25 - */ -static void WindowSceneryMousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - switch (widgetIndex) - { - case WIDX_SCENERY_PRIMARY_COLOUR_BUTTON: - WindowDropdownShowColour(w, widget, w->colours[1], gWindowSceneryPrimaryColour); - break; - case WIDX_SCENERY_SECONDARY_COLOUR_BUTTON: - WindowDropdownShowColour(w, widget, w->colours[1], gWindowScenerySecondaryColour); - break; - case WIDX_SCENERY_TERTIARY_COLOUR_BUTTON: - WindowDropdownShowColour(w, widget, w->colours[1], gWindowSceneryTertiaryColour); - break; - } - - if (widgetIndex >= WIDX_SCENERY_TAB_1) - { - gWindowSceneryActiveTabIndex = widgetIndex - WIDX_SCENERY_TAB_1; - w->Invalidate(); - gSceneryPlaceCost = MONEY32_UNDEFINED; - - WindowSceneryUpdateScroll(w); - } -} - -/** - * - * rct2: 0x006E1A54 - */ -static void WindowSceneryDropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - if (dropdownIndex == -1) - return; - - if (widgetIndex == WIDX_SCENERY_PRIMARY_COLOUR_BUTTON) - { - gWindowSceneryPrimaryColour = static_cast(dropdownIndex); - } - else if (widgetIndex == WIDX_SCENERY_SECONDARY_COLOUR_BUTTON) - { - gWindowScenerySecondaryColour = static_cast(dropdownIndex); - } - else if (widgetIndex == WIDX_SCENERY_TERTIARY_COLOUR_BUTTON) - { - gWindowSceneryTertiaryColour = static_cast(dropdownIndex); - } - - w->Invalidate(); -} - -static ScenerySelection GetSceneryIdByCursorPos(rct_window* w, const ScreenCoordsXY& screenCoords); - -/** - * - * rct2: 0x006E1B9F - */ -static void WindowSceneryPeriodicUpdate(rct_window* w) -{ - if (!_selectedScenery.IsUndefined()) - { - // Find out what scenery the cursor is over - const CursorState* state = context_get_cursor_state(); - rct_widgetindex widgetIndex = window_find_widget_from_point(w, state->position); - if (widgetIndex == WIDX_SCENERY_LIST) - { - ScreenCoordsXY scrollPos = {}; - int32_t scrollArea = 0; - int32_t scrollId = 0; - WidgetScrollGetPart(w, &w->widgets[WIDX_SCENERY_LIST], state->position, scrollPos, &scrollArea, &scrollId); - if (scrollArea == SCROLL_PART_VIEW) - { - const ScenerySelection scenery = GetSceneryIdByCursorPos(w, scrollPos); - if (scenery == _selectedScenery) - { - return; - } - } - } - - // Cursor was not over the currently hover selected scenery so reset hover selection. - // This will happen when the mouse leaves the scroll window and is required so that the cost and description switch to - // the tool scenery selection. + InitScrollWidgets(); + ContentUpdateScroll(); + show_gridlines(); + gWindowSceneryRotation = 3; + gSceneryCtrlPressed = false; + gSceneryShiftPressed = false; _selectedScenery = {}; + _hoverCounter = 0; + window_push_others_below(this); + gSceneryGhostType = 0; + gSceneryPlaceCost = MONEY32_UNDEFINED; + gSceneryPlaceRotation = 0; + gWindowSceneryPaintEnabled = 0; // repaint coloured scenery tool state + gWindowSceneryEyedropperEnabled = false; + + min_width = WINDOW_SCENERY_WIDTH; + max_width = WINDOW_SCENERY_WIDTH; + min_height = WINDOW_SCENERY_HEIGHT; + max_height = WINDOW_SCENERY_HEIGHT; } -} -/** - * - * rct2: 0x006E1CD3 - */ -static void WindowSceneryUpdate(rct_window* w) -{ - const CursorState* state = context_get_cursor_state(); - rct_window* other = window_find_from_point(state->position); - if (other == w) + void OnClose() override { - ScreenCoordsXY window = state->position - ScreenCoordsXY{ w->windowPos.x - 26, w->windowPos.y }; + scenery_remove_ghost_tool_placement(); + hide_gridlines(); + viewport_set_visibility(0); - if (window.y < 44 || window.x <= w->width) + if (gWindowSceneryScatterEnabled) + window_close_by_class(WC_SCENERY_SCATTER); + + if (scenery_tool_is_active()) + tool_cancel(); + } + + void OnMouseUp(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) { - rct_widgetindex widgetIndex = window_find_widget_from_point(w, state->position); - if (widgetIndex >= WIDX_SCENERY_TAB_CONTENT_PANEL) - { - _hoverCounter++; - if (_hoverCounter < 8) + case WIDX_SCENERY_CLOSE: + if (gWindowSceneryScatterEnabled) + window_close_by_class(WC_SCENERY_SCATTER); + Close(); + break; + case WIDX_SCENERY_ROTATE_OBJECTS_BUTTON: + gWindowSceneryRotation++; + gWindowSceneryRotation = gWindowSceneryRotation % 4; + scenery_remove_ghost_tool_placement(); + Invalidate(); + break; + case WIDX_SCENERY_REPAINT_SCENERY_BUTTON: + gWindowSceneryPaintEnabled ^= 1; + gWindowSceneryEyedropperEnabled = false; + if (gWindowSceneryScatterEnabled) + window_close_by_class(WC_SCENERY_SCATTER); + Invalidate(); + break; + case WIDX_SCENERY_EYEDROPPER_BUTTON: + gWindowSceneryPaintEnabled = 0; + gWindowSceneryEyedropperEnabled = !gWindowSceneryEyedropperEnabled; + if (gWindowSceneryScatterEnabled) + window_close_by_class(WC_SCENERY_SCATTER); + scenery_remove_ghost_tool_placement(); + Invalidate(); + break; + case WIDX_SCENERY_BUILD_CLUSTER_BUTTON: + gWindowSceneryPaintEnabled = 0; + gWindowSceneryEyedropperEnabled = false; + if (gWindowSceneryScatterEnabled) + window_close_by_class(WC_SCENERY_SCATTER); + else if ( + network_get_mode() != NETWORK_MODE_CLIENT + || network_can_perform_command(network_get_current_player_group_index(), -2)) { - if (input_get_state() != InputState::ScrollLeft) - { - w->min_width = WINDOW_SCENERY_WIDTH; - w->max_width = WINDOW_SCENERY_WIDTH; - w->min_height = WINDOW_SCENERY_HEIGHT; - w->max_height = WINDOW_SCENERY_HEIGHT; - } + WindowSceneryScatterOpen(); } else { - const auto& listWidget = w->widgets[WIDX_SCENERY_LIST]; - const auto nonListHeight = w->height - listWidget.height() + 2; + context_show_error(STR_CANT_DO_THIS, STR_PERMISSION_DENIED, {}); + } + Invalidate(); + break; + } + } - const auto numRows = static_cast(WindowSceneryCountRows(w)); - const auto maxContentHeight = numRows * SCENERY_BUTTON_HEIGHT; - const auto maxWindowHeight = maxContentHeight + nonListHeight; - const auto windowHeight = std::clamp(maxWindowHeight, WINDOW_SCENERY_HEIGHT, 463); + void OnResize() override + { + if (width < min_width) + { + Invalidate(); + width = min_width; + Invalidate(); + } - w->min_width = WINDOW_SCENERY_WIDTH; - w->max_width = WINDOW_SCENERY_WIDTH; - w->min_height = windowHeight; - w->max_height = windowHeight; + if (width > max_width) + { + Invalidate(); + width = max_width; + Invalidate(); + } + + if (height < min_height) + { + Invalidate(); + height = min_height; + Invalidate(); + // HACK: For some reason invalidate has not been called + window_event_invalidate_call(this); + ContentUpdateScroll(); + } + + if (height > max_height) + { + Invalidate(); + height = max_height; + Invalidate(); + // HACK: For some reason invalidate has not been called + window_event_invalidate_call(this); + ContentUpdateScroll(); + } + } + + void OnMouseDown(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_SCENERY_PRIMARY_COLOUR_BUTTON: + WindowDropdownShowColour(this, &widgets[widgetIndex], colours[1], gWindowSceneryPrimaryColour); + break; + case WIDX_SCENERY_SECONDARY_COLOUR_BUTTON: + WindowDropdownShowColour(this, &widgets[widgetIndex], colours[1], gWindowScenerySecondaryColour); + break; + case WIDX_SCENERY_TERTIARY_COLOUR_BUTTON: + WindowDropdownShowColour(this, &widgets[widgetIndex], colours[1], gWindowSceneryTertiaryColour); + break; + } + + if (widgetIndex >= WIDX_SCENERY_TAB_1) + { + gWindowSceneryActiveTabIndex = widgetIndex - WIDX_SCENERY_TAB_1; + Invalidate(); + gSceneryPlaceCost = MONEY32_UNDEFINED; + + ContentUpdateScroll(); + } + } + + void OnDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) override + { + if (dropdownIndex == -1) + return; + + if (widgetIndex == WIDX_SCENERY_PRIMARY_COLOUR_BUTTON) + { + gWindowSceneryPrimaryColour = static_cast(dropdownIndex); + } + else if (widgetIndex == WIDX_SCENERY_SECONDARY_COLOUR_BUTTON) + { + gWindowScenerySecondaryColour = static_cast(dropdownIndex); + } + else if (widgetIndex == WIDX_SCENERY_TERTIARY_COLOUR_BUTTON) + { + gWindowSceneryTertiaryColour = static_cast(dropdownIndex); + } + + Invalidate(); + } + + void OnPeriodicUpdate() override + { + if (!_selectedScenery.IsUndefined()) + { + // Find out what scenery the cursor is over + const CursorState* state = context_get_cursor_state(); + rct_widgetindex widgetIndex = window_find_widget_from_point(this, state->position); + if (widgetIndex == WIDX_SCENERY_LIST) + { + ScreenCoordsXY scrollPos = {}; + int32_t scrollArea = 0; + int32_t scrollId = 0; + WidgetScrollGetPart(this, &widgets[WIDX_SCENERY_LIST], state->position, scrollPos, &scrollArea, &scrollId); + if (scrollArea == SCROLL_PART_VIEW) + { + const ScenerySelection scenery = GetSceneryIdByCursorPos(scrollPos); + if (scenery == _selectedScenery) + { + return; + } + } + } + + // Cursor was not over the currently hover selected scenery so reset hover selection. + // This will happen when the mouse leaves the scroll window and is required so that the cost and description switch + // to the tool scenery selection. + _selectedScenery = {}; + } + } + + void OnUpdate() override + { + const CursorState* state = context_get_cursor_state(); + rct_window* other = window_find_from_point(state->position); + if (other == this) + { + ScreenCoordsXY window = state->position - ScreenCoordsXY{ windowPos.x - 26, windowPos.y }; + + if (window.y < 44 || window.x <= width) + { + rct_widgetindex widgetIndex = window_find_widget_from_point(this, state->position); + if (widgetIndex >= WIDX_SCENERY_TAB_CONTENT_PANEL) + { + _hoverCounter++; + if (_hoverCounter < 8) + { + if (input_get_state() != InputState::ScrollLeft) + { + min_width = WINDOW_SCENERY_WIDTH; + max_width = WINDOW_SCENERY_WIDTH; + min_height = WINDOW_SCENERY_HEIGHT; + max_height = WINDOW_SCENERY_HEIGHT; + } + } + else + { + const auto& listWidget = widgets[WIDX_SCENERY_LIST]; + const auto nonListHeight = height - listWidget.height() + 2; + + const auto numRows = static_cast(CountRows()); + const auto maxContentHeight = numRows * SCENERY_BUTTON_HEIGHT; + const auto maxWindowHeight = maxContentHeight + nonListHeight; + const auto windowHeight = std::clamp(maxWindowHeight, WINDOW_SCENERY_HEIGHT, 463); + + min_width = WINDOW_SCENERY_WIDTH; + max_width = WINDOW_SCENERY_WIDTH; + min_height = windowHeight; + max_height = windowHeight; + } + } + } + } + else + { + _hoverCounter = 0; + if (input_get_state() != InputState::ScrollLeft) + { + min_width = WINDOW_SCENERY_WIDTH; + max_width = WINDOW_SCENERY_WIDTH; + min_height = WINDOW_SCENERY_HEIGHT; + max_height = WINDOW_SCENERY_HEIGHT; + } + } + + Invalidate(); + + if (!scenery_tool_is_active()) + { + Close(); + return; + } + + if (gWindowSceneryEyedropperEnabled) + { + gCurrentToolId = Tool::Crosshair; + } + else if (gWindowSceneryPaintEnabled == 1) + { + gCurrentToolId = Tool::PaintDown; + } + else + { + const auto tabIndex = gWindowSceneryActiveTabIndex; + const auto tabSelectedScenery = GetSelectedScenery(tabIndex); + if (!tabSelectedScenery.IsUndefined()) + { + if (tabSelectedScenery.SceneryType == SCENERY_TYPE_BANNER) + { + gCurrentToolId = Tool::EntranceDown; + } + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_LARGE) + { + gCurrentToolId = static_cast(get_large_scenery_entry(tabSelectedScenery.EntryIndex)->tool_id); + } + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) + { + gCurrentToolId = static_cast(get_wall_entry(tabSelectedScenery.EntryIndex)->tool_id); + } + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_PATH_ITEM) + { // path bit + gCurrentToolId = static_cast(get_footpath_item_entry(tabSelectedScenery.EntryIndex)->tool_id); + } + else + { // small scenery + gCurrentToolId = static_cast(get_small_scenery_entry(tabSelectedScenery.EntryIndex)->tool_id); } } } } - else + + ScreenSize OnScrollGetSize(int32_t scrollIndex) override { - _hoverCounter = 0; - if (input_get_state() != InputState::ScrollLeft) + if (scrollIndex == SceneryContentScrollIndex) { - w->min_width = WINDOW_SCENERY_WIDTH; - w->max_width = WINDOW_SCENERY_WIDTH; - w->min_height = WINDOW_SCENERY_HEIGHT; - w->max_height = WINDOW_SCENERY_HEIGHT; + return ContentScrollGetSize(); + } + return {}; + } + + void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + if (scrollIndex == SceneryContentScrollIndex) + { + ContentScrollMouseDown(screenCoords); } } - w->Invalidate(); - - if (!scenery_tool_is_active()) + void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override { - window_close(w); - return; - } - - if (gWindowSceneryEyedropperEnabled) - { - gCurrentToolId = Tool::Crosshair; - } - else if (gWindowSceneryPaintEnabled == 1) - { - gCurrentToolId = Tool::PaintDown; - } - else - { - const auto tabIndex = gWindowSceneryActiveTabIndex; - const auto tabSelectedScenery = GetSelectedScenery(tabIndex); - if (!tabSelectedScenery.IsUndefined()) + if (scrollIndex == SceneryContentScrollIndex) { - if (tabSelectedScenery.SceneryType == SCENERY_TYPE_BANNER) - { - gCurrentToolId = Tool::EntranceDown; - } - else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_LARGE) - { - gCurrentToolId = static_cast(get_large_scenery_entry(tabSelectedScenery.EntryIndex)->tool_id); - } - else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) - { - gCurrentToolId = static_cast(get_wall_entry(tabSelectedScenery.EntryIndex)->tool_id); - } - else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_PATH_ITEM) - { // path bit - gCurrentToolId = static_cast(get_footpath_item_entry(tabSelectedScenery.EntryIndex)->tool_id); - } - else - { // small scenery - gCurrentToolId = static_cast(get_small_scenery_entry(tabSelectedScenery.EntryIndex)->tool_id); - } + ContentScrollMouseOver(screenCoords); } } -} -static void WindowSceneryContentScrollGetSize(rct_window* w, int32_t* height) -{ - auto rows = WindowSceneryCountRows(w); - *height = WindowSceneryRowsHeight(rows); -} - -/** - * - * rct2: 0x006E1A91 - */ -void WindowSceneryScrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height) -{ - if (scrollIndex == SceneryContentScrollIndex) + OpenRCT2String OnTooltip(const rct_widgetindex widgetIndex, const rct_string_id fallback) override { - WindowSceneryContentScrollGetSize(w, height); + if (widgetIndex >= WIDX_SCENERY_TAB_1) + { + const auto tabIndex = static_cast(widgetIndex - WIDX_SCENERY_TAB_1); + if (_tabEntries.size() > tabIndex) + { + const auto& tabInfo = _tabEntries[tabIndex]; + if (tabInfo.IsMisc()) + { + auto ft = Formatter(); + ft.Add(STR_MISCELLANEOUS); + return { fallback, ft }; + } + + const auto* sceneryEntry = tabInfo.GetSceneryGroupEntry(); + if (sceneryEntry != nullptr) + { + auto ft = Formatter(); + ft.Add(sceneryEntry->name); + return { fallback, ft }; + } + } + } + return { STR_NONE, Formatter() }; } -} -static ScenerySelection GetSceneryIdByCursorPos(rct_window* w, const ScreenCoordsXY& screenCoords) -{ - ScenerySelection scenery{}; - - const auto numColumns = WindowSceneryGetNumColumns(w); - const auto colIndex = screenCoords.x / SCENERY_BUTTON_WIDTH; - const auto rowIndex = screenCoords.y / SCENERY_BUTTON_HEIGHT; - if (colIndex >= 0 && colIndex < numColumns && rowIndex >= 0) + void OnPrepareDraw() override { - const auto tabSceneryIndex = static_cast((rowIndex * numColumns) + colIndex); + // Set the window title + rct_string_id titleStringId = STR_MISCELLANEOUS; const auto tabIndex = gWindowSceneryActiveTabIndex; if (tabIndex < _tabEntries.size()) { - auto& tabInfo = _tabEntries[tabIndex]; - if (tabSceneryIndex < tabInfo.Entries.size()) + const auto& tabInfo = _tabEntries[tabIndex]; + const auto* sgEntry = tabInfo.GetSceneryGroupEntry(); + if (sgEntry != nullptr) { - return tabInfo.Entries[tabSceneryIndex]; + titleStringId = sgEntry->name; } } - } - return scenery; -} + widgets[WIDX_SCENERY_TITLE].text = titleStringId; -static void WindowSceneryContentScrollMouseDown(rct_window* w, const ScreenCoordsXY& screenCoords) -{ - const auto scenery = GetSceneryIdByCursorPos(w, screenCoords); - if (scenery.IsUndefined()) - return; + pressed_widgets = 0; + pressed_widgets |= 1ULL << (tabIndex + WIDX_SCENERY_TAB_1); + if (gWindowSceneryPaintEnabled == 1) + pressed_widgets |= (1ULL << WIDX_SCENERY_REPAINT_SCENERY_BUTTON); + if (gWindowSceneryEyedropperEnabled) + pressed_widgets |= (1ULL << WIDX_SCENERY_EYEDROPPER_BUTTON); + if (gWindowSceneryScatterEnabled) + pressed_widgets |= (1ULL << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); - SetSelectedScenery(gWindowSceneryActiveTabIndex, scenery); + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; + widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::Empty; + widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::Empty; - gWindowSceneryPaintEnabled &= 0xFE; - gWindowSceneryEyedropperEnabled = false; - OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + (w->width / 2)); - _hoverCounter = -16; - gSceneryPlaceCost = MONEY32_UNDEFINED; - w->Invalidate(); -} - -/** - * - * rct2: 0x006E1C4A - */ -void WindowSceneryScrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) -{ - if (scrollIndex == SceneryContentScrollIndex) - { - WindowSceneryContentScrollMouseDown(w, screenCoords); - } -} - -static void WindowSceneryContentScrollMouseOver(rct_window* w, const ScreenCoordsXY& screenCoords) -{ - ScenerySelection scenery = GetSceneryIdByCursorPos(w, screenCoords); - if (!scenery.IsUndefined()) - { - _selectedScenery = scenery; - w->Invalidate(); - } -} - -/** - * - * rct2: 0x006E1BB8 - */ -void WindowSceneryScrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) -{ - if (scrollIndex == SceneryContentScrollIndex) - { - WindowSceneryContentScrollMouseOver(w, screenCoords); - } -} - -/** - * - * rct2: 0x006E1C05 - */ -OpenRCT2String WindowSceneryTooltip(rct_window* w, const rct_widgetindex widgetIndex, const rct_string_id fallback) -{ - if (widgetIndex >= WIDX_SCENERY_TAB_1) - { - const auto tabIndex = static_cast(widgetIndex - WIDX_SCENERY_TAB_1); - if (_tabEntries.size() > tabIndex) + if (!(gWindowSceneryPaintEnabled & 1)) { - const auto& tabInfo = _tabEntries[tabIndex]; - if (tabInfo.IsMisc()) - { - auto ft = Formatter(); - ft.Add(STR_MISCELLANEOUS); - return { fallback, ft }; - } + widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::FlatBtn; + } - const auto* sceneryEntry = tabInfo.GetSceneryGroupEntry(); + const auto tabSelectedScenery = GetSelectedScenery(tabIndex); + if (!tabSelectedScenery.IsUndefined()) + { + if (tabSelectedScenery.SceneryType == SCENERY_TYPE_SMALL) + { + if (!(gWindowSceneryPaintEnabled & 1)) + { + widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::FlatBtn; + } + + auto* sceneryEntry = get_small_scenery_entry(tabSelectedScenery.EntryIndex); + if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_ROTATABLE)) + { + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::FlatBtn; + } + } + else if (tabSelectedScenery.SceneryType >= SCENERY_TYPE_LARGE) + { + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::FlatBtn; + } + } + + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryPrimaryColour) + | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowScenerySecondaryColour) + | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryTertiaryColour) + | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; + + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + + if (gWindowSceneryPaintEnabled & 1) + { // repaint coloured scenery tool is on + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; + } + else if (!tabSelectedScenery.IsUndefined()) + { + if (tabSelectedScenery.SceneryType == SCENERY_TYPE_BANNER) + { + auto* bannerEntry = get_banner_entry(tabSelectedScenery.EntryIndex); + if (bannerEntry->flags & BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR) + { + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + } + } + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_LARGE) + { + auto* sceneryEntry = get_large_scenery_entry(tabSelectedScenery.EntryIndex); + + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR) + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + } + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) + { + auto* wallEntry = get_wall_entry(tabSelectedScenery.EntryIndex); + if (wallEntry->flags & (WALL_SCENERY_HAS_PRIMARY_COLOUR | WALL_SCENERY_HAS_GLASS)) + { + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + + if (wallEntry->flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) + { + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + + if (wallEntry->flags2 & WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR) + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + if (wallEntry->flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + } + } + } + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_SMALL) + { + auto* sceneryEntry = get_small_scenery_entry(tabSelectedScenery.EntryIndex); + + if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG_HAS_GLASS)) + { + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + + if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)) + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + } + } + } + + auto windowWidth = width; + if (_tabEntries.size() > 0) + { + const auto lastTabIndex = _tabEntries.size() - 1; + const auto lastTabWidget = &widgets[WIDX_SCENERY_TAB_1 + lastTabIndex]; + windowWidth = std::max(windowWidth, lastTabWidget->right + 3); + } + min_width = windowWidth; + max_width = windowWidth; + + widgets[WIDX_SCENERY_BACKGROUND].right = windowWidth - 1; + widgets[WIDX_SCENERY_BACKGROUND].bottom = height - 1; + widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].right = windowWidth - 1; + widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].bottom = height - 1; + widgets[WIDX_SCENERY_TITLE].right = windowWidth - 2; + widgets[WIDX_SCENERY_CLOSE].left = windowWidth - 13; + widgets[WIDX_SCENERY_CLOSE].right = widgets[WIDX_SCENERY_CLOSE].left + 10; + widgets[WIDX_SCENERY_LIST].right = windowWidth - 26; + widgets[WIDX_SCENERY_LIST].bottom = height - 14; + + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].left = windowWidth - 25; + widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].left = windowWidth - 25; + widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].left = windowWidth - 25; + widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].left = windowWidth - 25; + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].right = windowWidth - 2; + widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].right = windowWidth - 2; + widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].right = windowWidth - 2; + widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].right = windowWidth - 2; + + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].left = windowWidth - 19; + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].left = windowWidth - 19; + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].left = windowWidth - 19; + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].right = windowWidth - 8; + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].right = windowWidth - 8; + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].right = windowWidth - 8; + } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + DrawWidgets(dpi); + DrawTabs(dpi, windowPos); + + auto selectedSceneryEntry = _selectedScenery; + if (selectedSceneryEntry.IsUndefined()) + { + if (gWindowSceneryPaintEnabled & 1) // repaint coloured scenery tool is on + return; + if (gWindowSceneryEyedropperEnabled) + return; + + selectedSceneryEntry = GetSelectedScenery(gWindowSceneryActiveTabIndex); + if (selectedSceneryEntry.IsUndefined()) + return; + } + + auto [name, price] = GetNameAndPrice(selectedSceneryEntry); + if (price != MONEY32_UNDEFINED && !(gParkFlags & PARK_FLAGS_NO_MONEY)) + { + auto ft = Formatter(); + ft.Add(price); + + // -14 + DrawTextBasic( + &dpi, windowPos + ScreenCoordsXY{ width - 0x1A, height - 13 }, STR_COST_LABEL, ft, { TextAlignment::RIGHT }); + } + + auto ft = Formatter(); + ft.Add(name); + DrawTextEllipsised(&dpi, { windowPos.x + 3, windowPos.y + height - 13 }, width - 19, STR_BLACK_STRING, ft); + } + + void OnScrollDraw(int32_t scrollIndex, rct_drawpixelinfo& dpi) override + { + if (scrollIndex == SceneryContentScrollIndex) + { + ContentScrollDraw(dpi); + } + } + + void SetSelectedItem( + const ScenerySelection& scenery, const std::optional primary, const std::optional secondary, + const std::optional tertiary, const std::optional rotation) + { + auto tabIndex = FindTabWithScenery(scenery); + if (!tabIndex.has_value()) + { + return; + } + + gWindowSceneryActiveTabIndex = tabIndex.value(); + SetSelectedScenery(tabIndex.value(), scenery); + if (primary.has_value()) + { + gWindowSceneryPrimaryColour = primary.value(); + } + if (secondary.has_value()) + { + gWindowScenerySecondaryColour = secondary.value(); + } + if (tertiary.has_value()) + { + gWindowSceneryTertiaryColour = tertiary.value(); + } + if (rotation.has_value()) + { + gWindowSceneryRotation = rotation.value(); + } + gWindowSceneryEyedropperEnabled = false; + OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, context_get_width() / 2); + _hoverCounter = -16; + gSceneryPlaceCost = MONEY32_UNDEFINED; + Invalidate(); + } + + void SetSelectedTab(const ObjectEntryIndex sceneryGroupIndex) + { + const auto* tabInfo = GetSceneryTabInfoForGroup(sceneryGroupIndex); + if (tabInfo == nullptr) + { + tabInfo = &_tabEntries.back(); + } + const auto tabId = std::distance(&*_tabEntries.cbegin(), tabInfo); + + OnMouseDown(WIDX_SCENERY_TAB_1 + tabId); + } + + // Used after removing objects, in order to avoid crashes. + void ResetSelectedSceneryItems() + { + gWindowSceneryTabSelections.clear(); + } + + void Init() + { + _tabEntries.clear(); + + auto maxTabs = 32; + for (ObjectEntryIndex scenerySetIndex = 0; scenerySetIndex < maxTabs - 1; scenerySetIndex++) + { + const auto* sceneryGroupEntry = get_scenery_group_entry(scenerySetIndex); + if (sceneryGroupEntry != nullptr && scenery_group_is_invented(scenerySetIndex)) + { + SceneryTabInfo tabInfo; + tabInfo.SceneryGroupIndex = scenerySetIndex; + for (size_t i = 0; i < sceneryGroupEntry->entry_count; i++) + { + const auto& sceneryEntry = sceneryGroupEntry->scenery_entries[i]; + if (IsSceneryAvailableToBuild(sceneryEntry)) + { + tabInfo.Entries.push_back(sceneryEntry); + } + } + if (tabInfo.Entries.size() > 0) + { + _tabEntries.push_back(std::move(tabInfo)); + } + } + } + + // Add misc tab + _tabEntries.emplace_back(); + + // small scenery + for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_SMALL_SCENERY_OBJECTS; sceneryId++) + { + const auto* sceneryEntry = get_small_scenery_entry(sceneryId); if (sceneryEntry != nullptr) { - auto ft = Formatter(); - ft.Add(sceneryEntry->name); - return { fallback, ft }; + InitSceneryEntry({ SCENERY_TYPE_SMALL, sceneryId }, sceneryEntry->scenery_tab_id); } } - } - return { STR_NONE, Formatter() }; -} -/** - * - * rct2: 0x006E118B - */ -void WindowSceneryInvalidate(rct_window* w) -{ - // Set the window title - rct_string_id titleStringId = STR_MISCELLANEOUS; - const auto tabIndex = gWindowSceneryActiveTabIndex; - if (tabIndex < _tabEntries.size()) + // large scenery + for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_LARGE_SCENERY_OBJECTS; sceneryId++) + { + const auto* sceneryEntry = get_large_scenery_entry(sceneryId); + if (sceneryEntry != nullptr) + { + InitSceneryEntry({ SCENERY_TYPE_LARGE, sceneryId }, sceneryEntry->scenery_tab_id); + } + } + + // walls + for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_WALL_SCENERY_OBJECTS; sceneryId++) + { + const auto* sceneryEntry = get_wall_entry(sceneryId); + if (sceneryEntry != nullptr) + { + InitSceneryEntry({ SCENERY_TYPE_WALL, sceneryId }, sceneryEntry->scenery_tab_id); + } + } + + // banners + for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_BANNER_OBJECTS; sceneryId++) + { + const auto* sceneryEntry = get_banner_entry(sceneryId); + if (sceneryEntry != nullptr) + { + InitSceneryEntry({ SCENERY_TYPE_BANNER, sceneryId }, sceneryEntry->scenery_tab_id); + } + } + + // path bits + for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_PATH_ADDITION_OBJECTS; sceneryId++) + { + const auto* sceneryEntry = get_footpath_item_entry(sceneryId); + if (sceneryEntry != nullptr) + { + InitSceneryEntry({ SCENERY_TYPE_PATH_ITEM, sceneryId }, sceneryEntry->scenery_tab_id); + } + } + + // Remove misc tab if empty + if (_tabEntries.back().Entries.size() == 0) + { + _tabEntries.pop_back(); + } + + SortTabs(); + PrepareWidgets(); + window_invalidate_by_class(WC_SCENERY); + } + + void SetDefaultPlacementConfiguration() { + gWindowSceneryRotation = 3; + gWindowSceneryPrimaryColour = COLOUR_BORDEAUX_RED; + gWindowScenerySecondaryColour = COLOUR_YELLOW; + gWindowSceneryTertiaryColour = COLOUR_DARK_BROWN; + + Init(); + + gWindowSceneryTabSelections.clear(); + gWindowSceneryActiveTabIndex = 0; + } + +private: + int32_t GetNumColumns() const + { + const auto& listWidget = widgets[WIDX_SCENERY_LIST]; + const auto contentWidth = listWidget.width() - SCROLLBAR_WIDTH; + return contentWidth / SCENERY_BUTTON_WIDTH; + } + + template T CountRows(T items) const + { + const auto rows = items / GetNumColumns(); + return rows; + } + + size_t CountRows() const + { + const auto tabIndex = gWindowSceneryActiveTabIndex; + if (tabIndex >= _tabEntries.size()) + { + return 0; + } + + const auto totalItems = _tabEntries[tabIndex].Entries.size(); + const auto numColumns = GetNumColumns(); + const auto rows = CountRows(totalItems + numColumns - 1); + return rows; + } + + int32_t constexpr ContentRowsHeight(const size_t rows) const + { + return static_cast(rows * SCENERY_BUTTON_HEIGHT); + } + + void ContentUpdateScroll() + { + const auto tabIndex = gWindowSceneryActiveTabIndex; + if (tabIndex >= _tabEntries.size()) + { + return; + } + + const int32_t listHeight = height - 14 - widgets[WIDX_SCENERY_LIST].top - 1; + + const auto sceneryItem = ContentCountRowsWithSelectedItem(tabIndex); + scrolls[SceneryContentScrollIndex].v_bottom = ContentRowsHeight(sceneryItem.allRows) + 1; + + const int32_t maxTop = std::max(0, scrolls[SceneryContentScrollIndex].v_bottom - listHeight); + auto rowSelected = CountRows(sceneryItem.selected_item); + if (sceneryItem.scenerySelection.IsUndefined()) + { + rowSelected = 0; + const auto& scenery = _tabEntries[tabIndex].Entries[0]; + if (!scenery.IsUndefined()) + { + SetSelectedScenery(tabIndex, scenery); + } + } + + scrolls[SceneryContentScrollIndex].v_top = ContentRowsHeight(rowSelected); + scrolls[SceneryContentScrollIndex].v_top = std::min(maxTop, scrolls[SceneryContentScrollIndex].v_top); + + WidgetScrollUpdateThumbs(this, WIDX_SCENERY_LIST); + } + + SceneryItem ContentCountRowsWithSelectedItem(const size_t tabIndex) + { + SceneryItem sceneryItem = { 0, 0, ScenerySelection() }; + const auto scenerySelection = GetSelectedScenery(tabIndex); const auto& tabInfo = _tabEntries[tabIndex]; - const auto* sgEntry = tabInfo.GetSceneryGroupEntry(); - if (sgEntry != nullptr) + for (size_t i = 0; i < tabInfo.Entries.size(); i++) { - titleStringId = sgEntry->name; - } - } - w->widgets[WIDX_SCENERY_TITLE].text = titleStringId; - - w->pressed_widgets = 0; - w->pressed_widgets |= 1ULL << (tabIndex + WIDX_SCENERY_TAB_1); - if (gWindowSceneryPaintEnabled == 1) - w->pressed_widgets |= (1ULL << WIDX_SCENERY_REPAINT_SCENERY_BUTTON); - if (gWindowSceneryEyedropperEnabled) - w->pressed_widgets |= (1ULL << WIDX_SCENERY_EYEDROPPER_BUTTON); - if (gWindowSceneryScatterEnabled) - w->pressed_widgets |= (1ULL << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); - - w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; - w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::Empty; - w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::Empty; - - if (!(gWindowSceneryPaintEnabled & 1)) - { - w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::FlatBtn; - } - - const auto tabSelectedScenery = GetSelectedScenery(tabIndex); - if (!tabSelectedScenery.IsUndefined()) - { - if (tabSelectedScenery.SceneryType == SCENERY_TYPE_SMALL) - { - if (!(gWindowSceneryPaintEnabled & 1)) + const auto& currentEntry = tabInfo.Entries[i]; + if (currentEntry == scenerySelection) { - w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::FlatBtn; - } - - auto* sceneryEntry = get_small_scenery_entry(tabSelectedScenery.EntryIndex); - if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_ROTATABLE)) - { - w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::FlatBtn; + sceneryItem.selected_item = static_cast(i); + sceneryItem.scenerySelection = scenerySelection; } } - else if (tabSelectedScenery.SceneryType >= SCENERY_TYPE_LARGE) - { - w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::FlatBtn; - } + sceneryItem.allRows = static_cast(CountRows(tabInfo.Entries.size() + 8)); + return sceneryItem; } - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryPrimaryColour) - | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowScenerySecondaryColour) - | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryTertiaryColour) - | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; - w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; - - if (gWindowSceneryPaintEnabled & 1) - { // repaint coloured scenery tool is on - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; - } - else if (!tabSelectedScenery.IsUndefined()) + const ScenerySelection GetSelectedScenery(const size_t tabIndex) { - if (tabSelectedScenery.SceneryType == SCENERY_TYPE_BANNER) + if (gWindowSceneryTabSelections.size() > tabIndex) { - auto* bannerEntry = get_banner_entry(tabSelectedScenery.EntryIndex); - if (bannerEntry->flags & BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR) + return gWindowSceneryTabSelections[tabIndex]; + } + return {}; + } + + void SetSelectedScenery(const size_t tabIndex, const ScenerySelection& value) + { + if (gWindowSceneryTabSelections.size() <= tabIndex) + { + gWindowSceneryTabSelections.resize(tabIndex + 1); + } + gWindowSceneryTabSelections[tabIndex] = value; + } + + SceneryTabInfo* GetSceneryTabInfoForGroup(const ObjectEntryIndex sceneryGroupIndex) + { + if (sceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + { + return &_tabEntries[_tabEntries.size() - 1]; + } + + for (auto& tabEntry : _tabEntries) + { + if (tabEntry.SceneryGroupIndex == sceneryGroupIndex) + return &tabEntry; + } + + return nullptr; + } + + std::optional FindTabWithScenery(const ScenerySelection& scenery) + { + for (size_t i = 0; i < _tabEntries.size(); i++) + { + const auto& tabInfo = _tabEntries[i]; + if (tabInfo.Contains(scenery)) { - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + return i; } } - else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_LARGE) - { - auto* sceneryEntry = get_large_scenery_entry(tabSelectedScenery.EntryIndex); + return std::nullopt; + } - if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR) - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - } - else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) + void InitSceneryEntry(const ScenerySelection& selection, const ObjectEntryIndex sceneryGroupIndex) + { + Guard::ArgumentInRange(selection.EntryIndex, 0, OBJECT_ENTRY_INDEX_NULL); + + if (IsSceneryAvailableToBuild(selection)) { - auto* wallEntry = get_wall_entry(tabSelectedScenery.EntryIndex); - if (wallEntry->flags & (WALL_SCENERY_HAS_PRIMARY_COLOUR | WALL_SCENERY_HAS_GLASS)) + // Get current tab + const auto tabIndex = FindTabWithScenery(selection); + + // Add scenery to primary group (usually trees or path additions) + if (sceneryGroupIndex != OBJECT_ENTRY_INDEX_NULL) { - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + auto* tabInfo = GetSceneryTabInfoForGroup(sceneryGroupIndex); + if (tabInfo != nullptr) + { + tabInfo->AddEntry(selection); + return; + } + } + // If scenery is no tab, add it to misc + if (!tabIndex.has_value()) + { + auto* tabInfo = GetSceneryTabInfoForGroup(OBJECT_ENTRY_INDEX_NULL); + if (tabInfo != nullptr) + { + tabInfo->AddEntry(selection); + } + } + } + } + + void SortTabs() + { + std::sort(_tabEntries.begin(), _tabEntries.end(), [](const SceneryTabInfo& a, const SceneryTabInfo& b) { + if (a.SceneryGroupIndex == b.SceneryGroupIndex) + return false; + + if (a.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + return false; + if (b.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + return true; + + const auto* entryA = a.GetSceneryGroupEntry(); + const auto* entryB = b.GetSceneryGroupEntry(); + return entryA->priority < entryB->priority; + }); + } + + void PrepareWidgets() + { + // Add the base widgets + _widgets.clear(); + for (const auto& widget : WindowSceneryBaseWidgets) + { + _widgets.push_back(widget); + } + + // Remove WWT_LAST + auto lastWidget = _widgets.back(); + _widgets.pop_back(); + + // Add tabs + ScreenCoordsXY pos = { 3, 17 }; + for (const auto& tabInfo : _tabEntries) + { + auto widget = MakeTab(pos, STR_STRING_DEFINED_TOOLTIP); + pos.x += 31; + + if (tabInfo.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + { + widget.image = SPR_TAB_QUESTION | IMAGE_TYPE_REMAP; + } + + _widgets.push_back(widget); + } + + _widgets.push_back(lastWidget); + + widgets = _widgets.data(); + } + + ScenerySelection GetSceneryIdByCursorPos(const ScreenCoordsXY& screenCoords) const + { + ScenerySelection scenery{}; + + const auto numColumns = GetNumColumns(); + const auto colIndex = screenCoords.x / SCENERY_BUTTON_WIDTH; + const auto rowIndex = screenCoords.y / SCENERY_BUTTON_HEIGHT; + if (colIndex >= 0 && colIndex < numColumns && rowIndex >= 0) + { + const auto tabSceneryIndex = static_cast((rowIndex * numColumns) + colIndex); + const auto tabIndex = gWindowSceneryActiveTabIndex; + if (tabIndex < _tabEntries.size()) + { + auto& tabInfo = _tabEntries[tabIndex]; + if (tabSceneryIndex < tabInfo.Entries.size()) + { + return tabInfo.Entries[tabSceneryIndex]; + } + } + } + return scenery; + } + + ScreenSize ContentScrollGetSize() const + { + auto rows = CountRows(); + return { 0, ContentRowsHeight(rows) }; + } + + void ContentScrollMouseDown(const ScreenCoordsXY& screenCoords) + { + const auto scenery = GetSceneryIdByCursorPos(screenCoords); + if (scenery.IsUndefined()) + return; + + SetSelectedScenery(gWindowSceneryActiveTabIndex, scenery); + + gWindowSceneryPaintEnabled &= 0xFE; + gWindowSceneryEyedropperEnabled = false; + OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, windowPos.x + (width / 2)); + _hoverCounter = -16; + gSceneryPlaceCost = MONEY32_UNDEFINED; + Invalidate(); + } + + void ContentScrollMouseOver(const ScreenCoordsXY& screenCoords) + { + ScenerySelection scenery = GetSceneryIdByCursorPos(screenCoords); + if (!scenery.IsUndefined()) + { + _selectedScenery = scenery; + Invalidate(); + } + } + + std::pair GetNameAndPrice(ScenerySelection selectedScenery) + { + rct_string_id name = STR_UNKNOWN_OBJECT_TYPE; + money32 price = MONEY32_UNDEFINED; + if (selectedScenery.IsUndefined() && gSceneryPlaceCost != MONEY32_UNDEFINED) + { + price = gSceneryPlaceCost; + } + else + { + switch (selectedScenery.SceneryType) + { + case SCENERY_TYPE_SMALL: + { + auto* sceneryEntry = get_small_scenery_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + { + price = sceneryEntry->price * 10; + name = sceneryEntry->name; + } + break; + } + case SCENERY_TYPE_PATH_ITEM: + { + auto* sceneryEntry = get_footpath_item_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + { + price = sceneryEntry->price; + name = sceneryEntry->name; + } + break; + } + case SCENERY_TYPE_WALL: + { + auto* sceneryEntry = get_wall_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + { + price = sceneryEntry->price; + name = sceneryEntry->name; + } + break; + } + case SCENERY_TYPE_LARGE: + { + auto* sceneryEntry = get_large_scenery_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + { + price = sceneryEntry->price * 10; + name = sceneryEntry->name; + } + break; + } + case SCENERY_TYPE_BANNER: + { + auto* sceneryEntry = get_banner_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + { + price = sceneryEntry->price; + name = sceneryEntry->name; + } + break; + } + } + } + return { name, price }; + } + + void DrawTabs(rct_drawpixelinfo& dpi, const ScreenCoordsXY& offset) + { + for (size_t tabIndex = 0; tabIndex < _tabEntries.size(); tabIndex++) + { + auto widgetIndex = static_cast(WIDX_SCENERY_TAB_1 + tabIndex); + auto scgEntry = _tabEntries[tabIndex].GetSceneryGroupEntry(); + if (scgEntry != nullptr) + { + auto imageOffset = tabIndex == gWindowSceneryActiveTabIndex ? 1 : 0; + auto imageId = ImageId(scgEntry->image + imageOffset, colours[1]); + gfx_draw_sprite(&dpi, imageId, offset + ScreenCoordsXY{ widgets[widgetIndex].left, widgets[widgetIndex].top }); + } + } + } + + void DrawSceneryItem(rct_drawpixelinfo& dpi, ScenerySelection scenerySelection) + { + if (scenerySelection.SceneryType == SCENERY_TYPE_BANNER) + { + auto bannerEntry = get_banner_entry(scenerySelection.EntryIndex); + auto imageId = ImageId(bannerEntry->image + gWindowSceneryRotation * 2, gWindowSceneryPrimaryColour); + gfx_draw_sprite(&dpi, imageId, { 33, 40 }); + gfx_draw_sprite(&dpi, imageId.WithIndexOffset(1), { 33, 40 }); + } + else if (scenerySelection.SceneryType == SCENERY_TYPE_LARGE) + { + auto sceneryEntry = get_large_scenery_entry(scenerySelection.EntryIndex); + auto imageId = ImageId( + sceneryEntry->image + gWindowSceneryRotation, gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour); + gfx_draw_sprite(&dpi, imageId, { 33, 0 }); + } + else if (scenerySelection.SceneryType == SCENERY_TYPE_WALL) + { + auto wallEntry = get_wall_entry(scenerySelection.EntryIndex); + auto imageId = ImageId(wallEntry->image); + auto spriteTop = (wallEntry->height * 2) + 0x32; + if (wallEntry->flags & WALL_SCENERY_HAS_GLASS) + { + imageId = imageId.WithPrimary(gWindowSceneryPrimaryColour); if (wallEntry->flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) { - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + imageId = imageId.WithSecondary(gWindowScenerySecondaryColour); + } + gfx_draw_sprite(&dpi, imageId, { 47, spriteTop }); - if (wallEntry->flags2 & WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR) - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + auto glassImageId = ImageId(wallEntry->image + 6).WithTransparancy(gWindowSceneryPrimaryColour); + gfx_draw_sprite(&dpi, glassImageId, { 47, spriteTop }); + } + else + { + imageId = imageId.WithPrimary(gWindowSceneryPrimaryColour); + if (wallEntry->flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) + { + imageId = imageId.WithSecondary(gWindowScenerySecondaryColour); if (wallEntry->flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + { + imageId = imageId.WithTertiary(gWindowSceneryTertiaryColour); + } + } + gfx_draw_sprite(&dpi, imageId, { 47, spriteTop }); + + if (wallEntry->flags & WALL_SCENERY_IS_DOOR) + { + gfx_draw_sprite(&dpi, imageId.WithIndexOffset(1), { 47, spriteTop }); } } } - else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_SMALL) + else if (scenerySelection.SceneryType == SCENERY_TYPE_PATH_ITEM) { - auto* sceneryEntry = get_small_scenery_entry(tabSelectedScenery.EntryIndex); - - if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG_HAS_GLASS)) + auto* pathBitEntry = get_footpath_item_entry(scenerySelection.EntryIndex); + auto imageId = ImageId(pathBitEntry->image); + gfx_draw_sprite(&dpi, imageId, { 11, 16 }); + } + else + { + auto sceneryEntry = get_small_scenery_entry(scenerySelection.EntryIndex); + auto imageId = ImageId(sceneryEntry->image + gWindowSceneryRotation); + if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR)) { - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - + imageId = imageId.WithPrimary(gWindowSceneryPrimaryColour); if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)) - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + { + imageId = imageId.WithSecondary(gWindowScenerySecondaryColour); + } + } + + auto spriteTop = (sceneryEntry->height / 4) + 43; + if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_FULL_TILE) && sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE)) + { + spriteTop -= 12; + } + + gfx_draw_sprite(&dpi, imageId, { 32, spriteTop }); + + if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_GLASS)) + { + imageId = ImageId(sceneryEntry->image + 4 + gWindowSceneryRotation) + .WithTransparancy(gWindowSceneryPrimaryColour); + gfx_draw_sprite(&dpi, imageId, { 32, spriteTop }); + } + + if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_ANIMATED_FG)) + { + imageId = ImageId(sceneryEntry->image + 4 + gWindowSceneryRotation); + gfx_draw_sprite(&dpi, imageId, { 32, spriteTop }); } } } - auto windowWidth = w->width; - if (_tabEntries.size() > 0) + void ContentScrollDraw(rct_drawpixelinfo& dpi) { - const auto lastTabIndex = _tabEntries.size() - 1; - const auto lastTabWidget = &w->widgets[WIDX_SCENERY_TAB_1 + lastTabIndex]; - windowWidth = std::max(windowWidth, lastTabWidget->right + 3); - } - w->min_width = windowWidth; - w->max_width = windowWidth; + gfx_clear(&dpi, ColourMapA[colours[1]].mid_light); - w->widgets[WIDX_SCENERY_BACKGROUND].right = windowWidth - 1; - w->widgets[WIDX_SCENERY_BACKGROUND].bottom = w->height - 1; - w->widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].right = windowWidth - 1; - w->widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].bottom = w->height - 1; - w->widgets[WIDX_SCENERY_TITLE].right = windowWidth - 2; - w->widgets[WIDX_SCENERY_CLOSE].left = windowWidth - 13; - w->widgets[WIDX_SCENERY_CLOSE].right = w->widgets[WIDX_SCENERY_CLOSE].left + 10; - w->widgets[WIDX_SCENERY_LIST].right = windowWidth - 26; - w->widgets[WIDX_SCENERY_LIST].bottom = w->height - 14; - - w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].left = windowWidth - 25; - w->widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].left = windowWidth - 25; - w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].left = windowWidth - 25; - w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].left = windowWidth - 25; - w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].right = windowWidth - 2; - w->widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].right = windowWidth - 2; - w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].right = windowWidth - 2; - w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].right = windowWidth - 2; - - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].left = windowWidth - 19; - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].left = windowWidth - 19; - w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].left = windowWidth - 19; - w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].right = windowWidth - 8; - w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].right = windowWidth - 8; - w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].right = windowWidth - 8; -} - -static std::pair WindowSceneryGetNameAndPrice(ScenerySelection selectedScenery) -{ - rct_string_id name = STR_UNKNOWN_OBJECT_TYPE; - money32 price = MONEY32_UNDEFINED; - if (selectedScenery.IsUndefined() && gSceneryPlaceCost != MONEY32_UNDEFINED) - { - price = gSceneryPlaceCost; - } - else - { - switch (selectedScenery.SceneryType) + auto numColumns = GetNumColumns(); + auto tabIndex = gWindowSceneryActiveTabIndex; + if (tabIndex >= _tabEntries.size()) { - case SCENERY_TYPE_SMALL: - { - auto* sceneryEntry = get_small_scenery_entry(selectedScenery.EntryIndex); - if (sceneryEntry != nullptr) - { - price = sceneryEntry->price * 10; - name = sceneryEntry->name; - } - break; - } - case SCENERY_TYPE_PATH_ITEM: - { - auto* sceneryEntry = get_footpath_item_entry(selectedScenery.EntryIndex); - if (sceneryEntry != nullptr) - { - price = sceneryEntry->price; - name = sceneryEntry->name; - } - break; - } - case SCENERY_TYPE_WALL: - { - auto* sceneryEntry = get_wall_entry(selectedScenery.EntryIndex); - if (sceneryEntry != nullptr) - { - price = sceneryEntry->price; - name = sceneryEntry->name; - } - break; - } - case SCENERY_TYPE_LARGE: - { - auto* sceneryEntry = get_large_scenery_entry(selectedScenery.EntryIndex); - if (sceneryEntry != nullptr) - { - price = sceneryEntry->price * 10; - name = sceneryEntry->name; - } - break; - } - case SCENERY_TYPE_BANNER: - { - auto* sceneryEntry = get_banner_entry(selectedScenery.EntryIndex); - if (sceneryEntry != nullptr) - { - price = sceneryEntry->price; - name = sceneryEntry->name; - } - break; - } - } - } - return { name, price }; -} - -static void WindowSceneryDrawTabs(rct_window* w, rct_drawpixelinfo* dpi, const ScreenCoordsXY& offset) -{ - for (size_t tabIndex = 0; tabIndex < _tabEntries.size(); tabIndex++) - { - auto widgetIndex = static_cast(WIDX_SCENERY_TAB_1 + tabIndex); - auto scgEntry = _tabEntries[tabIndex].GetSceneryGroupEntry(); - if (scgEntry != nullptr) - { - auto imageOffset = tabIndex == gWindowSceneryActiveTabIndex ? 1 : 0; - auto imageId = ImageId(scgEntry->image + imageOffset, w->colours[1]); - gfx_draw_sprite(dpi, imageId, offset + ScreenCoordsXY{ w->widgets[widgetIndex].left, w->widgets[widgetIndex].top }); - } - } -} - -/** - * - * rct2: 0x006E1462 - */ -void WindowSceneryPaint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - WindowSceneryDrawTabs(w, dpi, w->windowPos); - - auto selectedSceneryEntry = _selectedScenery; - if (selectedSceneryEntry.IsUndefined()) - { - if (gWindowSceneryPaintEnabled & 1) // repaint coloured scenery tool is on return; - if (gWindowSceneryEyedropperEnabled) - return; - - selectedSceneryEntry = GetSelectedScenery(gWindowSceneryActiveTabIndex); - if (selectedSceneryEntry.IsUndefined()) - return; - } - - auto [name, price] = WindowSceneryGetNameAndPrice(selectedSceneryEntry); - if (price != MONEY32_UNDEFINED && !(gParkFlags & PARK_FLAGS_NO_MONEY)) - { - auto ft = Formatter(); - ft.Add(price); - - // -14 - DrawTextBasic( - dpi, w->windowPos + ScreenCoordsXY{ w->width - 0x1A, w->height - 13 }, STR_COST_LABEL, ft, - { TextAlignment::RIGHT }); - } - - auto ft = Formatter(); - ft.Add(name); - DrawTextEllipsised(dpi, { w->windowPos.x + 3, w->windowPos.y + w->height - 13 }, w->width - 19, STR_BLACK_STRING, ft); -} - -static void WindowSceneryScrollpaintItem(rct_window* w, rct_drawpixelinfo* dpi, ScenerySelection scenerySelection) -{ - if (scenerySelection.SceneryType == SCENERY_TYPE_BANNER) - { - auto bannerEntry = get_banner_entry(scenerySelection.EntryIndex); - auto imageId = ImageId(bannerEntry->image + gWindowSceneryRotation * 2, gWindowSceneryPrimaryColour); - gfx_draw_sprite(dpi, imageId, { 33, 40 }); - gfx_draw_sprite(dpi, imageId.WithIndexOffset(1), { 33, 40 }); - } - else if (scenerySelection.SceneryType == SCENERY_TYPE_LARGE) - { - auto sceneryEntry = get_large_scenery_entry(scenerySelection.EntryIndex); - auto imageId = ImageId( - sceneryEntry->image + gWindowSceneryRotation, gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour); - gfx_draw_sprite(dpi, imageId, { 33, 0 }); - } - else if (scenerySelection.SceneryType == SCENERY_TYPE_WALL) - { - auto wallEntry = get_wall_entry(scenerySelection.EntryIndex); - auto imageId = ImageId(wallEntry->image); - auto spriteTop = (wallEntry->height * 2) + 0x32; - if (wallEntry->flags & WALL_SCENERY_HAS_GLASS) - { - imageId = imageId.WithPrimary(gWindowSceneryPrimaryColour); - if (wallEntry->flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) - { - imageId = imageId.WithSecondary(gWindowScenerySecondaryColour); - } - gfx_draw_sprite(dpi, imageId, { 47, spriteTop }); - - auto glassImageId = ImageId(wallEntry->image + 6).WithTransparancy(gWindowSceneryPrimaryColour); - gfx_draw_sprite(dpi, glassImageId, { 47, spriteTop }); } - else + + ScreenCoordsXY topLeft{ 0, 0 }; + + const auto& tabInfo = _tabEntries[tabIndex]; + for (size_t sceneryTabItemIndex = 0; sceneryTabItemIndex < tabInfo.Entries.size(); sceneryTabItemIndex++) { - imageId = imageId.WithPrimary(gWindowSceneryPrimaryColour); - if (wallEntry->flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) + const auto& currentSceneryGlobal = tabInfo.Entries[sceneryTabItemIndex]; + const auto tabSelectedScenery = GetSelectedScenery(tabIndex); + if (gWindowSceneryPaintEnabled == 1 || gWindowSceneryEyedropperEnabled) { - imageId = imageId.WithSecondary(gWindowScenerySecondaryColour); - if (wallEntry->flags & WALL_SCENERY_HAS_TERNARY_COLOUR) + if (_selectedScenery == currentSceneryGlobal) { - imageId = imageId.WithTertiary(gWindowSceneryTertiaryColour); + gfx_fill_rect_inset( + &dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, + colours[1], INSET_RECT_FLAG_FILL_MID_LIGHT); } } - gfx_draw_sprite(dpi, imageId, { 47, spriteTop }); - - if (wallEntry->flags & WALL_SCENERY_IS_DOOR) + else { - gfx_draw_sprite(dpi, imageId.WithIndexOffset(1), { 47, spriteTop }); + if (tabSelectedScenery == currentSceneryGlobal) + { + gfx_fill_rect_inset( + &dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, + colours[1], (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_MID_LIGHT)); + } + else if (_selectedScenery == currentSceneryGlobal) + { + gfx_fill_rect_inset( + &dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, + colours[1], INSET_RECT_FLAG_FILL_MID_LIGHT); + } + } + + rct_drawpixelinfo clipdpi; + if (clip_drawpixelinfo( + &clipdpi, &dpi, topLeft + ScreenCoordsXY{ 1, 1 }, SCENERY_BUTTON_WIDTH - 2, SCENERY_BUTTON_HEIGHT - 2)) + { + DrawSceneryItem(clipdpi, currentSceneryGlobal); + } + + topLeft.x += SCENERY_BUTTON_WIDTH; + if (topLeft.x >= numColumns * SCENERY_BUTTON_WIDTH) + { + topLeft.y += SCENERY_BUTTON_HEIGHT; + topLeft.x = 0; } } } - else if (scenerySelection.SceneryType == SCENERY_TYPE_PATH_ITEM) - { - auto* pathBitEntry = get_footpath_item_entry(scenerySelection.EntryIndex); - auto imageId = ImageId(pathBitEntry->image); - gfx_draw_sprite(dpi, imageId, { 11, 16 }); - } - else - { - auto sceneryEntry = get_small_scenery_entry(scenerySelection.EntryIndex); - auto imageId = ImageId(sceneryEntry->image + gWindowSceneryRotation); - if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR)) - { - imageId = imageId.WithPrimary(gWindowSceneryPrimaryColour); - if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)) - { - imageId = imageId.WithSecondary(gWindowScenerySecondaryColour); - } - } +}; - auto spriteTop = (sceneryEntry->height / 4) + 43; - if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_FULL_TILE) && sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_VOFFSET_CENTRE)) - { - spriteTop -= 12; - } - - gfx_draw_sprite(dpi, imageId, { 32, spriteTop }); - - if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_HAS_GLASS)) - { - imageId = ImageId(sceneryEntry->image + 4 + gWindowSceneryRotation).WithTransparancy(gWindowSceneryPrimaryColour); - gfx_draw_sprite(dpi, imageId, { 32, spriteTop }); - } - - if (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_ANIMATED_FG)) - { - imageId = ImageId(sceneryEntry->image + 4 + gWindowSceneryRotation); - gfx_draw_sprite(dpi, imageId, { 32, spriteTop }); - } - } +rct_window* WindowSceneryOpen() +{ + return WindowFocusOrCreate( + WC_SCENERY, ScreenCoordsXY(context_get_width() - WINDOW_SCENERY_WIDTH, 0x1D), WINDOW_SCENERY_WIDTH, + WINDOW_SCENERY_HEIGHT, WF_NO_SCROLLING); } -static void WindowSceneryContentScrollPaint(rct_window* w, rct_drawpixelinfo* dpi) +void WindowScenerySetSelectedItem( + const ScenerySelection& scenery, const std::optional primary, const std::optional secondary, + const std::optional tertiary, const std::optional rotation) { - gfx_clear(dpi, ColourMapA[w->colours[1]].mid_light); - - auto numColumns = WindowSceneryGetNumColumns(w); - auto tabIndex = gWindowSceneryActiveTabIndex; - if (tabIndex >= _tabEntries.size()) - { - return; - } - - ScreenCoordsXY topLeft{ 0, 0 }; - - const auto& tabInfo = _tabEntries[tabIndex]; - for (size_t sceneryTabItemIndex = 0; sceneryTabItemIndex < tabInfo.Entries.size(); sceneryTabItemIndex++) - { - const auto& currentSceneryGlobal = tabInfo.Entries[sceneryTabItemIndex]; - const auto tabSelectedScenery = GetSelectedScenery(tabIndex); - if (gWindowSceneryPaintEnabled == 1 || gWindowSceneryEyedropperEnabled) - { - if (_selectedScenery == currentSceneryGlobal) - { - gfx_fill_rect_inset( - dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, - w->colours[1], INSET_RECT_FLAG_FILL_MID_LIGHT); - } - } - else - { - if (tabSelectedScenery == currentSceneryGlobal) - { - gfx_fill_rect_inset( - dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, - w->colours[1], (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_MID_LIGHT)); - } - else if (_selectedScenery == currentSceneryGlobal) - { - gfx_fill_rect_inset( - dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, - w->colours[1], INSET_RECT_FLAG_FILL_MID_LIGHT); - } - } - - rct_drawpixelinfo clipdpi; - if (clip_drawpixelinfo( - &clipdpi, dpi, topLeft + ScreenCoordsXY{ 1, 1 }, SCENERY_BUTTON_WIDTH - 2, SCENERY_BUTTON_HEIGHT - 2)) - { - WindowSceneryScrollpaintItem(w, &clipdpi, currentSceneryGlobal); - } - - topLeft.x += SCENERY_BUTTON_WIDTH; - if (topLeft.x >= numColumns * SCENERY_BUTTON_WIDTH) - { - topLeft.y += SCENERY_BUTTON_HEIGHT; - topLeft.x = 0; - } - } -} - -void WindowSceneryScrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex) -{ - if (scrollIndex == SceneryContentScrollIndex) - { - WindowSceneryContentScrollPaint(w, dpi); - } -} - -bool WindowScenerySetSelectedItem(const ScenerySelection& scenery) -{ - bool result = false; - rct_window* w = window_bring_to_front_by_class(WC_SCENERY); + auto* w = static_cast(window_bring_to_front_by_class(WC_SCENERY)); if (w != nullptr) { - auto tabIndex = WindowSceneryFindTabWithScenery(scenery); - if (tabIndex) - { - gWindowSceneryActiveTabIndex = *tabIndex; - SetSelectedScenery(*tabIndex, scenery); - - OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, context_get_width() / 2); - _hoverCounter = -16; - gSceneryPlaceCost = MONEY32_UNDEFINED; - w->Invalidate(); - result = true; - } + w->SetSelectedItem(scenery, primary, secondary, tertiary, rotation); } - return result; } void WindowScenerySetSelectedTab(const ObjectEntryIndex sceneryGroupIndex) { - const auto* tabInfo = GetSceneryTabInfoForGroup(sceneryGroupIndex); - if (tabInfo == nullptr) + // Should this bring to front? + auto* w = static_cast(window_find_by_class(WC_SCENERY)); + if (w != nullptr) { - tabInfo = &_tabEntries.back(); - } - const auto tabId = std::distance(&*_tabEntries.cbegin(), tabInfo); - auto* window = window_find_by_class(WC_SCENERY); - if (window != nullptr) - { - window_event_mouse_down_call(window, WIDX_SCENERY_TAB_1 + tabId); + return w->SetSelectedTab(sceneryGroupIndex); } } // Used after removing objects, in order to avoid crashes. void WindowSceneryResetSelectedSceneryItems() { - gWindowSceneryTabSelections.clear(); + auto* w = static_cast(window_find_by_class(WC_SCENERY)); + if (w != nullptr) + { + w->ResetSelectedSceneryItems(); + } +} + +void WindowScenerySetDefaultPlacementConfiguration() +{ + auto* w = static_cast(window_find_by_class(WC_SCENERY)); + if (w != nullptr) + { + w->SetDefaultPlacementConfiguration(); + } +} + +void WindowSceneryInit() +{ + auto* w = static_cast(window_find_by_class(WC_SCENERY)); + if (w != nullptr) + { + w->Init(); + } } diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 650aa20f1e..52e71f0852 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -1103,13 +1103,10 @@ static void SceneryEyedropperToolDown(const ScreenCoordsXY& windowPos, rct_widge auto* sceneryEntry = get_small_scenery_entry(entryIndex); if (sceneryEntry != nullptr) { - if (WindowScenerySetSelectedItem({ SCENERY_TYPE_SMALL, entryIndex })) - { - gWindowSceneryRotation = sceneryElement->GetDirectionWithOffset(get_current_rotation()); - gWindowSceneryPrimaryColour = sceneryElement->GetPrimaryColour(); - gWindowScenerySecondaryColour = sceneryElement->GetSecondaryColour(); - gWindowSceneryEyedropperEnabled = false; - } + WindowScenerySetSelectedItem( + { SCENERY_TYPE_SMALL, entryIndex }, sceneryElement->GetPrimaryColour(), + sceneryElement->GetSecondaryColour(), std::nullopt, + sceneryElement->GetDirectionWithOffset(get_current_rotation())); } break; } @@ -1119,13 +1116,9 @@ static void SceneryEyedropperToolDown(const ScreenCoordsXY& windowPos, rct_widge auto* sceneryEntry = get_wall_entry(entryIndex); if (sceneryEntry != nullptr) { - if (WindowScenerySetSelectedItem({ SCENERY_TYPE_WALL, entryIndex })) - { - gWindowSceneryPrimaryColour = info.Element->AsWall()->GetPrimaryColour(); - gWindowScenerySecondaryColour = info.Element->AsWall()->GetSecondaryColour(); - gWindowSceneryTertiaryColour = info.Element->AsWall()->GetTertiaryColour(); - gWindowSceneryEyedropperEnabled = false; - } + WindowScenerySetSelectedItem( + { SCENERY_TYPE_WALL, entryIndex }, info.Element->AsWall()->GetPrimaryColour(), + info.Element->AsWall()->GetSecondaryColour(), info.Element->AsWall()->GetTertiaryColour(), std::nullopt); } break; } @@ -1135,13 +1128,10 @@ static void SceneryEyedropperToolDown(const ScreenCoordsXY& windowPos, rct_widge auto* sceneryEntry = get_large_scenery_entry(entryIndex); if (sceneryEntry != nullptr) { - if (WindowScenerySetSelectedItem({ SCENERY_TYPE_LARGE, entryIndex })) - { - gWindowSceneryRotation = (get_current_rotation() + info.Element->GetDirection()) & 3; - gWindowSceneryPrimaryColour = info.Element->AsLargeScenery()->GetPrimaryColour(); - gWindowScenerySecondaryColour = info.Element->AsLargeScenery()->GetSecondaryColour(); - gWindowSceneryEyedropperEnabled = false; - } + WindowScenerySetSelectedItem( + { SCENERY_TYPE_LARGE, entryIndex }, info.Element->AsLargeScenery()->GetPrimaryColour(), + info.Element->AsLargeScenery()->GetSecondaryColour(), std::nullopt, + (get_current_rotation() + info.Element->GetDirection()) & 3); } break; } @@ -1153,10 +1143,8 @@ static void SceneryEyedropperToolDown(const ScreenCoordsXY& windowPos, rct_widge auto sceneryEntry = get_banner_entry(banner->type); if (sceneryEntry != nullptr) { - if (WindowScenerySetSelectedItem({ SCENERY_TYPE_BANNER, banner->type })) - { - gWindowSceneryEyedropperEnabled = false; - } + WindowScenerySetSelectedItem( + { SCENERY_TYPE_BANNER, banner->type }, std::nullopt, std::nullopt, std::nullopt, std::nullopt); } } break; @@ -1167,10 +1155,8 @@ static void SceneryEyedropperToolDown(const ScreenCoordsXY& windowPos, rct_widge auto* pathBitEntry = get_footpath_item_entry(entryIndex); if (pathBitEntry != nullptr) { - if (WindowScenerySetSelectedItem({ SCENERY_TYPE_PATH_ITEM, entryIndex })) - { - gWindowSceneryEyedropperEnabled = false; - } + WindowScenerySetSelectedItem( + { SCENERY_TYPE_PATH_ITEM, entryIndex }, std::nullopt, std::nullopt, std::nullopt, std::nullopt); } break; } diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 890e682aaf..362e914a10 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -175,7 +175,9 @@ bool ClearSceneryToolIsActive(); bool WaterToolIsActive(); rct_window* WindowSceneryOpen(); -bool WindowScenerySetSelectedItem(const ScenerySelection& scenery); +void WindowScenerySetSelectedItem( + const ScenerySelection& sceneryconst, std::optional primary, const std::optional secondary, + const std::optional tertiary, const std::optional rotation); void WindowScenerySetSelectedTab(const ObjectEntryIndex sceneryGroupIndex); void WindowScenerySetDefaultPlacementConfiguration(); void WindowSceneryInit();