From a469b4f395dfd91ba581d02bf81efdd58e3de5b3 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 5 Apr 2021 18:43:12 +0100 Subject: [PATCH] Fix: Recalculate padding and minimum sizes when GUI or Font zoom is changed. (cherry picked from commit 4791ff28627eabe6322352428dc1b42344f545b9) --- src/gfx.cpp | 2 +- src/gfxinit.cpp | 2 +- src/network/network_client.cpp | 2 +- src/network/network_gui.cpp | 4 +- src/newgrf_gui.cpp | 2 +- src/osk_gui.cpp | 2 +- src/settings.cpp | 2 +- src/settings_gui.cpp | 7 +-- src/video/video_driver.cpp | 2 +- src/widget.cpp | 90 +++++++++++++++++++++++++++++----- src/widget_type.h | 33 +++++++++++-- src/widgets/dropdown.cpp | 2 +- src/window.cpp | 3 +- src/window_func.h | 6 ++- 14 files changed, 130 insertions(+), 29 deletions(-) diff --git a/src/gfx.cpp b/src/gfx.cpp index 0340901979..5a30964c3a 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1313,7 +1313,7 @@ void LoadStringWidthTable(bool monospace) } } - ReInitAllWindows(); + ReInitAllWindows(false); } /** diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 51fb77f791..43267b818b 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -369,7 +369,7 @@ void CheckBlitter() ClearFontCache(); GfxClearSpriteCache(); - ReInitAllWindows(); + ReInitAllWindows(false); } static void UpdateRouteStepSpriteSize() diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index fe237e0f77..6f1aa637b8 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -1326,7 +1326,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SETTINGS_ACCESS _network_settings_access = p->Recv_bool(); DeleteWindowById(WC_CHEATS, 0); - ReInitAllWindows(); + ReInitAllWindows(false); return NETWORK_RECV_STATUS_OKAY; } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 8162f1e474..844326775b 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -100,7 +100,9 @@ public: this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP)); leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP); - leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK).width + GetSpriteSize(SPR_BLOT).width + GetSpriteSize(SPR_FLAGS_BASE).width, 12); + leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK, nullptr, ZOOM_LVL_OUT_4X).width + + GetSpriteSize(SPR_BLOT, nullptr, ZOOM_LVL_OUT_4X).width + + GetSpriteSize(SPR_FLAGS_BASE, nullptr, ZOOM_LVL_OUT_4X).width, 12); leaf->SetFill(0, 1); this->Add(leaf); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index ef416b0b7d..3ccc470de9 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1993,7 +1993,7 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed) w->InvalidateData(); - ReInitAllWindows(); + ReInitAllWindows(false); DeleteWindowByClass(WC_BUILD_OBJECT); } } diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index 9229e7dcf7..b5ddeede5f 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -237,7 +237,7 @@ static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType hor->Add(spc); } NWidgetLeaf *leaf = new NWidgetLeaf(widtype, COLOUR_GREY, widnum, widdata, STR_NULL); - leaf->SetMinimalSize(ScaleGUITrad(key_width), height); + leaf->SetMinimalSizeAbsolute(ScaleGUITrad(key_width), height); hor->Add(leaf); } diff --git a/src/settings.cpp b/src/settings.cpp index c01f5697b7..79ec02f4ae 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1357,7 +1357,7 @@ static bool InvalidateNewGRFChangeWindows(int32 p1) { InvalidateWindowClassesData(WC_SAVELOAD); DeleteWindowByClass(WC_GAME_OPTIONS); - ReInitAllWindows(); + ReInitAllWindows(_gui_zoom_cfg); return true; } diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index efcecd824e..482a87747d 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -533,7 +533,7 @@ struct GameOptionsWindow : Window { case WID_GO_CURRENCY_DROPDOWN: // Currency if (index == CURRENCY_CUSTOM) ShowCustCurrency(); this->opt->locale.currency = index; - ReInitAllWindows(); + ReInitAllWindows(false); break; case WID_GO_AUTOSAVE_DROPDOWN: // Autosave options @@ -548,7 +548,7 @@ struct GameOptionsWindow : Window { ClearAllCachedNames(); UpdateAllVirtCoords(); CheckBlitter(); - ReInitAllWindows(); + ReInitAllWindows(false); FlushDeparturesWindowTextCaches(); break; @@ -577,7 +577,7 @@ struct GameOptionsWindow : Window { UpdateCursorSize(); UpdateAllVirtCoords(); FixTitleGameZoom(); - ReInitAllWindows(); + ReInitAllWindows(true); FlushDeparturesWindowTextCaches(); } break; @@ -592,6 +592,7 @@ struct GameOptionsWindow : Window { ClearFontCache(); LoadStringWidthTable(); UpdateAllVirtCoords(); + ReInitAllWindows(true); FlushDeparturesWindowTextCaches(); } break; diff --git a/src/video/video_driver.cpp b/src/video/video_driver.cpp index c0572d010f..251c86122f 100644 --- a/src/video/video_driver.cpp +++ b/src/video/video_driver.cpp @@ -130,7 +130,7 @@ void VideoDriver::RealChangeBlitter(const char *repl_blitter) this->ClearSystemSprites(); ClearFontCache(); GfxClearSpriteCache(); - ReInitAllWindows(); + ReInitAllWindows(false); } void VideoDriver::Tick() diff --git a/src/widget.cpp b/src/widget.cpp index 6d18562652..6bc04ae01a 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -821,6 +821,14 @@ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) return (this->type == tp) ? this : nullptr; } +void NWidgetBase::AdjustPaddingForZoom() +{ + this->padding_top = ScaleGUITrad(this->uz_padding_top); + this->padding_right = ScaleGUITrad(this->uz_padding_right); + this->padding_bottom = ScaleGUITrad(this->uz_padding_bottom); + this->padding_left = ScaleGUITrad(this->uz_padding_left); +} + /** * Constructor for resizable nested widgets. * @param tp Nested widget type. @@ -833,6 +841,15 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : this->fill_y = fill_y; } +void NWidgetResizeBase::AdjustPaddingForZoom() +{ + if (!this->absolute) { + this->min_x = ScaleGUITrad(this->uz_min_x); + this->min_y = std::max(ScaleGUITrad(this->uz_min_y), this->uz_text_lines * GetCharacterHeight(this->uz_text_size) + ScaleGUITrad(this->uz_text_spacing)); + } + NWidgetBase::AdjustPaddingForZoom(); +} + /** * Set minimal size of the widget. * @param min_x Horizontal minimal size of the widget. @@ -840,6 +857,20 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : */ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) { + this->uz_min_x = std::max(this->uz_min_x, min_x); + this->uz_min_y = std::max(this->uz_min_y, min_y); + this->min_x = ScaleGUITrad(this->uz_min_x); + this->min_y = std::max(ScaleGUITrad(this->uz_min_y), this->uz_text_lines * GetCharacterHeight(this->uz_text_size) + ScaleGUITrad(this->uz_text_spacing)); +} + +/** + * Set absolute (post-scaling) minimal size of the widget. + * @param min_x Horizontal minimal size of the widget. + * @param min_y Vertical minimal size of the widget. + */ +void NWidgetResizeBase::SetMinimalSizeAbsolute(uint min_x, uint min_y) +{ + this->absolute = true; this->min_x = std::max(this->min_x, min_x); this->min_y = std::max(this->min_y, min_y); } @@ -852,7 +883,10 @@ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) */ void NWidgetResizeBase::SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size) { - this->min_y = min_lines * GetCharacterHeight(size) + spacing; + this->uz_text_lines = min_lines; + this->uz_text_spacing = spacing; + this->uz_text_size = size; + this->min_y = std::max(ScaleGUITrad(this->uz_min_y), this->uz_text_lines * GetCharacterHeight(this->uz_text_size) + ScaleGUITrad(this->uz_text_spacing)); } /** @@ -995,6 +1029,14 @@ NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) return nullptr; } +void NWidgetContainer::AdjustPaddingForZoom() +{ + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + child_wid->AdjustPaddingForZoom(); + } + NWidgetBase::AdjustPaddingForZoom(); +} + /** * Append widget \a wid to container. * @param wid Widget to append. @@ -1036,6 +1078,14 @@ void NWidgetStacked::SetIndex(int index) this->index = index; } +void NWidgetStacked::AdjustPaddingForZoom() +{ + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + child_wid->AdjustPaddingForZoom(); + } + NWidgetContainer::AdjustPaddingForZoom(); +} + void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array) { if (this->index >= 0 && init_array) { // Fill w->nested_array[] @@ -1166,6 +1216,14 @@ NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags this->flags = flags; } +void NWidgetPIPContainer::AdjustPaddingForZoom() +{ + this->pip_pre = ScaleGUITrad(this->uz_pip_pre); + this->pip_inter = ScaleGUITrad(this->uz_pip_inter); + this->pip_post = ScaleGUITrad(this->uz_pip_post); + NWidgetContainer::AdjustPaddingForZoom(); +} + /** * Set additional pre/inter/post space for the container. * @@ -1177,9 +1235,13 @@ NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags */ void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) { - this->pip_pre = pip_pre; - this->pip_inter = pip_inter; - this->pip_post = pip_post; + this->uz_pip_pre = pip_pre; + this->uz_pip_inter = pip_inter; + this->uz_pip_post = pip_post; + + this->pip_pre = ScaleGUITrad(this->uz_pip_pre); + this->pip_inter = ScaleGUITrad(this->uz_pip_inter); + this->pip_post = ScaleGUITrad(this->uz_pip_post); } void NWidgetPIPContainer::Draw(const Window *w) @@ -1862,6 +1924,12 @@ void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) this->child->SetPIP(pip_pre, pip_inter, pip_post); } +void NWidgetBackground::AdjustPaddingForZoom() +{ + if (child != nullptr) child->AdjustPaddingForZoom(); + NWidgetCore::AdjustPaddingForZoom(); +} + void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) { if (init_array && this->index >= 0) { @@ -2203,11 +2271,11 @@ void NWidgetScrollbar::SetupSmallestSize(Window *w, bool init_array) switch (this->type) { case NWID_HSCROLLBAR: - this->SetMinimalSize(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height); + this->SetMinimalSizeAbsolute(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height); break; case NWID_VSCROLLBAR: - this->SetMinimalSize(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3); + this->SetMinimalSizeAbsolute(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3); break; default: NOT_REACHED(); @@ -2840,7 +2908,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != nullptr) { assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); - nwrb->SetMinimalSize(ScaleGUITrad(parts->u.xy.x), ScaleGUITrad(parts->u.xy.y)); + nwrb->SetMinimalSize(parts->u.xy.x, parts->u.xy.y); } break; } @@ -2886,15 +2954,15 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, } case WPT_PADDING: - if (*dest != nullptr) (*dest)->SetPadding(ScaleGUITrad(parts->u.padding.top), ScaleGUITrad(parts->u.padding.right), ScaleGUITrad(parts->u.padding.bottom), ScaleGUITrad(parts->u.padding.left)); + if (*dest != nullptr) (*dest)->SetPadding(parts->u.padding.top, parts->u.padding.right, parts->u.padding.bottom, parts->u.padding.left); break; case WPT_PIPSPACE: { NWidgetPIPContainer *nwc = dynamic_cast(*dest); - if (nwc != nullptr) nwc->SetPIP(ScaleGUITrad(parts->u.pip.pre), ScaleGUITrad(parts->u.pip.inter), ScaleGUITrad(parts->u.pip.post)); + if (nwc != nullptr) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); NWidgetBackground *nwb = dynamic_cast(*dest); - if (nwb != nullptr) nwb->SetPIP(ScaleGUITrad(parts->u.pip.pre), ScaleGUITrad(parts->u.pip.inter), ScaleGUITrad(parts->u.pip.post)); + if (nwb != nullptr) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); break; } @@ -3091,7 +3159,7 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid NWidgetHorizontal *hor = nullptr; // Storage for buttons in one row. int hor_length = 0; - Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); + Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON, nullptr, ZOOM_LVL_OUT_4X); sprite_size.width += WD_MATRIX_LEFT + WD_MATRIX_RIGHT; sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1; // 1 for the 'offset' of being pressed diff --git a/src/widget_type.h b/src/widget_type.h index dfbc5029c8..db93bc98d5 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -138,6 +138,7 @@ class NWidgetBase : public ZeroedMemoryAllocator { public: NWidgetBase(WidgetType tp); + virtual void AdjustPaddingForZoom(); virtual void SetupSmallestSize(Window *w, bool init_array) = 0; virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) = 0; @@ -159,10 +160,11 @@ public: */ inline void SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left) { - this->padding_top = top; - this->padding_right = right; - this->padding_bottom = bottom; - this->padding_left = left; + this->uz_padding_top = top; + this->uz_padding_right = right; + this->uz_padding_bottom = bottom; + this->uz_padding_left = left; + this->AdjustPaddingForZoom(); } inline uint GetHorizontalStepSize(SizingType sizing) const; @@ -208,6 +210,11 @@ public: uint8 padding_bottom; ///< Paddings added to the bottom of the widget. Managed by parent container widget. uint8 padding_left; ///< Paddings added to the left of the widget. Managed by parent container widget. (parent container may swap this with padding_right for RTL) + uint8 uz_padding_top; ///< Unscaled top padding, for resize calculation. + uint8 uz_padding_right; ///< Unscaled right padding, for resize calculation. + uint8 uz_padding_bottom; ///< Unscaled bottom padding, for resize calculation. + uint8 uz_padding_left; ///< Unscaled left padding, for resize calculation. + inline bool IsOutsideDrawArea() const { if ((int)(this->pos_x + this->current_x) <= _cur_dpi->left || (int)(this->pos_x) >= _cur_dpi->left + _cur_dpi->width) return true; @@ -266,7 +273,9 @@ class NWidgetResizeBase : public NWidgetBase { public: NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y); + void AdjustPaddingForZoom() override; void SetMinimalSize(uint min_x, uint min_y); + void SetMinimalSizeAbsolute(uint min_x, uint min_y); void SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size); void SetFill(uint fill_x, uint fill_y); void SetResize(uint resize_x, uint resize_y); @@ -275,6 +284,14 @@ public: uint min_x; ///< Minimal horizontal size of only this widget. uint min_y; ///< Minimal vertical size of only this widget. + + bool absolute; ///< Set if minimum size is fixed and should not be resized. + uint uz_min_x; ///< Unscaled Minimal horizontal size of only this widget. + uint uz_min_y; ///< Unscaled Minimal vertical size of only this widget. + + uint8 uz_text_lines; ///< 'Unscaled' text lines, stored for resize calculation. + uint8 uz_text_spacing; ///< 'Unscaled' text padding, stored for resize calculation. + FontSize uz_text_size; ///< 'Unscaled' font size, stored for resize calculation. }; /** Nested widget flags that affect display and interaction with 'real' widgets. */ @@ -406,6 +423,7 @@ public: NWidgetContainer(WidgetType tp); ~NWidgetContainer(); + void AdjustPaddingForZoom() override; void Add(NWidgetBase *wid); void FillNestedArray(NWidgetBase **array, uint length) override; @@ -444,6 +462,7 @@ public: void SetIndex(int index); + void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w, bool init_array) override; void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; void FillNestedArray(NWidgetBase **array, uint length) override; @@ -472,6 +491,7 @@ class NWidgetPIPContainer : public NWidgetContainer { public: NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags = NC_NONE); + void AdjustPaddingForZoom() override; void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); void Draw(const Window *w) override; @@ -483,6 +503,10 @@ protected: uint8 pip_pre; ///< Amount of space before first widget. uint8 pip_inter; ///< Amount of space between widgets. uint8 pip_post; ///< Amount of space after last widget. + + uint8 uz_pip_pre; ///< Unscaled space before first widget. + uint8 uz_pip_inter; ///< Unscaled space between widgets. + uint8 uz_pip_post; ///< Unscaled space after last widget. }; /** @@ -590,6 +614,7 @@ public: void Add(NWidgetBase *nwid); void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); + void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w, bool init_array) override; void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index a6d506b414..d0f5753af8 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -157,7 +157,7 @@ struct DropdownWindow : Window { uint items_width = size.width - (scroll ? NWidgetScrollbar::GetVerticalDimension().width : 0); NWidgetCore *nwi = this->GetWidget(WID_DM_ITEMS); - nwi->SetMinimalSize(items_width, size.height + 4); + nwi->SetMinimalSizeAbsolute(items_width, size.height + 4); nwi->colour = wi_colour; nwi = this->GetWidget(WID_DM_SCROLL); diff --git a/src/window.cpp b/src/window.cpp index f39c3e31a4..28b413eb89 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -3486,7 +3486,7 @@ void HideVitalWindows() } /** Re-initialize all windows. */ -void ReInitAllWindows() +void ReInitAllWindows(bool zoom_changed) { NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. NWidgetScrollbar::InvalidateDimensionCache(); @@ -3495,6 +3495,7 @@ void ReInitAllWindows() InitDepotWindowBlockSizes(); for (Window *w : Window::IterateFromBack()) { + if (zoom_changed) w->nested_root->AdjustPaddingForZoom(); w->ReInit(); } diff --git a/src/window_func.h b/src/window_func.h index e17f185cde..d63b4f6af2 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -43,7 +43,11 @@ void DeleteConstructionWindows(); void HideVitalWindows(); void ShowVitalWindows(); -void ReInitAllWindows(); +/** + * Re-initialize all windows. + * @param zoom_changed Set if windows are being re-initialized due to a zoom level changed. + */ +void ReInitAllWindows(bool zoom_changed); void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index); void SetWindowDirty(WindowClass cls, WindowNumber number);