From 90ab449f78fb7ae131e73c11515b0b85470e649b Mon Sep 17 00:00:00 2001 From: Hielke Morsink Date: Sat, 9 Apr 2022 00:49:12 +0200 Subject: [PATCH 1/3] Fix #16050: Scenery window positioning This supersedes #16095 The position and size arguments of WindowCreate are now optional - not a window doesn't have to know the size beforehand. This removes the WF_NO_SCROLLING flag from the call to WindowCreate, but that seems to have no use for the scenery window anyway. Co-authored-by: Ian-Polito --- src/openrct2-ui/windows/Scenery.cpp | 57 +++++++++++++++++------------ src/openrct2/interface/Window.h | 2 +- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index 1607b4255d..7e1a558fde 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -28,10 +28,11 @@ #include static constexpr const rct_string_id WINDOW_TITLE = STR_NONE; -constexpr int32_t WINDOW_SCENERY_WIDTH = 634; -constexpr int32_t WINDOW_SCENERY_HEIGHT = 180; +constexpr int32_t WINDOW_SCENERY_MIN_WIDTH = 634; +constexpr int32_t WINDOW_SCENERY_MIN_HEIGHT = 180; constexpr int32_t SCENERY_BUTTON_WIDTH = 66; constexpr int32_t SCENERY_BUTTON_HEIGHT = 80; +constexpr int32_t SceneryTabWidth = 31; constexpr uint8_t SceneryContentScrollIndex = 0; @@ -58,7 +59,7 @@ 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), + WINDOW_SHIM(WINDOW_TITLE, WINDOW_SCENERY_MIN_WIDTH, WINDOW_SCENERY_MIN_HEIGHT), MakeWidget ({ 0, 43}, {634, 99}, WindowWidgetType::Resize, WindowColour::Secondary ), // 8 0x009DE2C8 MakeWidget ({ 2, 47}, {607, 80}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // 1000000 0x009DE418 MakeWidget ({609, 44}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_ROTATE_ARROW, STR_ROTATE_OBJECTS_90 ), // 2000000 0x009DE428 @@ -122,6 +123,7 @@ private: std::vector _tabEntries; std::vector _widgets; + int32_t _requiredWidth; ScenerySelection _selectedScenery; int16_t _hoverCounter; @@ -145,10 +147,12 @@ public: 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; + width = GetRequiredWidth(); + min_width = width; + max_width = width; + height = WINDOW_SCENERY_MIN_HEIGHT; + min_height = height; + max_height = height; } void OnClose() override @@ -345,10 +349,8 @@ public: { 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; + min_height = WINDOW_SCENERY_MIN_HEIGHT; + max_height = WINDOW_SCENERY_MIN_HEIGHT; } } else @@ -359,10 +361,8 @@ public: 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); + const auto windowHeight = std::clamp(maxWindowHeight, WINDOW_SCENERY_MIN_HEIGHT, 463); - min_width = WINDOW_SCENERY_WIDTH; - max_width = WINDOW_SCENERY_WIDTH; min_height = windowHeight; max_height = windowHeight; } @@ -374,10 +374,8 @@ public: _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; + min_height = WINDOW_SCENERY_MIN_HEIGHT; + max_height = WINDOW_SCENERY_MIN_HEIGHT; } } @@ -615,8 +613,6 @@ public: 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; @@ -825,11 +821,19 @@ public: _tabEntries.pop_back(); } + // Set required width + _requiredWidth = static_cast(_tabEntries.size()) * SceneryTabWidth + 5; + SortTabs(); PrepareWidgets(); window_invalidate_by_class(WC_SCENERY); } + int32_t GetRequiredWidth() const + { + return std::max(_requiredWidth, WINDOW_SCENERY_MIN_WIDTH); + } + private: int32_t GetNumColumns() const { @@ -1343,9 +1347,16 @@ private: rct_window* WindowSceneryOpen() { - return WindowFocusOrCreate( - WC_SCENERY, ScreenCoordsXY(context_get_width() - WINDOW_SCENERY_WIDTH, 0x1D), WINDOW_SCENERY_WIDTH, - WINDOW_SCENERY_HEIGHT, WF_NO_SCROLLING); + auto* w = static_cast(window_bring_to_front_by_class(WC_SCENERY)); + if (w == nullptr) + { + w = WindowCreate(WC_SCENERY); + + // Now the window is initialized, we know the width that it requires. Move it to the top-right edge + window_move_position(w, { context_get_width() - w->GetRequiredWidth(), 0x1D }); + window_push_others_below(w); + } + return w; } void WindowScenerySetSelectedItem( diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 1723e87b91..17a355b77d 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -675,7 +675,7 @@ rct_window* window_bring_to_front_by_number(rct_windowclass cls, rct_windownumbe rct_window* WindowCreate( std::unique_ptr&& w, rct_windowclass cls, ScreenCoordsXY pos, int32_t width, int32_t height, uint32_t flags); template::value>::type* = nullptr> -T* WindowCreate(rct_windowclass cls, const ScreenCoordsXY& pos, int32_t width, int32_t height, uint32_t flags = 0) +T* WindowCreate(rct_windowclass cls, const ScreenCoordsXY& pos = {}, int32_t width = 0, int32_t height = 0, uint32_t flags = 0) { return static_cast(WindowCreate(std::make_unique(), cls, pos, width, height, flags)); } From c995abc25ecff93c8b70d96683e8c9389c40f117 Mon Sep 17 00:00:00 2001 From: Hielke Morsink Date: Sat, 9 Apr 2022 17:42:17 +0200 Subject: [PATCH 2/3] Fix: Crash on opening scenery window after removing tabs The crash occurred because gWindowSceneryTabSelections did not get cleared when the window is not open, yet this is a global variable that needs clearing. The function that handles this (WindowSceneryResetSelectedSceneryItems) gets called with the `INTENT_ACTION_REFRESH_SCENERY` intent. --- src/openrct2-ui/windows/Scenery.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index 7e1a558fde..87d1a8b84b 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -730,12 +730,6 @@ public: OnMouseDown(WIDX_SCENERY_TAB_1 + tabId); } - // Used after removing objects, in order to avoid crashes. - void ResetSelectedSceneryItems() - { - gWindowSceneryTabSelections.clear(); - } - void Init() { _tabEntries.clear(); @@ -1383,11 +1377,8 @@ void WindowScenerySetSelectedTab(const ObjectEntryIndex sceneryGroupIndex) // Used after removing objects, in order to avoid crashes. void WindowSceneryResetSelectedSceneryItems() { - auto* w = static_cast(window_find_by_class(WC_SCENERY)); - if (w != nullptr) - { - w->ResetSelectedSceneryItems(); - } + gWindowSceneryTabSelections.clear(); + gWindowSceneryActiveTabIndex = 0; } void WindowScenerySetDefaultPlacementConfiguration() @@ -1397,8 +1388,7 @@ void WindowScenerySetDefaultPlacementConfiguration() gWindowScenerySecondaryColour = COLOUR_YELLOW; gWindowSceneryTertiaryColour = COLOUR_DARK_BROWN; - gWindowSceneryTabSelections.clear(); - gWindowSceneryActiveTabIndex = 0; + WindowSceneryResetSelectedSceneryItems(); } void WindowSceneryInit() From 5f60dc4081686e2e57d8fe629b5788286370a73a Mon Sep 17 00:00:00 2001 From: Ian-Polito Date: Sat, 9 Apr 2022 17:50:17 +0200 Subject: [PATCH 3/3] Take the nice additional changes from #16095 --- src/openrct2-ui/windows/Scenery.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index 87d1a8b84b..7685054c02 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -32,7 +32,8 @@ constexpr int32_t WINDOW_SCENERY_MIN_WIDTH = 634; constexpr int32_t WINDOW_SCENERY_MIN_HEIGHT = 180; constexpr int32_t SCENERY_BUTTON_WIDTH = 66; constexpr int32_t SCENERY_BUTTON_HEIGHT = 80; -constexpr int32_t SceneryTabWidth = 31; +constexpr int32_t TabWidth = 31; +constexpr int32_t MaxTabs = 32; constexpr uint8_t SceneryContentScrollIndex = 0; @@ -734,8 +735,7 @@ public: { _tabEntries.clear(); - auto maxTabs = 32; - for (ObjectEntryIndex scenerySetIndex = 0; scenerySetIndex < maxTabs - 1; scenerySetIndex++) + for (ObjectEntryIndex scenerySetIndex = 0; scenerySetIndex < MaxTabs - 1; scenerySetIndex++) { const auto* sceneryGroupEntry = get_scenery_group_entry(scenerySetIndex); if (sceneryGroupEntry != nullptr && scenery_group_is_invented(scenerySetIndex)) @@ -816,7 +816,7 @@ public: } // Set required width - _requiredWidth = static_cast(_tabEntries.size()) * SceneryTabWidth + 5; + _requiredWidth = static_cast(_tabEntries.size()) * TabWidth + 5; SortTabs(); PrepareWidgets(); @@ -1024,7 +1024,7 @@ private: for (const auto& tabInfo : _tabEntries) { auto widget = MakeTab(pos, STR_STRING_DEFINED_TOOLTIP); - pos.x += 31; + pos.x += TabWidth; if (tabInfo.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) {