diff --git a/binaries/data/mods/_test.gui/gui/settings/cguisize/getcomputedsize.js b/binaries/data/mods/_test.gui/gui/settings/cguisize/getcomputedsize.js new file mode 100644 index 0000000000..521d540b64 --- /dev/null +++ b/binaries/data/mods/_test.gui/gui/settings/cguisize/getcomputedsize.js @@ -0,0 +1 @@ +testObject.getComputedSize(); \ No newline at end of file diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 59e8f39d99..083434ffea 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -348,7 +348,6 @@ JSObject* CGUI::TickObjects(const ScriptRequest& rq, Script::StructuredClone ini sendingPromise = CallPageInit(rq, initData, hotloadData, scriptName); } - m_BaseObject->RecurseObject(&IGUIObject::IsHidden, &IGUIObject::DispatchDelayedSettingChanges); m_BaseObject->RecurseObject(&IGUIObject::IsHiddenOrGhostOrOutOfBoundaries, &IGUIObject::Tick); SendEventToAll(EventNameTick); m_Tooltip.Update(FindObjectUnderMouse(), m_MousePos, *this); @@ -387,7 +386,7 @@ void CGUI::DrawSprite(const CGUISpriteInstance& Sprite, CCanvas2D& canvas, const void CGUI::UpdateResolution() { - m_BaseObject->RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); + m_BaseObject->RecurseObject(nullptr, &IGUIObject::HandleSizeChanged); } std::unique_ptr CGUI::ConstructObject(const CStr& str) @@ -593,7 +592,7 @@ void CGUI::LoadXmlFile(const VfsPath& Filename, std::unordered_set& Pat void CGUI::LoadedXmlFiles() { - m_BaseObject->RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); + m_BaseObject->RecurseObject(nullptr, &IGUIObject::HandleSizeChanged); SGUIMessage msg(GUIM_LOAD); m_BaseObject->RecurseObject(nullptr, &IGUIObject::HandleMessage, msg); diff --git a/source/gui/CGUI.h b/source/gui/CGUI.h index cbf3ceaaf4..f442663309 100644 --- a/source/gui/CGUI.h +++ b/source/gui/CGUI.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -250,7 +250,7 @@ public: * * Needs no input since screen resolution is global. * - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ void UpdateResolution(); diff --git a/source/gui/CGUISetting.h b/source/gui/CGUISetting.h index a06815f6a5..1f0a6e559f 100644 --- a/source/gui/CGUISetting.h +++ b/source/gui/CGUISetting.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -54,18 +54,6 @@ public: */ virtual void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue value) = 0; - void DeferSettingChange() - { - delayNotification = true; - } - - void DispatchDelayedSettingChange() - { - if (!std::exchange(delayNotification, false)) - return; - - OnSettingChange(GetName(), true); - } protected: IGUISetting(IGUISetting&& other); IGUISetting& operator=(IGUISetting&& other) = delete; @@ -95,7 +83,6 @@ protected: */ IGUIObject& m_Object; - bool delayNotification{false}; private: CStr m_Name; }; diff --git a/source/gui/ObjectBases/IGUIObject.cpp b/source/gui/ObjectBases/IGUIObject.cpp index f2e9b61996..9651210c27 100644 --- a/source/gui/ObjectBases/IGUIObject.cpp +++ b/source/gui/ObjectBases/IGUIObject.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -137,8 +137,8 @@ void IGUIObject::SettingChanged(const CStr& Setting, const bool SendMessage) { if (Setting == "size") { - // If setting was "size", we need to re-cache itself and all children - RecurseObject(nullptr, &IGUIObject::UpdateCachedSize); + // Notify all children that they'll have to re-cache their actual size. + RecurseObject(nullptr, &IGUIObject::HandleSizeChanged); } else if (Setting == "hidden") { @@ -181,7 +181,7 @@ bool IGUIObject::IsMouseOver() const if (m_VisibleArea) return m_VisibleArea.PointInside(m_pGUI.GetMousePos()); - return m_CachedActualSize.PointInside(m_pGUI.GetMousePos()); + return GetActualSize().PointInside(m_pGUI.GetMousePos()); } void IGUIObject::UpdateMouseOver(IGUIObject* const& pMouseOver) @@ -241,13 +241,25 @@ void IGUIObject::ResetStates() UpdateMouseOver(nullptr); } -void IGUIObject::UpdateCachedSize() +void IGUIObject::HandleSizeChanged() +{ + m_CachedActualSizeDirty = true; +} + +const CRect& IGUIObject::GetActualSize() const +{ + if (std::exchange(m_CachedActualSizeDirty, false)) + RecalculateActualSize(); + + return m_CachedActualSize; +} + +void IGUIObject::RecalculateActualSize() const { // If absolute="false" and the object has got a parent, - // use its cached size instead of the screen. Notice - // it must have just been cached for it to work. + // use its cached size instead of the screen. if (!m_Absolute && m_pParent && !IsRootObject()) - m_CachedActualSize = m_Size->GetSize(m_pParent->m_CachedActualSize); + m_CachedActualSize = m_Size->GetSize(m_pParent->GetActualSize()); else m_CachedActualSize = m_Size->GetSize(CRect(m_pGUI.GetWindowSize())); @@ -271,14 +283,6 @@ void IGUIObject::UpdateCachedSize() } } -CRect IGUIObject::GetComputedSize() -{ - // Ensure the size is up to date before we use it. - m_Settings.at("size")->DispatchDelayedSettingChange(); - UpdateCachedSize(); - return m_CachedActualSize; -} - bool IGUIObject::ApplyStyle(const CStr& StyleName) { if (!m_pGUI.HasStyle(StyleName)) @@ -548,10 +552,10 @@ void IGUIObject::DrawInArea(CCanvas2D& canvas, CRect& area) { bool isInsideBoundaries = false; RecurseObject(nullptr, &IGUIObject::SetIsInsideBoundaries, isInsideBoundaries); - if (!area.IntersectWith(m_CachedActualSize)) + if (!area.IntersectWith(GetActualSize())) return; - CRect intersection = area.Intersection(m_CachedActualSize); + CRect intersection = area.Intersection(GetActualSize()); m_VisibleArea = intersection; @@ -564,9 +568,3 @@ void IGUIObject::DrawInArea(CCanvas2D& canvas, CRect& area) bool IGUIObject::IsHiddenOrGhostOrOutOfBoundaries() const { return !m_IsInsideBoundaries || IsHiddenOrGhost(); } - -void IGUIObject::DispatchDelayedSettingChanges() -{ - for (const auto& setting : m_Settings) - setting.second->DispatchDelayedSettingChange(); -} diff --git a/source/gui/ObjectBases/IGUIObject.h b/source/gui/ObjectBases/IGUIObject.h index 8c7169bc99..74a14ac170 100644 --- a/source/gui/ObjectBases/IGUIObject.h +++ b/source/gui/ObjectBases/IGUIObject.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -194,12 +194,13 @@ public: * is not wanted in real time, therefore it is cached, update * the cached size with this function. */ - virtual void UpdateCachedSize(); + virtual void HandleSizeChanged(); /** - * Updates and returns the size of the object. + * Get the size of the object. + * Besides m_Size it also depends on the parent's size, hence "actual". */ - virtual CRect GetComputedSize(); + virtual const CRect& GetActualSize() const; virtual const CStrW& GetTooltipText() const { return m_Tooltip; } virtual const CStr& GetTooltipStyle() const { return m_TooltipStyle; } @@ -277,8 +278,6 @@ public: virtual void DrawInArea(CCanvas2D& canvas, CRect& area); - virtual void DispatchDelayedSettingChanges(); - protected: /** * Draws the object. @@ -390,13 +389,6 @@ protected: */ virtual void AdditionalChildrenHandled() {} - /** - * Cached size, real size m_Size is actually dependent on resolution - * and can have different *real* outcomes, this is the real outcome - * cached to avoid slow calculations in real time. - */ - CRect m_CachedActualSize; - /** * Execute the script for a particular action. * Does nothing if no script has been registered for that action. @@ -428,6 +420,11 @@ protected: */ void UpdateMouseOver(IGUIObject* const& pMouseOver); + /** + * Recompute the actual (absolute) size from scratch again and cache it. + */ + virtual void RecalculateActualSize() const; + //@} private: //-------------------------------------------------------- @@ -518,6 +515,20 @@ protected: CRect m_VisibleArea; bool m_IsInsideBoundaries = true; + /** + * The actual size (usually) depends on the size of the parent. + * And to avoid recomputing all the time, it is cached here. + * Do not read from this directly, it is not guaranteed to be up-to-date, + * call GetActualSize() insead. + */ + mutable CRect m_CachedActualSize; + + /** + * Whether m_CacheActualSize is not up-to-date and will have to be recomputed + * when accessing it the next time. + */ + mutable bool m_CachedActualSizeDirty = true; + CGUISimpleSetting m_Enabled; CGUISimpleSetting m_Hidden; CGUISimpleSetting m_Size; diff --git a/source/gui/ObjectBases/IGUIPanel.cpp b/source/gui/ObjectBases/IGUIPanel.cpp index 65355e072a..7c8912ff2c 100644 --- a/source/gui/ObjectBases/IGUIPanel.cpp +++ b/source/gui/ObjectBases/IGUIPanel.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -38,23 +38,16 @@ IGUIPanel::~IGUIPanel() bool IGUIPanel::IsMouseOver() const { + GetActualSize(); // Updates m_CachedLayoutActualSize if necessary. return m_CachedLayoutActualSize.PointInside(m_pGUI.GetMousePos()); } -void IGUIPanel::UpdateCachedSize() +void IGUIPanel::RecalculateActualSize() const { - IGUIObject::UpdateCachedSize(); + IGUIObject::RecalculateActualSize(); m_CachedLayoutActualSize = m_CachedActualSize; } -CRect IGUIPanel::GetComputedSize() -{ - // Ensure the size is up to date before we use it. - m_Settings.at("size")->DispatchDelayedSettingChange(); - UpdateCachedSize(); - return m_CachedLayoutActualSize; -} - const std::vector& IGUIPanel::GetVisibleChildren() const { if (m_Drawing) diff --git a/source/gui/ObjectBases/IGUIPanel.h b/source/gui/ObjectBases/IGUIPanel.h index 30aa35993d..ea213f64fa 100644 --- a/source/gui/ObjectBases/IGUIPanel.h +++ b/source/gui/ObjectBases/IGUIPanel.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,15 +29,13 @@ public: IGUIPanel(CGUI& pGUI); virtual ~IGUIPanel(); - virtual void UpdateCachedSize(); - virtual CRect GetComputedSize(); - virtual bool IsMouseOver() const; virtual const std::vector& GetVisibleChildren() const; protected: - CRect m_CachedLayoutActualSize; + virtual void RecalculateActualSize() const; + mutable CRect m_CachedLayoutActualSize; bool m_Drawing = false; }; diff --git a/source/gui/ObjectBases/IGUIScrollBarOwner.h b/source/gui/ObjectBases/IGUIScrollBarOwner.h index adfae306df..23cf1e1d6f 100644 --- a/source/gui/ObjectBases/IGUIScrollBarOwner.h +++ b/source/gui/ObjectBases/IGUIScrollBarOwner.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -70,7 +70,7 @@ public: * Get Scroll Bar reference (it should be transparent it's actually * pointers). */ - virtual IGUIScrollBar& GetScrollBar(const int& index) + virtual IGUIScrollBar& GetScrollBar(const int& index) const { return *m_ScrollBars[index]; } diff --git a/source/gui/ObjectBases/IGUITextOwner.cpp b/source/gui/ObjectBases/IGUITextOwner.cpp index b5ca20b1d0..57907447a7 100644 --- a/source/gui/ObjectBases/IGUITextOwner.cpp +++ b/source/gui/ObjectBases/IGUITextOwner.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -79,7 +79,7 @@ void IGUITextOwner::HandleMessage(SGUIMessage& Message) } } -void IGUITextOwner::UpdateCachedSize() +void IGUITextOwner::HandleSizeChanged() { // update our text positions m_GeneratedTextsValid = false; @@ -103,7 +103,7 @@ void IGUITextOwner::DrawText(CCanvas2D& canvas, size_t index, const CGUIColor& c m_GeneratedTexts.at(index).Draw(m_pObject.GetGUI(), canvas, color, pos, clipping); } -void IGUITextOwner::CalculateTextPosition(CRect& ObjSize, CVector2D& TextPos, CGUIText& Text) +void IGUITextOwner::CalculateTextPosition(const CRect& ObjSize, CVector2D& TextPos, CGUIText& Text) { // The horizontal Alignment is now computed in GenerateText in order to not have to // loop through all of the TextCall objects again. diff --git a/source/gui/ObjectBases/IGUITextOwner.h b/source/gui/ObjectBases/IGUITextOwner.h index ad35aabd34..59b62aa6df 100644 --- a/source/gui/ObjectBases/IGUITextOwner.h +++ b/source/gui/ObjectBases/IGUITextOwner.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -75,9 +75,9 @@ public: virtual void HandleMessage(SGUIMessage& Message); /** - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ - virtual void UpdateCachedSize(); + virtual void HandleSizeChanged(); /** * Draws the Text. @@ -115,7 +115,7 @@ protected: /** * Calculate the position for the text, based on the alignment. */ - void CalculateTextPosition(CRect& ObjSize, CVector2D& TextPos, CGUIText& Text); + void CalculateTextPosition(const CRect& ObjSize, CVector2D& TextPos, CGUIText& Text); CGUISimpleSetting m_TextAlign; CGUISimpleSetting m_TextVAlign; diff --git a/source/gui/ObjectTypes/CButton.cpp b/source/gui/ObjectTypes/CButton.cpp index 1f0ac79b93..28c4fc1bb4 100644 --- a/source/gui/ObjectTypes/CButton.cpp +++ b/source/gui/ObjectTypes/CButton.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -53,8 +53,8 @@ void CButton::SetupText() { ENSURE(m_GeneratedTexts.size() == 1); - m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, m_CachedActualSize.GetWidth(), m_BufferZone, m_TextAlign, this); - CalculateTextPosition(m_CachedActualSize, m_TextPos, m_GeneratedTexts[0]); + m_GeneratedTexts[0] = CGUIText(m_pGUI, m_Caption, m_Font, GetActualSize().GetWidth(), m_BufferZone, m_TextAlign, this); + CalculateTextPosition(GetActualSize(), m_TextPos, m_GeneratedTexts[0]); } void CButton::ResetStates() @@ -63,10 +63,10 @@ void CButton::ResetStates() IGUIButtonBehavior::ResetStates(); } -void CButton::UpdateCachedSize() +void CButton::HandleSizeChanged() { - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); + IGUIObject::HandleSizeChanged(); + IGUITextOwner::HandleSizeChanged(); } CSize2D CButton::GetTextSize() @@ -92,7 +92,7 @@ void CButton::Draw(CCanvas2D& canvas) m_pGUI.DrawSprite( GetButtonSprite(m_Sprite, m_SpriteOver, m_SpritePressed, m_SpriteDisabled), canvas, - m_CachedActualSize, + GetActualSize(), m_VisibleArea); DrawText(canvas, 0, ChooseColor(), m_TextPos, m_VisibleArea); @@ -104,7 +104,7 @@ bool CButton::IsMouseOver() const return false; if (!m_MouseEventMask) return true; - return m_MouseEventMask.IsMouseOver(m_pGUI.GetMousePos(), m_CachedActualSize); + return m_MouseEventMask.IsMouseOver(m_pGUI.GetMousePos(), GetActualSize()); } const CGUIColor& CButton::ChooseColor() diff --git a/source/gui/ObjectTypes/CButton.h b/source/gui/ObjectTypes/CButton.h index efea1ddb1b..e27d6b27b4 100644 --- a/source/gui/ObjectTypes/CButton.h +++ b/source/gui/ObjectTypes/CButton.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -44,9 +44,9 @@ public: virtual void ResetStates(); /** - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ - virtual void UpdateCachedSize(); + virtual void HandleSizeChanged(); /** * @return the object text size. diff --git a/source/gui/ObjectTypes/CChart.cpp b/source/gui/ObjectTypes/CChart.cpp index 930e39db18..ee703cca7e 100644 --- a/source/gui/ObjectTypes/CChart.cpp +++ b/source/gui/ObjectTypes/CChart.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -53,10 +53,10 @@ CChart::CChart(CGUI& pGUI) { } -void CChart::UpdateCachedSize() +void CChart::HandleSizeChanged() { - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); + IGUIObject::HandleSizeChanged(); + IGUITextOwner::HandleSizeChanged(); } void CChart::HandleMessage(SGUIMessage& Message) @@ -72,11 +72,11 @@ void CChart::HandleMessage(SGUIMessage& Message) void CChart::DrawAxes(CCanvas2D& canvas) const { canvas.DrawRect(CRect( - m_CachedActualSize.TopLeft(), - m_CachedActualSize.BottomLeft() + CVector2D(m_AxisWidth, 0.0f)), m_AxisColor); + GetActualSize().TopLeft(), + GetActualSize().BottomLeft() + CVector2D(m_AxisWidth, 0.0f)), m_AxisColor); canvas.DrawRect(CRect( - m_CachedActualSize.BottomLeft() - CVector2D(0.0f, m_AxisWidth), - m_CachedActualSize.BottomRight()), m_AxisColor); + GetActualSize().BottomLeft() - CVector2D(0.0f, m_AxisWidth), + GetActualSize().BottomRight()), m_AxisColor); } void CChart::Draw(CCanvas2D& canvas) @@ -130,8 +130,8 @@ void CChart::Draw(CCanvas2D& canvas) CRect CChart::GetChartRect() const { return CRect( - m_CachedActualSize.TopLeft() + CVector2D(m_AxisWidth, m_AxisWidth), - m_CachedActualSize.BottomRight() - CVector2D(m_AxisWidth, m_AxisWidth) + GetActualSize().TopLeft() + CVector2D(m_AxisWidth, m_AxisWidth), + GetActualSize().BottomRight() - CVector2D(m_AxisWidth, m_AxisWidth) ); } diff --git a/source/gui/ObjectTypes/CChart.h b/source/gui/ObjectTypes/CChart.h index 9e3fc2000f..6a45c5792c 100644 --- a/source/gui/ObjectTypes/CChart.h +++ b/source/gui/ObjectTypes/CChart.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -58,9 +58,9 @@ public: protected: /** - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ - void UpdateCachedSize(); + void HandleSizeChanged(); /** * @see IGUIObject#HandleMessage() diff --git a/source/gui/ObjectTypes/CCheckBox.cpp b/source/gui/ObjectTypes/CCheckBox.cpp index 1a686c9d6e..9f47c667a9 100644 --- a/source/gui/ObjectTypes/CCheckBox.cpp +++ b/source/gui/ObjectTypes/CCheckBox.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -69,6 +69,6 @@ void CCheckBox::Draw(CCanvas2D& canvas) GetButtonSprite(m_SpriteChecked, m_SpriteCheckedOver, m_SpriteCheckedPressed, m_SpriteCheckedDisabled) : GetButtonSprite(m_SpriteUnchecked, m_SpriteUncheckedOver, m_SpriteUncheckedPressed, m_SpriteUncheckedDisabled), canvas, - m_CachedActualSize, + GetActualSize(), m_VisibleArea); } diff --git a/source/gui/ObjectTypes/CDropDown.cpp b/source/gui/ObjectTypes/CDropDown.cpp index b5764205bd..5a606621e1 100644 --- a/source/gui/ObjectTypes/CDropDown.cpp +++ b/source/gui/ObjectTypes/CDropDown.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -73,9 +73,9 @@ void CDropDown::SetupText() CList::SetupText(); } -void CDropDown::UpdateCachedSize() +void CDropDown::HandleSizeChanged() { - CList::UpdateCachedSize(); + CList::HandleSizeChanged(); SetupText(); } @@ -191,7 +191,7 @@ void CDropDown::HandleMessage(SGUIMessage& Message) const CVector2D& mouse = m_pGUI.GetMousePos(); // If the regular area is pressed, then abort, and close. - if (m_CachedActualSize.PointInside(mouse)) + if (GetActualSize().PointInside(mouse)) { m_Open = false; GetScrollBar(0).SetZ(GetBufferedZ()); @@ -370,51 +370,51 @@ void CDropDown::SetupListRect() if (m_ItemsYPositions.empty()) { - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, m_CachedActualSize.bottom + m_DropDownBuffer + m_DropDownSize); + m_CachedListRect = CRect(GetActualSize().left, GetActualSize().bottom + m_DropDownBuffer, + GetActualSize().right, GetActualSize().bottom + m_DropDownBuffer + m_DropDownSize); m_HideScrollBar = false; } // Too many items so use a scrollbar else if (m_ItemsYPositions.back() > m_DropDownSize) { // Place items below if at least some items can be placed below - if (m_CachedActualSize.bottom + m_DropDownBuffer + m_DropDownSize <= windowSize.Height) - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, m_CachedActualSize.bottom + m_DropDownBuffer + m_DropDownSize); - else if ((m_ItemsYPositions.size() > m_MinimumVisibleItems && windowSize.Height - m_CachedActualSize.bottom - m_DropDownBuffer >= m_ItemsYPositions[m_MinimumVisibleItems]) || - m_CachedActualSize.top < windowSize.Height - m_CachedActualSize.bottom) - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, windowSize.Height); + if (GetActualSize().bottom + m_DropDownBuffer + m_DropDownSize <= windowSize.Height) + m_CachedListRect = CRect(GetActualSize().left, GetActualSize().bottom + m_DropDownBuffer, + GetActualSize().right, GetActualSize().bottom + m_DropDownBuffer + m_DropDownSize); + else if ((m_ItemsYPositions.size() > m_MinimumVisibleItems && windowSize.Height - GetActualSize().bottom - m_DropDownBuffer >= m_ItemsYPositions[m_MinimumVisibleItems]) || + GetActualSize().top < windowSize.Height - GetActualSize().bottom) + m_CachedListRect = CRect(GetActualSize().left, GetActualSize().bottom + m_DropDownBuffer, + GetActualSize().right, windowSize.Height); // Not enough space below, thus place items above else - m_CachedListRect = CRect(m_CachedActualSize.left, std::max(0.f, m_CachedActualSize.top - m_DropDownBuffer - m_DropDownSize), - m_CachedActualSize.right, m_CachedActualSize.top - m_DropDownBuffer); + m_CachedListRect = CRect(GetActualSize().left, std::max(0.f, GetActualSize().top - m_DropDownBuffer - m_DropDownSize), + GetActualSize().right, GetActualSize().top - m_DropDownBuffer); m_HideScrollBar = false; } else { // Enough space below, no scrollbar needed - if (m_CachedActualSize.bottom + m_DropDownBuffer + m_ItemsYPositions.back() <= windowSize.Height) + if (GetActualSize().bottom + m_DropDownBuffer + m_ItemsYPositions.back() <= windowSize.Height) { - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, m_CachedActualSize.bottom + m_DropDownBuffer + m_ItemsYPositions.back()); + m_CachedListRect = CRect(GetActualSize().left, GetActualSize().bottom + m_DropDownBuffer, + GetActualSize().right, GetActualSize().bottom + m_DropDownBuffer + m_ItemsYPositions.back()); m_HideScrollBar = true; } // Enough space below for some items, but not all, so place items below and use a scrollbar - else if ((m_ItemsYPositions.size() > m_MinimumVisibleItems && windowSize.Height - m_CachedActualSize.bottom - m_DropDownBuffer >= m_ItemsYPositions[m_MinimumVisibleItems]) || - m_CachedActualSize.top < windowSize.Height - m_CachedActualSize.bottom) + else if ((m_ItemsYPositions.size() > m_MinimumVisibleItems && windowSize.Height - GetActualSize().bottom - m_DropDownBuffer >= m_ItemsYPositions[m_MinimumVisibleItems]) || + GetActualSize().top < windowSize.Height - GetActualSize().bottom) { - m_CachedListRect = CRect(m_CachedActualSize.left, m_CachedActualSize.bottom + m_DropDownBuffer, - m_CachedActualSize.right, windowSize.Height); + m_CachedListRect = CRect(GetActualSize().left, GetActualSize().bottom + m_DropDownBuffer, + GetActualSize().right, windowSize.Height); m_HideScrollBar = false; } // Not enough space below, thus place items above. Hide the scrollbar accordingly else { - m_CachedListRect = CRect(m_CachedActualSize.left, std::max(0.f, m_CachedActualSize.top - m_DropDownBuffer - m_ItemsYPositions.back()), - m_CachedActualSize.right, m_CachedActualSize.top - m_DropDownBuffer); - m_HideScrollBar = m_CachedActualSize.top > m_ItemsYPositions.back() + m_DropDownBuffer; + m_CachedListRect = CRect(GetActualSize().left, std::max(0.f, GetActualSize().top - m_DropDownBuffer - m_ItemsYPositions.back()), + GetActualSize().right, GetActualSize().top - m_DropDownBuffer); + m_HideScrollBar = GetActualSize().top > m_ItemsYPositions.back() + m_DropDownBuffer; } } } @@ -428,8 +428,8 @@ bool CDropDown::IsMouseOver() const { if (m_Open) { - CRect rect(m_CachedActualSize.left, std::min(m_CachedActualSize.top, GetListRect().top), - m_CachedActualSize.right, std::max(m_CachedActualSize.bottom, GetListRect().bottom)); + CRect rect(GetActualSize().left, std::min(GetActualSize().top, GetListRect().top), + GetActualSize().right, std::max(GetActualSize().bottom, GetListRect().bottom)); return rect.PointInside(m_pGUI.GetMousePos()); } else @@ -441,12 +441,12 @@ void CDropDown::Draw(CCanvas2D& canvas) const CGUISpriteInstance& sprite = m_Enabled ? m_Sprite : m_SpriteDisabled; const CGUISpriteInstance& spriteOverlay = m_Enabled ? m_SpriteOverlay : m_SpriteOverlayDisabled; - m_pGUI.DrawSprite(sprite, canvas, m_CachedActualSize, m_VisibleArea); + m_pGUI.DrawSprite(sprite, canvas, GetActualSize(), m_VisibleArea); if (m_ButtonWidth > 0.f) { - CRect rect(m_CachedActualSize.right - m_ButtonWidth, m_CachedActualSize.top, - m_CachedActualSize.right, m_CachedActualSize.bottom); + CRect rect(GetActualSize().right - m_ButtonWidth, GetActualSize().top, + GetActualSize().right, GetActualSize().bottom); if (!m_Enabled) { @@ -466,11 +466,11 @@ void CDropDown::Draw(CCanvas2D& canvas) if (m_Selected != -1) // TODO: Maybe check validity completely? { - CRect cliparea = m_VisibleArea != CRect() ? m_VisibleArea : m_CachedActualSize; - if (cliparea.right > m_CachedActualSize.right - m_ButtonWidth) - cliparea.right = m_CachedActualSize.right - m_ButtonWidth; + CRect cliparea = m_VisibleArea != CRect() ? m_VisibleArea : GetActualSize(); + if (cliparea.right > GetActualSize().right - m_ButtonWidth) + cliparea.right = GetActualSize().right - m_ButtonWidth; - CVector2D pos(m_CachedActualSize.left, m_CachedActualSize.top); + CVector2D pos(GetActualSize().left, GetActualSize().top); DrawText(canvas, m_Selected, m_Enabled ? m_TextColorSelected : m_TextColorDisabled, pos, cliparea); } @@ -488,7 +488,7 @@ void CDropDown::Draw(CCanvas2D& canvas) if (m_HideScrollBar) m_ScrollBar.Set(old, false); } - m_pGUI.DrawSprite(spriteOverlay, canvas, m_CachedActualSize, m_VisibleArea); + m_pGUI.DrawSprite(spriteOverlay, canvas, GetActualSize(), m_VisibleArea); } // When a dropdown list is opened, it needs to be visible above all the other diff --git a/source/gui/ObjectTypes/CDropDown.h b/source/gui/ObjectTypes/CDropDown.h index 8550686d9b..07c83a0100 100644 --- a/source/gui/ObjectTypes/CDropDown.h +++ b/source/gui/ObjectTypes/CDropDown.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -93,7 +93,7 @@ protected: * If the size changed, the texts have to be updated as * the word wrapping depends on the size. */ - virtual void UpdateCachedSize(); + virtual void HandleSizeChanged(); /** * Sets up text, should be called every time changes has been @@ -117,7 +117,7 @@ protected: bool m_Open; // I didn't cache this at first, but it's just as easy as caching - // m_CachedActualSize, so I thought, what the heck it's used a lot. + // GetActualSize(), so I thought, what the heck it's used a lot. CRect m_CachedListRect; // Hide scrollbar when it's not needed diff --git a/source/gui/ObjectTypes/CImage.cpp b/source/gui/ObjectTypes/CImage.cpp index f9466c3e7f..c2a5d1fd1a 100644 --- a/source/gui/ObjectTypes/CImage.cpp +++ b/source/gui/ObjectTypes/CImage.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,5 +30,5 @@ CImage::CImage(CGUI& pGUI) void CImage::Draw(CCanvas2D& canvas) { - m_pGUI.DrawSprite(m_Sprite, canvas, m_CachedActualSize, m_VisibleArea); + m_pGUI.DrawSprite(m_Sprite, canvas, GetActualSize(), m_VisibleArea); } diff --git a/source/gui/ObjectTypes/CInput.cpp b/source/gui/ObjectTypes/CInput.cpp index 5bbb8167e7..1a7bf3bd37 100644 --- a/source/gui/ObjectTypes/CInput.cpp +++ b/source/gui/ObjectTypes/CInput.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -913,10 +913,10 @@ void CInput::HandleMessage(SGUIMessage& Message) Message.value == "z" || Message.value == "absolute")) { - GetScrollBar(0).SetX(m_CachedActualSize.right); - GetScrollBar(0).SetY(m_CachedActualSize.top); + GetScrollBar(0).SetX(GetActualSize().right); + GetScrollBar(0).SetY(GetActualSize().top); GetScrollBar(0).SetZ(GetBufferedZ()); - GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); + GetScrollBar(0).SetLength(GetActualSize().bottom - GetActualSize().top); } // Update scrollbar @@ -945,7 +945,7 @@ void CInput::HandleMessage(SGUIMessage& Message) if (!m_MultiLine) GetScrollBar(0).SetLength(0.f); else - GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); + GetScrollBar(0).SetLength(GetActualSize().bottom - GetActualSize().top); UpdateText(); } @@ -970,7 +970,7 @@ void CInput::HandleMessage(SGUIMessage& Message) m_MultiLine && GetScrollBar(0).GetStyle()) { - if (m_pGUI.GetMousePos().X > m_CachedActualSize.right - GetScrollBar(0).GetStyle()->m_Width) + if (m_pGUI.GetMousePos().X > GetActualSize().right - GetScrollBar(0).GetStyle()->m_Width) break; } @@ -1127,10 +1127,10 @@ void CInput::HandleMessage(SGUIMessage& Message) } case GUIM_LOAD: { - GetScrollBar(0).SetX(m_CachedActualSize.right); - GetScrollBar(0).SetY(m_CachedActualSize.top); + GetScrollBar(0).SetX(GetActualSize().right); + GetScrollBar(0).SetY(GetActualSize().top); GetScrollBar(0).SetZ(GetBufferedZ()); - GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); + GetScrollBar(0).SetLength(GetActualSize().bottom - GetActualSize().top); GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); UpdateText(); @@ -1148,10 +1148,10 @@ void CInput::HandleMessage(SGUIMessage& Message) // Tell the IME where to draw the candidate list SDL_Rect rect; - rect.h = m_CachedActualSize.GetSize().Height; - rect.w = m_CachedActualSize.GetSize().Width; - rect.x = m_CachedActualSize.TopLeft().X; - rect.y = m_CachedActualSize.TopLeft().Y; + rect.h = GetActualSize().GetSize().Height; + rect.w = GetActualSize().GetSize().Width; + rect.x = GetActualSize().TopLeft().X; + rect.y = GetActualSize().TopLeft().Y; SDL_SetTextInputRect(&rect); SDL_StartTextInput(); break; @@ -1182,19 +1182,19 @@ void CInput::HandleMessage(SGUIMessage& Message) UpdateBufferPositionSetting(); } -void CInput::UpdateCachedSize() +void CInput::HandleSizeChanged() { // If an ancestor's size changed, this will let us intercept the change and // update our scrollbar positions - IGUIObject::UpdateCachedSize(); + IGUIObject::HandleSizeChanged(); if (m_ScrollBar) { - GetScrollBar(0).SetX(m_CachedActualSize.right); - GetScrollBar(0).SetY(m_CachedActualSize.top); + GetScrollBar(0).SetX(GetActualSize().right); + GetScrollBar(0).SetY(GetActualSize().top); GetScrollBar(0).SetZ(GetBufferedZ()); - GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); + GetScrollBar(0).SetLength(GetActualSize().bottom - GetActualSize().top); } m_GeneratedPlaceholderTextValid = false; @@ -1222,7 +1222,7 @@ void CInput::DrawContent(CCanvas2D& canvas) if (m_Mask && m_MaskChar->length() > 0) mask_char = (*m_MaskChar)[0]; - m_pGUI.DrawSprite(m_Sprite, canvas, m_CachedActualSize); + m_pGUI.DrawSprite(m_Sprite, canvas, GetActualSize()); float scroll = 0.f; if (m_ScrollBar && m_MultiLine) @@ -1252,8 +1252,8 @@ void CInput::DrawContent(CCanvas2D& canvas) textRenderer.SetCurrentFont(font_name, CStrIntern{}); textRenderer.Translate( - (float)(int)(m_CachedActualSize.left) + m_BufferZone, - (float)(int)(m_CachedActualSize.top + h) + m_BufferZone); + (float)(int)(GetActualSize().left) + m_BufferZone, + (float)(int)(GetActualSize().top + h) + m_BufferZone); // U+FE33: PRESENTATION FORM FOR VERTICAL LOW LINE // (sort of like a | which is aligned to the left of most characters) @@ -1306,7 +1306,7 @@ void CInput::DrawContent(CCanvas2D& canvas) it != m_CharacterPositions.end(); ++it, buffered_y += ls, x_pointer = 0.f) { - if (m_MultiLine && buffered_y > m_CachedActualSize.GetHeight()) + if (m_MultiLine && buffered_y > GetActualSize().GetHeight()) break; // We might as well use 'i' here to iterate, because we need it @@ -1348,33 +1348,33 @@ void CInput::DrawContent(CCanvas2D& canvas) if (m_MultiLine) { rect = CRect( - m_CachedActualSize.left + box_x + m_BufferZone, - m_CachedActualSize.top + buffered_y + (h - ls) / 2, - m_CachedActualSize.left + x_pointer + m_BufferZone, - m_CachedActualSize.top + buffered_y + (h + ls) / 2); + GetActualSize().left + box_x + m_BufferZone, + GetActualSize().top + buffered_y + (h - ls) / 2, + GetActualSize().left + x_pointer + m_BufferZone, + GetActualSize().top + buffered_y + (h + ls) / 2); - if (rect.bottom < m_CachedActualSize.top) + if (rect.bottom < GetActualSize().top) continue; - if (rect.top < m_CachedActualSize.top) - rect.top = m_CachedActualSize.top; + if (rect.top < GetActualSize().top) + rect.top = GetActualSize().top; - if (rect.bottom > m_CachedActualSize.bottom) - rect.bottom = m_CachedActualSize.bottom; + if (rect.bottom > GetActualSize().bottom) + rect.bottom = GetActualSize().bottom; } else // if one-line { rect = CRect( - m_CachedActualSize.left + box_x + m_BufferZone - m_HorizontalScroll, - m_CachedActualSize.top + buffered_y + (h - ls) / 2, - m_CachedActualSize.left + x_pointer + m_BufferZone - m_HorizontalScroll, - m_CachedActualSize.top + buffered_y + (h + ls) / 2); + GetActualSize().left + box_x + m_BufferZone - m_HorizontalScroll, + GetActualSize().top + buffered_y + (h - ls) / 2, + GetActualSize().left + x_pointer + m_BufferZone - m_HorizontalScroll, + GetActualSize().top + buffered_y + (h + ls) / 2); - if (rect.left < m_CachedActualSize.left) - rect.left = m_CachedActualSize.left; + if (rect.left < GetActualSize().left) + rect.left = GetActualSize().left; - if (rect.right > m_CachedActualSize.right) - rect.right = m_CachedActualSize.right; + if (rect.right > GetActualSize().right) + rect.right = GetActualSize().right; } m_pGUI.DrawSprite(m_SpriteSelectArea, canvas, rect); @@ -1414,7 +1414,7 @@ void CInput::DrawContent(CCanvas2D& canvas) { if (buffered_y + m_BufferZone >= -ls || !m_MultiLine) { - if (m_MultiLine && buffered_y + m_BufferZone > m_CachedActualSize.GetHeight()) + if (m_MultiLine && buffered_y + m_BufferZone > GetActualSize().GetHeight()) break; const CVector2D savedTranslate = textRenderer.GetTranslate(); @@ -1474,7 +1474,7 @@ void CInput::DrawContent(CCanvas2D& canvas) // check it's now outside a one-liner, then we'll break if (!m_MultiLine && i < (int)it->m_ListOfX.size() && - it->m_ListOfX[i] - m_HorizontalScroll > m_CachedActualSize.GetWidth() - m_BufferZone) + it->m_ListOfX[i] - m_HorizontalScroll > GetActualSize().GetWidth() - m_BufferZone) break; } @@ -1500,7 +1500,7 @@ void CInput::DrawContent(CCanvas2D& canvas) void CInput::Draw(CCanvas2D& canvas) { // We'll have to setup clipping manually, since we're doing the rendering manually. - CRect cliparea = m_VisibleArea ? m_VisibleArea : m_CachedActualSize; + CRect cliparea = m_VisibleArea ? m_VisibleArea : GetActualSize(); // First we'll figure out the clipping area, which is the cached actual size // substracted by an optional scrollbar @@ -1535,7 +1535,7 @@ void CInput::Draw(CCanvas2D& canvas) IGUIScrollBarOwner::Draw(canvas); // Draw the overlays last - m_pGUI.DrawSprite(m_SpriteOverlay, canvas, m_CachedActualSize, m_VisibleArea); + m_pGUI.DrawSprite(m_SpriteOverlay, canvas, GetActualSize(), m_VisibleArea); } void CInput::DrawPlaceholderText(CCanvas2D& canvas, const CRect& clipping) @@ -1543,7 +1543,7 @@ void CInput::DrawPlaceholderText(CCanvas2D& canvas, const CRect& clipping) if (!m_GeneratedPlaceholderTextValid) SetupGeneratedPlaceholderText(); - m_GeneratedPlaceholderText.Draw(m_pGUI, canvas, m_PlaceholderColor, m_CachedActualSize.TopLeft(), clipping); + m_GeneratedPlaceholderText.Draw(m_pGUI, canvas, m_PlaceholderColor, GetActualSize().TopLeft(), clipping); } void CInput::UpdateText(int from, int to_before, int to_after) @@ -1894,7 +1894,7 @@ void CInput::UpdateText(int from, int to_before, int to_after) if (m_ScrollBar) { GetScrollBar(0).SetScrollRange(m_CharacterPositions.size() * font.GetHeight() + m_BufferZone * 2.f); - GetScrollBar(0).SetScrollSpace(m_CachedActualSize.GetHeight()); + GetScrollBar(0).SetScrollSpace(GetActualSize().GetHeight()); } } @@ -1920,7 +1920,7 @@ int CInput::GetMouseHoveringTextPosition() const const float spacing{font.GetHeight()}; // Change mouse position relative to text. - mouse -= m_CachedActualSize.TopLeft(); + mouse -= GetActualSize().TopLeft(); mouse.X -= m_BufferZone; mouse.Y += scroll - m_BufferZone; @@ -1942,7 +1942,7 @@ int CInput::GetMouseHoveringTextPosition() const { // current is already set to begin, // but we'll change the mouse.x to fit our horizontal scrolling - mouse -= m_CachedActualSize.TopLeft(); + mouse -= GetActualSize().TopLeft(); mouse.X -= m_BufferZone - m_HorizontalScroll; // mouse.y is moot } @@ -2028,9 +2028,9 @@ bool CInput::SelectingText() const float CInput::GetTextAreaWidth() { if (m_ScrollBar && GetScrollBar(0).GetStyle()) - return m_CachedActualSize.GetWidth() - m_BufferZone * 2.f - GetScrollBar(0).GetStyle()->m_Width; + return GetActualSize().GetWidth() - m_BufferZone * 2.f - GetScrollBar(0).GetStyle()->m_Width; - return m_CachedActualSize.GetWidth() - m_BufferZone * 2.f; + return GetActualSize().GetWidth() - m_BufferZone * 2.f; } void CInput::UpdateAutoScroll() @@ -2062,10 +2062,10 @@ void CInput::UpdateAutoScroll() } // If scrolling down - if (-scroll + static_cast(row + 1) * spacing + m_BufferZone * 2.f > m_CachedActualSize.GetHeight()) + if (-scroll + static_cast(row + 1) * spacing + m_BufferZone * 2.f > GetActualSize().GetHeight()) { // Scroll so the selected row is shown completely, also with m_BufferZone length to the edge. - GetScrollBar(0).SetPos(static_cast(row + 1) * spacing - m_CachedActualSize.GetHeight() + m_BufferZone * 2.f); + GetScrollBar(0).SetPos(static_cast(row + 1) * spacing - GetActualSize().GetHeight() + m_BufferZone * 2.f); } // If scrolling up else if (-scroll + (float)row * spacing < 0.f) @@ -2095,8 +2095,8 @@ void CInput::UpdateAutoScroll() } // Check if outside to the right - if (x_position - m_HorizontalScroll + m_BufferZone * 2.f > m_CachedActualSize.GetWidth()) - m_HorizontalScroll = x_position - m_CachedActualSize.GetWidth() + m_BufferZone * 2.f; + if (x_position - m_HorizontalScroll + m_BufferZone * 2.f > GetActualSize().GetWidth()) + m_HorizontalScroll = x_position - GetActualSize().GetWidth() + m_BufferZone * 2.f; // Check if outside to the left if (x_position - m_HorizontalScroll < 0.f) @@ -2104,12 +2104,12 @@ void CInput::UpdateAutoScroll() // Check if the text doesn't even fill up to the right edge even though scrolling is done. if (m_HorizontalScroll != 0.f && - x_total - m_HorizontalScroll + m_BufferZone * 2.f < m_CachedActualSize.GetWidth()) - m_HorizontalScroll = x_total - m_CachedActualSize.GetWidth() + m_BufferZone * 2.f; + x_total - m_HorizontalScroll + m_BufferZone * 2.f < GetActualSize().GetWidth()) + m_HorizontalScroll = x_total - GetActualSize().GetWidth() + m_BufferZone * 2.f; // Now this is the fail-safe, if x_total isn't even the length of the control, // remove all scrolling - if (x_total + m_BufferZone * 2.f < m_CachedActualSize.GetWidth()) + if (x_total + m_BufferZone * 2.f < GetActualSize().GetWidth()) m_HorizontalScroll = 0.f; } } diff --git a/source/gui/ObjectTypes/CInput.h b/source/gui/ObjectTypes/CInput.h index 4faffe94ff..deeb4a9ead 100644 --- a/source/gui/ObjectTypes/CInput.h +++ b/source/gui/ObjectTypes/CInput.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -98,9 +98,9 @@ protected: virtual InReaction ManuallyHandleHotkeyEvent(const SDL_Event_* ev); /** - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ - virtual void UpdateCachedSize(); + virtual void HandleSizeChanged(); /** * Draws the Text diff --git a/source/gui/ObjectTypes/CList.cpp b/source/gui/ObjectTypes/CList.cpp index 8a1d454148..5a8dc8d9f8 100644 --- a/source/gui/ObjectTypes/CList.cpp +++ b/source/gui/ObjectTypes/CList.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -158,10 +158,10 @@ void CList::ResetStates() IGUIScrollBarOwner::ResetStates(); } -void CList::UpdateCachedSize() +void CList::HandleSizeChanged() { - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); + IGUIObject::HandleSizeChanged(); + IGUITextOwner::HandleSizeChanged(); } void CList::HandleMessage(SGUIMessage& Message) diff --git a/source/gui/ObjectTypes/CList.h b/source/gui/ObjectTypes/CList.h index ee58badbab..deb8769dd4 100644 --- a/source/gui/ObjectTypes/CList.h +++ b/source/gui/ObjectTypes/CList.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -57,9 +57,9 @@ public: virtual void ResetStates(); /** - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ - virtual void UpdateCachedSize(); + virtual void HandleSizeChanged(); /** * Adds an item last to the list. @@ -119,8 +119,8 @@ protected: const CGUISpriteInstance& spriteSelectArea, const CGUISpriteInstance& spriteSelectAreaOverlay, const CGUIColor& textColor); // Get the area of the list. This is so that it can easily be changed, like in CDropDown - // where the area is not equal to m_CachedActualSize. - virtual CRect GetListRect() const { return m_CachedActualSize; } + // where the area is not equal to GetActualSize(). + virtual CRect GetListRect() const { return GetActualSize(); } // Returns whether SetupText() has run since the last message was received // (and thus whether list items have possibly changed). diff --git a/source/gui/ObjectTypes/CMiniMap.cpp b/source/gui/ObjectTypes/CMiniMap.cpp index 132c4a9c70..609e756296 100644 --- a/source/gui/ObjectTypes/CMiniMap.cpp +++ b/source/gui/ObjectTypes/CMiniMap.cpp @@ -206,9 +206,9 @@ bool CMiniMap::IsMouseOver() const { const CVector2D& mousePos = m_pGUI.GetMousePos(); // Take the magnitude of the difference of the mouse position and minimap center. - const float distanceFromCenter = (mousePos - m_CachedActualSize.CenterPoint()).Length(); + const float distanceFromCenter = (mousePos - GetActualSize().CenterPoint()).Length(); // If the distance is less then the radius of the minimap (half the width) the mouse is over the minimap. - return distanceFromCenter < m_CachedActualSize.GetWidth() / 2.0; + return distanceFromCenter < GetActualSize().GetWidth() / 2.0; } void CMiniMap::GetMouseWorldCoordinates(float& x, float& z) const @@ -216,8 +216,8 @@ void CMiniMap::GetMouseWorldCoordinates(float& x, float& z) const // Determine X and Z according to proportion of mouse position and minimap. const CVector2D& mousePos = m_pGUI.GetMousePos(); - float px = (mousePos.X - m_CachedActualSize.left) / m_CachedActualSize.GetWidth(); - float py = (m_CachedActualSize.bottom - mousePos.Y) / m_CachedActualSize.GetHeight(); + float px = (mousePos.X - GetActualSize().left) / GetActualSize().GetWidth(); + float py = (GetActualSize().bottom - mousePos.Y) / GetActualSize().GetHeight(); float angle = GetAngle(); @@ -256,8 +256,8 @@ CVector2D CMiniMap::WorldSpaceToMiniMapSpace(const CVector3D& worldPosition) con // Calculate coordinates in GUI space. return CVector2D( - m_CachedActualSize.left + (0.5f + rotatedX) * m_CachedActualSize.GetWidth(), - m_CachedActualSize.bottom - (0.5f + rotatedY) * m_CachedActualSize.GetHeight()); + GetActualSize().left + (0.5f + rotatedX) * GetActualSize().GetWidth(), + GetActualSize().bottom - (0.5f + rotatedY) * GetActualSize().GetHeight()); } bool CMiniMap::FireWorldClickEvent(int button, int /*clicks*/) @@ -364,7 +364,7 @@ void CMiniMap::Draw(CCanvas2D& canvas) return; if (!m_Mask) - canvas.DrawRect(m_CachedActualSize, CColor(0.0f, 0.0f, 0.0f, 1.0f)); + canvas.DrawRect(GetActualSize(), CColor(0.0f, 0.0f, 0.0f, 1.0f)); CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr cmpRangeManager(*sim, SYSTEM_ENTITY); @@ -379,13 +379,13 @@ void CMiniMap::Draw(CCanvas2D& canvas) CMiniMapTexture& miniMapTexture = g_Game->GetView()->GetMiniMapTexture(); if (miniMapTexture.GetTexture()) { - const CVector2D center = m_CachedActualSize.CenterPoint(); + const CVector2D center = GetActualSize().CenterPoint(); const CRect source( 0, miniMapTexture.IsFlipped() ? 0 : miniMapTexture.GetTexture()->GetHeight(), miniMapTexture.GetTexture()->GetWidth(), miniMapTexture.IsFlipped() ? miniMapTexture.GetTexture()->GetHeight() : 0); - const CSize2D size(m_CachedActualSize.GetSize() / m_MapScale); + const CSize2D size(GetActualSize().GetSize() / m_MapScale); const CRect destination(center - size / 2.0f, size); canvas.DrawRotatedTexture( miniMapTexture.GetTexture(), destination, source, diff --git a/source/gui/ObjectTypes/COList.cpp b/source/gui/ObjectTypes/COList.cpp index 113ecbd29f..20aefc8995 100644 --- a/source/gui/ObjectTypes/COList.cpp +++ b/source/gui/ObjectTypes/COList.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2024 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -132,7 +132,7 @@ void COList::SetupText() CRect COList::GetListRect() const { - return m_CachedActualSize + CRect(0, m_HeadingHeight, 0, 0); + return GetActualSize() + CRect(0, m_HeadingHeight, 0, 0); } void COList::HandleMessage(SGUIMessage& Message) @@ -156,7 +156,7 @@ void COList::HandleMessage(SGUIMessage& Message) return; const CVector2D& mouse = m_pGUI.GetMousePos(); - if (!m_CachedActualSize.PointInside(mouse)) + if (!GetActualSize().PointInside(mouse)) return; float xpos = 0; @@ -169,7 +169,7 @@ void COList::HandleMessage(SGUIMessage& Message) // Check if it's a decimal value, and if so, assume relative positioning. if (column.m_Width < 1 && column.m_Width > 0) width *= m_TotalAvailableColumnWidth; - CVector2D leftTopCorner = m_CachedActualSize.TopLeft() + CVector2D(xpos, 0); + CVector2D leftTopCorner = GetActualSize().TopLeft() + CVector2D(xpos, 0); if (mouse.X >= leftTopCorner.X && mouse.X < leftTopCorner.X + width && mouse.Y < leftTopCorner.Y + m_HeadingHeight) @@ -362,8 +362,8 @@ void COList::DrawList(CCanvas2D& canvas, const int& selected, const CGUISpriteIn } // Draw line above column header - CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right, - m_CachedActualSize.top + m_HeadingHeight); + CRect rect_head(GetActualSize().left, GetActualSize().top, GetActualSize().right, + GetActualSize().top + m_HeadingHeight); m_pGUI.DrawSprite(m_SpriteHeading, canvas, rect_head, m_VisibleArea); // Draw column headers @@ -382,7 +382,7 @@ void COList::DrawList(CCanvas2D& canvas, const int& selected, const CGUISpriteIn if (column.m_Width < 1 && column.m_Width > 0) width *= m_TotalAvailableColumnWidth; - CVector2D leftTopCorner = m_CachedActualSize.TopLeft() + CVector2D(xpos, 0); + CVector2D leftTopCorner = GetActualSize().TopLeft() + CVector2D(xpos, 0); // Draw sort arrows in colum header if (m_Sortable) diff --git a/source/gui/ObjectTypes/CProgressBar.cpp b/source/gui/ObjectTypes/CProgressBar.cpp index 764da5e119..a14301af84 100644 --- a/source/gui/ObjectTypes/CProgressBar.cpp +++ b/source/gui/ObjectTypes/CProgressBar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -56,10 +56,10 @@ void CProgressBar::HandleMessage(SGUIMessage& Message) void CProgressBar::Draw(CCanvas2D& canvas) { - m_pGUI.DrawSprite(m_SpriteBackground, canvas, m_CachedActualSize, m_VisibleArea); + m_pGUI.DrawSprite(m_SpriteBackground, canvas, GetActualSize(), m_VisibleArea); // Get size of bar (notice it is drawn slightly closer, to appear above the background) - CRect size = m_CachedActualSize; - size.right = size.left + m_CachedActualSize.GetWidth() * (m_Progress / 100.f), + CRect size = GetActualSize(); + size.right = size.left + GetActualSize().GetWidth() * (m_Progress / 100.f), m_pGUI.DrawSprite(m_SpriteBar, canvas, size, m_VisibleArea); } diff --git a/source/gui/ObjectTypes/CScrollPanel.cpp b/source/gui/ObjectTypes/CScrollPanel.cpp index 91540f8c98..3d5d69cc6f 100644 --- a/source/gui/ObjectTypes/CScrollPanel.cpp +++ b/source/gui/ObjectTypes/CScrollPanel.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -56,10 +56,36 @@ void CScrollPanel::ResetStates() IGUIScrollBarOwner::ResetStates(); } -void CScrollPanel::UpdateCachedSize() +void CScrollPanel::RecalculateActualSize() const { - IGUIPanel::UpdateCachedSize(); - Setup(); + IGUIPanel::RecalculateActualSize(); + + IGUIScrollBar& scrollbar0 = GetScrollBar(0); + float vscroll = scrollbar0.GetPos(); + IGUIScrollBar& scrollbar1 = GetScrollBar(1); + float hscroll = scrollbar1.GetPos(); + + m_CachedActualSize = m_CachedLayoutActualSize; + + if (HasVerticalScrollBar() && m_CachedLayoutActualSize.GetHeight() < m_MinHeight) + m_CachedActualSize.bottom = m_CachedLayoutActualSize.top + m_MinHeight; + + if (HasHorizontalScrollBar() && m_CachedLayoutActualSize.GetWidth() < m_MinWidth) + m_CachedActualSize.right = m_CachedLayoutActualSize.left + m_MinWidth; + + m_CachedActualSize.top -= vscroll; + m_CachedActualSize.bottom -= vscroll; + + m_CachedActualSize.left -= hscroll; + m_CachedActualSize.right -= hscroll; + + if (scrollbar0.IsVisible()) + m_CachedActualSize.right -= scrollbar0.GetOuterRect().GetWidth(); + if (scrollbar1.IsVisible()) + m_CachedActualSize.bottom -= scrollbar1.GetOuterRect().GetHeight(); + + for (IGUIObject* child : m_Children) + child->RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::HandleSizeChanged); } void CScrollPanel::HandleMessage(SGUIMessage& Message) @@ -71,24 +97,9 @@ void CScrollPanel::HandleMessage(SGUIMessage& Message) float vscroll = scrollbar0.GetPos(); float hscroll = scrollbar1.GetPos(); - bool updateScrollPosition = false; - IGUIScrollBarOwner::HandleMessage(Message); - - if (vscroll != scrollbar0.GetPos()) - { - vscroll = scrollbar0.GetPos(); - updateScrollPosition = true; - } - - if (hscroll != scrollbar1.GetPos()) - { - hscroll = scrollbar1.GetPos(); - updateScrollPosition = true; - } - - if (updateScrollPosition) - UpdateScrollPosition(vscroll, hscroll); + if (vscroll != scrollbar0.GetPos() || hscroll != scrollbar1.GetPos()) + m_CachedActualSizeDirty = true; switch (Message.type) { @@ -97,20 +108,20 @@ void CScrollPanel::HandleMessage(SGUIMessage& Message) { scrollbar0.SetScrollBarStyle(m_ScrollBarStyle); scrollbar1.SetScrollBarStyle(m_ScrollBarStyle); - Setup(); + UpdateScrollBars(); } if (Message.value == "orientation" || Message.value == "size" || Message.value == "min_width" || Message.value == "min_height") { scrollbar0.SetPos(0); scrollbar1.SetPos(0); - Setup(); + UpdateScrollBars(); } break; case GUIM_CHILD_RESIZED: case GUIM_CHILD_TOGGLE_VISIBILITY: - Setup(); + UpdateScrollBars(); Message.Skip(false); break; @@ -118,7 +129,7 @@ void CScrollPanel::HandleMessage(SGUIMessage& Message) scrollbar0.SetScrollBarStyle(m_ScrollBarStyle); scrollbar1.SetScrollBarStyle(m_ScrollBarStyle); - Setup(); + UpdateScrollBars(); break; default: @@ -146,32 +157,21 @@ void CScrollPanel::Draw(CCanvas2D& canvas) m_Drawing = false; } -void CScrollPanel::Setup() +void CScrollPanel::UpdateScrollBars() { IGUIScrollBar& scrollbar0 = GetScrollBar(0); IGUIScrollBar& scrollbar1 = GetScrollBar(1); - m_CachedActualSize = m_CachedLayoutActualSize; - - if (HasVerticalScrollBar() && m_CachedLayoutActualSize.GetHeight() < m_MinHeight) - m_CachedActualSize.bottom = m_CachedLayoutActualSize.top + m_MinHeight; - - if (HasHorizontalScrollBar() && m_CachedLayoutActualSize.GetWidth() < m_MinWidth) - m_CachedActualSize.right = m_CachedLayoutActualSize.left + m_MinWidth; - - for (IGUIObject* child : m_Children) - child->RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::UpdateCachedSize); - float vscroll = scrollbar0.GetPos(); float hscroll = scrollbar1.GetPos(); float maxVRange = 0; float maxHRange = 0; - for (IGUIObject* child : m_Children) + for (const IGUIObject* child : m_Children) { if (child->IsHiddenOrGhost()) continue; - CRect childSize = child->GetComputedSize(); + const CRect& childSize = child->GetActualSize(); maxVRange = std::max(maxVRange, childSize.bottom); maxHRange = std::max(maxHRange, childSize.right); } @@ -216,37 +216,6 @@ void CScrollPanel::Setup() hscroll = maxHRange; scrollbar1.SetPos(hscroll); } - - UpdateScrollPosition(vscroll, hscroll); -} - -void CScrollPanel::UpdateScrollPosition(float scroll, float hscroll) -{ - IGUIScrollBar& scrollbar0 = GetScrollBar(0); - IGUIScrollBar& scrollbar1 = GetScrollBar(1); - - m_CachedActualSize = m_CachedLayoutActualSize; - - if (HasVerticalScrollBar() && m_CachedLayoutActualSize.GetHeight() < m_MinHeight) - m_CachedActualSize.bottom = m_CachedLayoutActualSize.top + m_MinHeight; - - if (HasHorizontalScrollBar() && m_CachedLayoutActualSize.GetWidth() < m_MinWidth) - m_CachedActualSize.right = m_CachedLayoutActualSize.left + m_MinWidth; - - m_CachedActualSize.top -= scroll; - m_CachedActualSize.bottom -= scroll; - - m_CachedActualSize.left -= hscroll; - m_CachedActualSize.right -= hscroll; - - // upddate scroll bars size base on m_Width - if (scrollbar0.IsVisible()) - m_CachedActualSize.right -= scrollbar0.GetOuterRect().GetWidth(); - if (scrollbar1.IsVisible()) - m_CachedActualSize.bottom -= scrollbar1.GetOuterRect().GetHeight(); - - for (IGUIObject* child : m_Children) - child->RecurseObject(&IGUIObject::IsHiddenOrGhost, &IGUIObject::UpdateCachedSize); } void CScrollPanel::ResetScrollPosition(EScrollOrientation orientation) diff --git a/source/gui/ObjectTypes/CScrollPanel.h b/source/gui/ObjectTypes/CScrollPanel.h index 21df8e38d0..7ad66173d5 100644 --- a/source/gui/ObjectTypes/CScrollPanel.h +++ b/source/gui/ObjectTypes/CScrollPanel.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,11 +35,8 @@ class CScrollPanel : public IGUIPanel, public IGUIScrollBarOwner public: CScrollPanel(CGUI& pGUI); - virtual void UpdateCachedSize(); virtual void ResetStates(); - void Setup(); - void ResetScrollPosition(EScrollOrientation orientation = EScrollOrientation::BOTH); protected: @@ -48,7 +45,9 @@ protected: */ virtual void HandleMessage(SGUIMessage& Message); - void UpdateScrollPosition(float vscroll, float hscroll); + virtual void RecalculateActualSize() const; + + void UpdateScrollBars(); bool HasHorizontalScrollBar() const { return *m_Orientation == EScrollOrientation::HORIZONTAL || *m_Orientation == EScrollOrientation::BOTH; }; bool HasVerticalScrollBar() const { return *m_Orientation == EScrollOrientation::VERTICAL || *m_Orientation == EScrollOrientation::BOTH; }; diff --git a/source/gui/ObjectTypes/CSlider.cpp b/source/gui/ObjectTypes/CSlider.cpp index 4847e339b8..cc76abc4fa 100644 --- a/source/gui/ObjectTypes/CSlider.cpp +++ b/source/gui/ObjectTypes/CSlider.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -49,7 +49,7 @@ void CSlider::ResetStates() float CSlider::GetSliderRatio() const { - return (m_MaxValue - m_MinValue) / (m_CachedActualSize.GetWidth() - m_ButtonSide); + return (m_MaxValue - m_MinValue) / (GetActualSize().GetWidth() - m_ButtonSide); } void CSlider::IncrementallyChangeValue(const float difference) @@ -105,7 +105,7 @@ void CSlider::HandleMessage(SGUIMessage& Message) void CSlider::Draw(CCanvas2D& canvas) { - CRect sliderLine(m_CachedActualSize); + CRect sliderLine(GetActualSize()); sliderLine.left += m_ButtonSide / 2.0f; sliderLine.right -= m_ButtonSide / 2.0f; m_pGUI.DrawSprite(IsEnabled() ? m_SpriteBar : m_SpriteBarDisabled, canvas, sliderLine, m_VisibleArea); @@ -124,7 +124,7 @@ CRect CSlider::GetButtonRect() const // config for debug purposes. const float value = Clamp(m_Value, m_MinValue, m_MaxValue); float ratio = m_MaxValue > m_MinValue ? (value - m_MinValue) / (m_MaxValue - m_MinValue) : 0.0f; - float x = m_CachedActualSize.left + ratio * (m_CachedActualSize.GetWidth() - m_ButtonSide); - float y = m_CachedActualSize.top + (m_CachedActualSize.GetHeight() - m_ButtonSide) / 2.0; + float x = GetActualSize().left + ratio * (GetActualSize().GetWidth() - m_ButtonSide); + float y = GetActualSize().top + (GetActualSize().GetHeight() - m_ButtonSide) / 2.0; return CRect(x, y, x + m_ButtonSide, y + m_ButtonSide); } diff --git a/source/gui/ObjectTypes/CText.cpp b/source/gui/ObjectTypes/CText.cpp index 0a6834c49d..a251210c2b 100644 --- a/source/gui/ObjectTypes/CText.cpp +++ b/source/gui/ObjectTypes/CText.cpp @@ -64,7 +64,7 @@ void CText::SetupText() if (m_GeneratedTexts.empty()) return; - float width = m_CachedActualSize.GetWidth(); + float width = GetActualSize().GetWidth(); // remove scrollbar if applicable if (m_ScrollBar && GetScrollBar(0).GetStyle()) width -= GetScrollBar(0).GetStyle()->m_Width; @@ -83,12 +83,12 @@ void CText::SetupText() bottom = true; GetScrollBar(0).SetScrollRange(m_GeneratedTexts[0].GetSize().Height); - GetScrollBar(0).SetScrollSpace(m_CachedActualSize.GetHeight()); + GetScrollBar(0).SetScrollSpace(GetActualSize().GetHeight()); - GetScrollBar(0).SetX(m_CachedActualSize.right); - GetScrollBar(0).SetY(m_CachedActualSize.top); + GetScrollBar(0).SetX(GetActualSize().right); + GetScrollBar(0).SetY(GetActualSize().top); GetScrollBar(0).SetZ(GetBufferedZ()); - GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); + GetScrollBar(0).SetLength(GetActualSize().bottom - GetActualSize().top); if (bottom) GetScrollBar(0).SetPos(GetScrollBar(0).GetMaxPos()); @@ -98,7 +98,7 @@ void CText::SetupText() } if (!m_ScrollBar || !std::ranges::any_of(m_ScrollBars, &IGUIScrollBar::IsVisible)) - CalculateTextPosition(m_CachedActualSize, m_TextPos, m_GeneratedTexts[0]); + CalculateTextPosition(GetActualSize(), m_TextPos, m_GeneratedTexts[0]); } void CText::ResetStates() @@ -107,10 +107,10 @@ void CText::ResetStates() IGUIScrollBarOwner::ResetStates(); } -void CText::UpdateCachedSize() +void CText::HandleSizeChanged() { - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); + IGUIObject::HandleSizeChanged(); + IGUITextOwner::HandleSizeChanged(); } CSize2D CText::GetTextSize() @@ -132,7 +132,7 @@ const CStrW& CText::GetTooltipText() const if (textChunk.m_Tooltip.empty()) continue; CRect area(textChunk.m_Pos - CVector2D(0.f, textChunk.m_Size.Height), textChunk.m_Size); - if (area.PointInside(m_pGUI.GetMousePos() - m_CachedActualSize.TopLeft())) + if (area.PointInside(m_pGUI.GetMousePos() - GetActualSize().TopLeft())) return textChunk.m_Tooltip; } return m_Tooltip; @@ -162,10 +162,10 @@ void CText::HandleMessage(SGUIMessage& Message) case GUIM_LOAD: { - GetScrollBar(0).SetX(m_CachedActualSize.right); - GetScrollBar(0).SetY(m_CachedActualSize.top); + GetScrollBar(0).SetX(GetActualSize().right); + GetScrollBar(0).SetY(GetActualSize().top); GetScrollBar(0).SetZ(GetBufferedZ()); - GetScrollBar(0).SetLength(m_CachedActualSize.bottom - m_CachedActualSize.top); + GetScrollBar(0).SetLength(GetActualSize().bottom - GetActualSize().top); GetScrollBar(0).SetScrollBarStyle(m_ScrollBarStyle); break; } @@ -179,14 +179,14 @@ void CText::HandleMessage(SGUIMessage& Message) void CText::Draw(CCanvas2D& canvas) { - m_pGUI.DrawSprite(m_Sprite, canvas, m_CachedActualSize, m_VisibleArea); + m_pGUI.DrawSprite(m_Sprite, canvas, GetActualSize(), m_VisibleArea); float scroll = 0.f; if (m_ScrollBar) scroll = GetScrollBar(0).GetPos(); // Clipping area (we'll have to subtract the scrollbar) - CRect cliparea = m_VisibleArea ? m_VisibleArea : m_CachedActualSize; + CRect cliparea = m_VisibleArea ? m_VisibleArea : GetActualSize(); if (m_Clip) { if (m_ScrollBar) @@ -206,7 +206,7 @@ void CText::Draw(CCanvas2D& canvas) if (m_ScrollBar && std::ranges::any_of(m_ScrollBars, &IGUIScrollBar::IsVisible)) { - DrawText(canvas, 0, color, m_CachedActualSize.TopLeft() - CVector2D(0.f, scroll), cliparea); + DrawText(canvas, 0, color, GetActualSize().TopLeft() - CVector2D(0.f, scroll), cliparea); // Draw scrollbars on top of the content IGUIScrollBarOwner::Draw(canvas); } @@ -214,5 +214,5 @@ void CText::Draw(CCanvas2D& canvas) DrawText(canvas, 0, color, m_TextPos, cliparea); // Draw the overlays last - m_pGUI.DrawSprite(m_SpriteOverlay, canvas, m_CachedActualSize, m_VisibleArea); + m_pGUI.DrawSprite(m_SpriteOverlay, canvas, GetActualSize(), m_VisibleArea); } diff --git a/source/gui/ObjectTypes/CText.h b/source/gui/ObjectTypes/CText.h index af04c58ae4..c12a6a3b84 100644 --- a/source/gui/ObjectTypes/CText.h +++ b/source/gui/ObjectTypes/CText.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -46,9 +46,9 @@ public: virtual void ResetStates(); /** - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ - virtual void UpdateCachedSize(); + virtual void HandleSizeChanged(); /** * @return the object text size. diff --git a/source/gui/ObjectTypes/CTooltip.cpp b/source/gui/ObjectTypes/CTooltip.cpp index a3a2073ac0..4a39e83c4a 100644 --- a/source/gui/ObjectTypes/CTooltip.cpp +++ b/source/gui/ObjectTypes/CTooltip.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -121,10 +121,10 @@ void CTooltip::SetupText() m_Size.Set(size, true); } -void CTooltip::UpdateCachedSize() +void CTooltip::HandleSizeChanged() { - IGUIObject::UpdateCachedSize(); - IGUITextOwner::UpdateCachedSize(); + IGUIObject::HandleSizeChanged(); + IGUITextOwner::HandleSizeChanged(); } void CTooltip::HandleMessage(SGUIMessage& Message) @@ -143,8 +143,8 @@ void CTooltip::Draw(CCanvas2D& canvas) m_GeneratedTextsValid = true; } - m_pGUI.DrawSprite(m_Sprite, canvas, m_CachedActualSize); - DrawText(canvas, 0, m_TextColor, m_CachedActualSize.TopLeft()); + m_pGUI.DrawSprite(m_Sprite, canvas, GetActualSize()); + DrawText(canvas, 0, m_TextColor, GetActualSize().TopLeft()); } float CTooltip::GetBufferedZ() const diff --git a/source/gui/ObjectTypes/CTooltip.h b/source/gui/ObjectTypes/CTooltip.h index dc804ea99d..277dffdafa 100644 --- a/source/gui/ObjectTypes/CTooltip.h +++ b/source/gui/ObjectTypes/CTooltip.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -50,9 +50,9 @@ protected: void SetupText(); /** - * @see IGUIObject#UpdateCachedSize() + * @see IGUIObject#HandleSizeChanged() */ - void UpdateCachedSize(); + void HandleSizeChanged(); /** * @see IGUIObject#HandleMessage() diff --git a/source/gui/Scripting/JSInterface_CGUISize.cpp b/source/gui/Scripting/JSInterface_CGUISize.cpp index bcddadb882..0910ec3fbb 100644 --- a/source/gui/Scripting/JSInterface_CGUISize.cpp +++ b/source/gui/Scripting/JSInterface_CGUISize.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -73,9 +73,10 @@ bool SetCRectField(JSContext* cx, unsigned argc, JS::Value* vp) return false; wrapper->GetMutable().*RectMember.*Member = static_cast(val); + wrapper->Set(wrapper->GetMutable(), true); // causes CGUISimpleSetting to actually process the change + args.rval().setUndefined(); - wrapper->DeferSettingChange(); return true; } diff --git a/source/gui/Scripting/JSInterface_GUIProxy.cpp b/source/gui/Scripting/JSInterface_GUIProxy.cpp index 69931ed5b8..5b0ca09209 100644 --- a/source/gui/Scripting/JSInterface_GUIProxy.cpp +++ b/source/gui/Scripting/JSInterface_GUIProxy.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -41,7 +41,7 @@ void JSI_GUIProxy::CreateFunctions(const ScriptRequest& rq, GUIProxy CreateFunction<&IGUIObject::GetName>(rq, cache, "toSource"); CreateFunction<&IGUIObject::SetFocus>(rq, cache, "focus"); CreateFunction<&IGUIObject::ReleaseFocus>(rq, cache, "blur"); - CreateFunction<&IGUIObject::GetComputedSize>(rq, cache, "getComputedSize"); + CreateFunction<&IGUIObject::GetActualSize>(rq, cache, "getComputedSize"); } DECLARE_GUIPROXY(IGUIObject); diff --git a/source/gui/tests/test_GUISetting.h b/source/gui/tests/test_GUISetting.h index 58a1a85b10..1e0c834119 100644 --- a/source/gui/tests/test_GUISetting.h +++ b/source/gui/tests/test_GUISetting.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -63,9 +63,9 @@ public: TestGUIObject(CGUI& gui) : IGUIObject(gui) {} void Draw(CCanvas2D&) {} - void UpdateCachedSize() { - haveUpdateCachedSize = true; - IGUIObject::UpdateCachedSize(); + void RecalculateActualSize() const { + cachedSizeRecalculated = true; + IGUIObject::RecalculateActualSize(); } CGUISimpleSetting* GetSizeSetting() const @@ -73,7 +73,7 @@ public: return static_cast*>(m_Settings.at("size")); } - bool haveUpdateCachedSize{false}; + mutable bool cachedSizeRecalculated{false}; }; void setUp() @@ -139,7 +139,6 @@ public: CGUISimpleSetting* setting{object.GetSizeSetting()}; object.SetSettingFromString("size", L"2 2 20 20", false); - object.haveUpdateCachedSize = false; ScriptRequest rq{gui.GetScriptInterface()}; JS::RootedValue val(rq.cx); @@ -151,36 +150,33 @@ public: TS_ASSERT(gui.GetScriptInterface()->LoadGlobalScriptFile(L"gui/settings/cguisize/lazyassign.js")); TS_ASSERT_EQUALS(setting->GetMutable().pixel, (CRect{5, 2, 20, 20})); TS_ASSERT_EQUALS(setting->GetMutable().percent, (CRect{0, 0, 0, 0})); - TS_ASSERT_EQUALS(object.haveUpdateCachedSize, false); + TS_ASSERT(!object.cachedSizeRecalculated); - // Force update of cached size. - object.GetComputedSize(); - object.haveUpdateCachedSize = false; + // This should finally recalculate the dirty (cached) actual size in order to return an up-to-date value. + TS_ASSERT_EQUALS(object.GetActualSize(), (CRect{5, 2, 20, 20})); + TS_ASSERT(object.cachedSizeRecalculated); + + object.cachedSizeRecalculated = false; // Compound assignment operator. TS_ASSERT(gui.GetScriptInterface()->LoadGlobalScriptFile(L"gui/settings/cguisize/compoundassignmentoperator.js")); TS_ASSERT_EQUALS(setting->GetMutable().pixel, (CRect{10, 2, 20, 20})); TS_ASSERT_EQUALS(setting->GetMutable().percent, (CRect{0, 0, 0, 0})); - TS_ASSERT_EQUALS(object.haveUpdateCachedSize, false); - - // Force update of cached size. - object.GetComputedSize(); - object.haveUpdateCachedSize = false; // Object assignment. TS_ASSERT(gui.GetScriptInterface()->LoadGlobalScriptFile(L"gui/settings/cguisize/objectassign.js")); TS_ASSERT_EQUALS(setting->GetMutable().pixel, (CRect{10, 2, 20, 20})); TS_ASSERT_EQUALS(setting->GetMutable().percent, (CRect{4, 0, 0, 20})); - TS_ASSERT_EQUALS(object.haveUpdateCachedSize, false); - - // Force update of cached size. - object.GetComputedSize(); - object.haveUpdateCachedSize = false; // assign TS_ASSERT(gui.GetScriptInterface()->LoadGlobalScriptFile(L"gui/settings/cguisize/assign.js")); TS_ASSERT_EQUALS(setting->GetMutable().pixel, (CRect{3, 0, 0, 2})); TS_ASSERT_EQUALS(setting->GetMutable().percent, (CRect{0, 0, 0, 0})); - TS_ASSERT_EQUALS(object.haveUpdateCachedSize, true); + + TS_ASSERT(!object.cachedSizeRecalculated); + // Call the getComputedSize method on it, which should finally recalculate the dirty (cached) actual size in + // order to return an up-to-date value. + TS_ASSERT(gui.GetScriptInterface()->LoadGlobalScriptFile(L"gui/settings/cguisize/getcomputedsize.js")); + TS_ASSERT(object.cachedSizeRecalculated); } }; diff --git a/source/pch/gui/precompiled.h b/source/pch/gui/precompiled.h index 402626fa77..3d9bec2766 100644 --- a/source/pch/gui/precompiled.h +++ b/source/pch/gui/precompiled.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ #include "lib/precompiled.h" // common precompiled header #if MSC_VERSION -# pragma warning(disable:4250) // "inherits 'IGUITextOwner::IGUITextOwner::UpdateCachedSize' via dominance" +# pragma warning(disable:4250) // "inherits 'IGUITextOwner::IGUITextOwner::HandleSizeChanged' via dominance" #endif #if CONFIG_ENABLE_PCH