vcl/inc/vcl/layout.hxx | 5 + vcl/inc/vcl/tabctrl.hxx | 13 +++++ vcl/source/control/tabctrl.cxx | 105 ++++++++++++++++++++++++----------------- vcl/source/window/layout.cxx | 53 ++++++++------------ vcl/source/window/window2.cxx | 38 ++++++++++++-- 5 files changed, 134 insertions(+), 80 deletions(-)
New commits: commit 8a2a5d01e8e8e25525d5873ca5caecbac5946a03 Author: Caolán McNamara <[email protected]> Date: Thu Aug 23 15:18:14 2012 +0100 we can need to redo the layout even when the sizes don't change i.e. container remains the same size, but something inside it has disappeared, requiring contents to be readjusted We still want to minimize recalculations, so mark parent containers as dirty on queue_resize of a widget and we can retain the layout tree of the clean ones and just move them into their new positions as big fat blocks Change-Id: I8c5d9b836b48c98765b5cc41be72eaa2913ae7d8 diff --git a/vcl/inc/vcl/layout.hxx b/vcl/inc/vcl/layout.hxx index 42071ce..c7af5b9 100644 --- a/vcl/inc/vcl/layout.hxx +++ b/vcl/inc/vcl/layout.hxx @@ -52,11 +52,16 @@ public: { return m_nBorderWidth; } + void markLayoutDirty() + { + m_bLayoutDirty = true; + } protected: virtual Size calculateRequisition() const = 0; virtual void setAllocation(const Size &rAllocation) = 0; private: int m_nBorderWidth; + bool m_bLayoutDirty; }; class VCL_DLLPUBLIC VclBox : public VclContainer diff --git a/vcl/inc/vcl/tabctrl.hxx b/vcl/inc/vcl/tabctrl.hxx index 7d9257e..c8c92c6 100644 --- a/vcl/inc/vcl/tabctrl.hxx +++ b/vcl/inc/vcl/tabctrl.hxx @@ -67,6 +67,7 @@ private: sal_Bool mbRestoreHelpId; sal_Bool mbRestoreUnqId; sal_Bool mbSmallInvalidate; + bool mbLayoutDirty; Link maActivateHdl; Link maDeactivateHdl; @@ -197,6 +198,18 @@ public: // rename nOldId to nNewId); void ReassignPageId(sal_uInt16 nOldId, sal_uInt16 nNewId); + + using Control::SetPosSizePixel; + virtual void SetPosSizePixel(const Point& rNewPos, const Size& rNewSize); + virtual void SetSizePixel(const Size& rNewSize); + + Size calculateRequisition() const; + void setAllocation(const Size &rAllocation); + + void markLayoutDirty() + { + mbLayoutDirty = true; + } }; #endif // _SV_TABCTRL_HXX diff --git a/vcl/source/control/tabctrl.cxx b/vcl/source/control/tabctrl.cxx index 11ea115..9a3e2f9 100644 --- a/vcl/source/control/tabctrl.cxx +++ b/vcl/source/control/tabctrl.cxx @@ -102,6 +102,8 @@ struct ImplTabCtrlData void TabControl::ImplInit( Window* pParent, WinBits nStyle ) { + mbLayoutDirty = true; + if ( !(nStyle & WB_NOTABSTOP) ) nStyle |= WB_TABSTOP; if ( !(nStyle & WB_NOGROUP) ) @@ -1238,7 +1240,7 @@ void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout ) // ----------------------------------------------------------------------- -void TabControl::Resize() +void TabControl::setAllocation(const Size &rAllocation) { ImplFreeLayoutData(); @@ -1262,7 +1264,7 @@ void TabControl::Resize() // Aktuelle TabPage resizen/positionieren sal_Bool bTabPage = ImplPosCurTabPage(); // Feststellen, was invalidiert werden muss - Size aNewSize = Control::GetOutputSizePixel(); + Size aNewSize = rAllocation; long nNewWidth = aNewSize.Width(); for( std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin(); it != mpTabCtrlData->maItemList.end(); ++it ) @@ -1295,6 +1297,29 @@ void TabControl::Resize() else Invalidate(); } + + mbLayoutDirty = false; +} + +void TabControl::SetPosSizePixel(const Point& rNewPos, const Size& rNewSize) +{ + Window::SetPosSizePixel(rNewPos, rNewSize); + //if size changed, TabControl::Resize got called already + if (mbLayoutDirty) + setAllocation(rNewSize); +} + +void TabControl::SetSizePixel(const Size& rNewSize) +{ + Window::SetSizePixel(rNewSize); + //if size changed, TabControl::Resize got called already + if (mbLayoutDirty) + setAllocation(rNewSize); +} + +void TabControl::Resize() +{ + setAllocation(Control::GetOutputSizePixel()); } // ----------------------------------------------------------------------- @@ -2142,57 +2167,55 @@ Point TabControl::GetItemsOffset() const // ----------------------------------------------------------------------- -Size TabControl::GetOptimalSize(WindowSizeType eType) const +Size TabControl::calculateRequisition() const { - switch (eType) { - case WINDOWSIZE_MINIMUM: - return mpTabCtrlData ? mpTabCtrlData->maMinSize : Size(); + Size aOptimalPageSize(0, 0); + long nTabLabelsBottom = 0; + long nTotalTabLabelWidths = 0; - default: + for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin(); + it != mpTabCtrlData->maItemList.end(); ++it ) { - Size aOptimalPageSize(0, 0); - long nTabLabelsBottom = 0; - long nTotalTabLabelWidths = 0; + Size aPageSize; + const TabPage *pPage = it->mpTabPage; + //it's a real nuisance if the page is not inserted yet :-( + if (pPage) + aPageSize = pPage->GetOptimalSize(WINDOWSIZE_PREFERRED); - for( std::vector< ImplTabItem >::const_iterator it = mpTabCtrlData->maItemList.begin(); - it != mpTabCtrlData->maItemList.end(); ++it ) - { - Size aPageSize; - const TabPage *pPage = it->mpTabPage; - if (pPage) - aPageSize = pPage->GetOptimalSize(eType); - else - fprintf(stderr, "nuisance, page not inserted yet :-(\n"); + if (aPageSize.Width() > aOptimalPageSize.Width()) + aOptimalPageSize.Width() = aPageSize.Width(); + if (aPageSize.Height() > aOptimalPageSize.Height()) + aOptimalPageSize.Height() = aPageSize.Height(); - if (aPageSize.Width() > aOptimalPageSize.Width()) - aOptimalPageSize.Width() = aPageSize.Width(); - if (aPageSize.Height() > aOptimalPageSize.Height()) - aOptimalPageSize.Height() = aPageSize.Height(); + TabControl* pThis = const_cast<TabControl*>(this); - TabControl* pThis = const_cast<TabControl*>(this); + sal_uInt16 nPos = it - mpTabCtrlData->maItemList.begin(); + Rectangle aTabRect = pThis->ImplGetTabRect(nPos, aPageSize.Width(), aPageSize.Height()); + if (aTabRect.Bottom() > nTabLabelsBottom) + nTabLabelsBottom = aTabRect.Bottom(); - sal_uInt16 nPos = it - mpTabCtrlData->maItemList.begin(); - Rectangle aTabRect = pThis->ImplGetTabRect(nPos, aPageSize.Width(), aPageSize.Height()); - if (aTabRect.Bottom() > nTabLabelsBottom) - nTabLabelsBottom = aTabRect.Bottom(); + ImplTabItem* pItem = const_cast<ImplTabItem*>(&(*it)); + Size aTabSize = pThis->ImplGetItemSize(pItem, LONG_MAX); + nTotalTabLabelWidths += aTabSize.Width(); + } - ImplTabItem* pItem = const_cast<ImplTabItem*>(&(*it)); - Size aTabSize = pThis->ImplGetItemSize(pItem, LONG_MAX); - nTotalTabLabelWidths += aTabSize.Width(); - } + Size aOptimalSize(aOptimalPageSize); + aOptimalSize.Height() += nTabLabelsBottom; - Size aOptimalSize(aOptimalPageSize); - aOptimalSize.Height() += nTabLabelsBottom; + if (nTotalTabLabelWidths > aOptimalSize.Width()) + aOptimalSize.Width() = nTotalTabLabelWidths; - if (nTotalTabLabelWidths > aOptimalSize.Width()) - aOptimalSize.Width() = nTotalTabLabelWidths; + aOptimalSize.Width() += TAB_OFFSET * 2; + aOptimalSize.Height() += TAB_OFFSET * 2; - aOptimalSize.Width() += TAB_OFFSET * 2; - aOptimalSize.Height() += TAB_OFFSET * 2; + return aOptimalSize; +} - return aOptimalSize; - } - } +Size TabControl::GetOptimalSize(WindowSizeType eType) const +{ + if (eType == WINDOWSIZE_MINIMUM) + return mpTabCtrlData ? mpTabCtrlData->maMinSize : Size(); + return calculateRequisition(); } // ----------------------------------------------------------------------- diff --git a/vcl/source/window/layout.cxx b/vcl/source/window/layout.cxx index 67b4af8..2290edd 100644 --- a/vcl/source/window/layout.cxx +++ b/vcl/source/window/layout.cxx @@ -33,6 +33,7 @@ VclContainer::VclContainer(Window *pParent) : Window(WINDOW_CONTAINER) , m_nBorderWidth(0) + , m_bLayoutDirty(true) { ImplInit(pParent, 0, NULL); } @@ -67,8 +68,11 @@ void VclContainer::SetPosSizePixel(const Point& rAllocPos, const Size& rAllocati else if (bSizeChanged) Window::SetSizePixel(aAllocation); - if (bSizeChanged) + if (m_bLayoutDirty || bSizeChanged) + { setAllocation(aAllocation); + m_bLayoutDirty = false; + } } void VclContainer::SetPosPixel(const Point& rAllocPos) @@ -86,11 +90,13 @@ void VclContainer::SetSizePixel(const Size& rAllocation) Size aAllocation = rAllocation; aAllocation.Width() -= m_nBorderWidth*2; aAllocation.Height() -= m_nBorderWidth*2; - - if (aAllocation != GetSizePixel()) - { + bool bSizeChanged = aAllocation != GetSizePixel(); + if (bSizeChanged) Window::SetSizePixel(aAllocation); + if (m_bLayoutDirty || bSizeChanged) + { setAllocation(aAllocation); + m_bLayoutDirty = false; } } @@ -143,22 +149,6 @@ Size VclBox::calculateRequisition() const return aSize; } -namespace -{ - //avoid redraws when size/pos is unchanged - void setPosSizePixel(Window &rWindow, const Point& rAllocPos, const Size& rAllocation) - { - bool bPosChanged = rAllocPos != rWindow.GetPosPixel(); - bool bSizeChanged = rAllocation != rWindow.GetSizePixel(); - if (bPosChanged && bSizeChanged) - rWindow.SetPosSizePixel(rAllocPos, rAllocation); - else if (bPosChanged) - rWindow.SetPosPixel(rAllocPos); - else if (bSizeChanged) - rWindow.SetSizePixel(rAllocation); - } -} - void VclBox::setAllocation(const Size &rAllocation) { //SetBackground( Color(0x00, 0xFF, 0x00) ); @@ -263,7 +253,7 @@ void VclBox::setAllocation(const Size &rAllocation) getPrimaryDimension(aBoxSize)); } - setPosSizePixel(*pChild, aChildPos, aChildSize); + pChild->SetPosSizePixel(aChildPos, aChildSize); } } } @@ -390,7 +380,7 @@ void VclButtonBox::setAllocation(const Size &rAllocation) setSecondaryDimension(aChildSize, getSecondaryDimension(aSize)); setPrimaryDimension(aChildSize, nHomogeneousDimension); - setPosSizePixel(*pChild, aPos, aChildSize); + pChild->SetPosSizePixel(aPos, aChildSize); nPrimaryCoordinate = getPrimaryCoordinate(aPos); setPrimaryCoordinate(aPos, nPrimaryCoordinate + nHomogeneousDimension + m_nSpacing); @@ -723,7 +713,7 @@ void VclGrid::setAllocation(const Size& rAllocation) break; } - setPosSizePixel(*pChild, aChildPos, aChildSize); + pChild->SetPosSizePixel(aChildPos, aChildSize); } aAllocPos.Y() += aHeights[y].m_nValue + get_row_spacing(); } @@ -786,7 +776,7 @@ void VclBin::setAllocation(const Size &rAllocation) { Window *pChild = get_child(); if (pChild && pChild->IsVisible()) - setPosSizePixel(*pChild, Point(0, 0), rAllocation); + pChild->SetPosSizePixel(Point(0, 0), rAllocation); } //To-Do, hook a DecorationView into VclFrame ? @@ -839,13 +829,13 @@ void VclFrame::setAllocation(const Size &rAllocation) Size aLabelSize = pLabel->GetOptimalSize(WINDOWSIZE_PREFERRED); aLabelSize.Height() = std::min(aLabelSize.Height(), aAllocation.Height()); aLabelSize.Width() = std::min(aLabelSize.Width(), aAllocation.Width()); - setPosSizePixel(*pLabel, aChildPos, aLabelSize); + pLabel->SetPosSizePixel(aChildPos, aLabelSize); aAllocation.Height() -= aLabelSize.Height(); aChildPos.Y() += aLabelSize.Height(); } if (pChild && pChild->IsVisible()) - setPosSizePixel(*pChild, aChildPos, aAllocation); + pChild->SetPosSizePixel(aChildPos, aAllocation); } Size VclAlignment::calculateRequisition() const @@ -876,7 +866,7 @@ void VclAlignment::setAllocation(const Size &rAllocation) aAllocation.Width() = rAllocation.Width() - (m_nLeftPadding + m_nRightPadding); aAllocation.Height() = rAllocation.Height() - (m_nTopPadding + m_nBottomPadding); - setPosSizePixel(*pChild, aChildPos, aAllocation); + pChild->SetPosSizePixel(aChildPos, aAllocation); } bool VclAlignment::set_property(const rtl::OString &rKey, const rtl::OString &rValue) @@ -980,7 +970,7 @@ void VclExpander::setAllocation(const Size &rAllocation) long nExtraExpanderHeight = aExpanderSize.Height() - aButtonSize.Height(); Point aButtonPos(aChildPos.X(), aChildPos.Y() + nExtraExpanderHeight/2); - setPosSizePixel(m_aDisclosureButton, aButtonPos, aButtonSize); + m_aDisclosureButton.SetPosSizePixel(aButtonPos, aButtonSize); if (pLabel && pLabel->IsVisible()) { @@ -990,7 +980,7 @@ void VclExpander::setAllocation(const Size &rAllocation) long nExtraLabelHeight = aExpanderSize.Height() - aLabelSize.Height(); Point aLabelPos(aChildPos.X() + aButtonSize.Width(), aChildPos.Y() + nExtraLabelHeight/2); - setPosSizePixel(*pLabel, aLabelPos, aLabelSize); + pLabel->SetPosSizePixel(aLabelPos, aLabelSize); } aAllocation.Height() -= aExpanderSize.Height(); @@ -1000,7 +990,7 @@ void VclExpander::setAllocation(const Size &rAllocation) { if (!m_aDisclosureButton.IsChecked()) aAllocation = Size(); - setPosSizePixel(*pChild, aChildPos, aAllocation); + pChild->SetPosSizePixel(aChildPos, aAllocation); } } @@ -1021,11 +1011,10 @@ IMPL_LINK( VclExpander, ClickHdl, DisclosureButton*, pBtn ) if (pChild) { pChild->Show(pBtn->IsChecked()); + queue_resize(); Dialog* pResizeDialog = m_bResizeTopLevel ? GetParentDialog() : NULL; if (pResizeDialog) pResizeDialog->setInitialLayoutSize(); - else - queue_resize(); } return 0; } diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx index 4a38819..5cdf4d3 100644 --- a/vcl/source/window/window2.cxx +++ b/vcl/source/window/window2.cxx @@ -41,6 +41,7 @@ #include <vcl/window.hxx> #include <vcl/scrbar.hxx> #include <vcl/dockwin.hxx> +#include <vcl/tabctrl.hxx> #include <window.h> #include <outfont.hxx> @@ -1749,16 +1750,39 @@ void Window::SetBackgroundBitmap( const BitmapEx& rBitmapEx ) } } -//When a widget wants to renegotiate size, get toplevel parent dialog and call -//resize on it. Maybe better to just find direct parent and if its a container -//chain it upwards one step at a time until a dialog is found. +//When a widget wants to renegotiate layout, get toplevel parent dialog and call +//resize on it. Mark all intermediate containers (or container-alike) widgets +//as dirty for the size remains unchanged, but layout changed circumstances void Window::queue_resize() { - Dialog *pParent = GetParentDialog(); - if (!pParent || pParent == this) + Dialog *pDialog = NULL; + + Window *pWindow = this; + + while( pWindow ) + { + if (pWindow->GetType() == WINDOW_CONTAINER) + { + VclContainer *pContainer = static_cast<VclContainer*>(pWindow); + pContainer->markLayoutDirty(); + } + else if (pWindow->GetType() == WINDOW_TABCONTROL) + { + TabControl *pTabControl = static_cast<TabControl*>(pWindow); + pTabControl->markLayoutDirty(); + } + else if (pWindow->IsDialog()) + { + pDialog = dynamic_cast<Dialog*>(pWindow); + break; + } + pWindow = pWindow->GetParent(); + } + + if (!pDialog || pDialog == this) return; - if (pParent->isLayoutEnabled()) - pParent->Resize(); + if (pDialog->isLayoutEnabled()) + pDialog->Resize(); } //We deliberately do not overwrite our maHelpId here
_______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
