Compute actual size of GUI objects lazily
Some checks failed
checkrefs / lfscheck (push) Has been cancelled
checkrefs / checkrefs (push) Has been cancelled
lint / cppcheck (push) Has been cancelled
lint / copyright (push) Has been cancelled
lint / jenkinsfiles (push) Has been cancelled
pre-commit / build (push) Has been cancelled

This shifts the responsibility of updating the actual size more towards
IGUIObject, and enables only ever doing it when the value is actually
needed. This allows us to remove the delay of size changed
notifications, since the value is now already recalculated as
infrequently as possible anyways.

All of that ensures that the actual size (returned by GetActualSize) is
always up-to-date e.g. when reading it from the parent, which was
previously broken.

Fixes #8200
This commit is contained in:
Vantha 2026-03-05 12:31:47 +01:00 committed by Vantha
parent d5384ad742
commit 5a92c22d90
37 changed files with 323 additions and 371 deletions

View file

@ -0,0 +1 @@
testObject.getComputedSize();

View file

@ -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<IGUIObject> CGUI::ConstructObject(const CStr& str)
@ -593,7 +592,7 @@ void CGUI::LoadXmlFile(const VfsPath& Filename, std::unordered_set<VfsPath>& 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);

View file

@ -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();

View file

@ -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;
};

View file

@ -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();
}

View file

@ -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<bool> m_Enabled;
CGUISimpleSetting<bool> m_Hidden;
CGUISimpleSetting<CGUISize> m_Size;

View file

@ -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<IGUIObject*>& IGUIPanel::GetVisibleChildren() const
{
if (m_Drawing)

View file

@ -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<IGUIObject*>& GetVisibleChildren() const;
protected:
CRect m_CachedLayoutActualSize;
virtual void RecalculateActualSize() const;
mutable CRect m_CachedLayoutActualSize;
bool m_Drawing = false;
};

View file

@ -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];
}

View file

@ -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.

View file

@ -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<EAlign> m_TextAlign;
CGUISimpleSetting<EVAlign> m_TextVAlign;

View file

@ -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()

View file

@ -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.

View file

@ -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)
);
}

View file

@ -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()

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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<float>(row + 1) * spacing + m_BufferZone * 2.f > m_CachedActualSize.GetHeight())
if (-scroll + static_cast<float>(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<float>(row + 1) * spacing - m_CachedActualSize.GetHeight() + m_BufferZone * 2.f);
GetScrollBar(0).SetPos(static_cast<float>(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;
}
}

View file

@ -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

View file

@ -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)

View file

@ -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).

View file

@ -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<ICmpRangeManager> 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,

View file

@ -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)

View file

@ -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);
}

View file

@ -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)

View file

@ -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; };

View file

@ -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<float>(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);
}

View file

@ -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);
}

View file

@ -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.

View file

@ -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

View file

@ -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()

View file

@ -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<float>(val);
wrapper->Set(wrapper->GetMutable(), true); // causes CGUISimpleSetting to actually process the change
args.rval().setUndefined();
wrapper->DeferSettingChange();
return true;
}

View file

@ -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<IGUIObject>::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);

View file

@ -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<CGUISize>* GetSizeSetting() const
@ -73,7 +73,7 @@ public:
return static_cast<CGUISimpleSetting<CGUISize>*>(m_Settings.at("size"));
}
bool haveUpdateCachedSize{false};
mutable bool cachedSizeRecalculated{false};
};
void setUp()
@ -139,7 +139,6 @@ public:
CGUISimpleSetting<CGUISize>* 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);
}
};

View file

@ -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