diff options
author | Caolán McNamara <caolanm@redhat.com> | 2012-08-23 15:18:14 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2012-09-28 08:48:38 +0100 |
commit | 7e1a1d4c846946c6c97078149f176e90438387de (patch) | |
tree | e7994c6fb9624df91d8458d80ab40563456a40ad | |
parent | e1f31827afa040487a6f72e182947fa852b691ac (diff) |
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
-rw-r--r-- | vcl/inc/vcl/layout.hxx | 5 | ||||
-rw-r--r-- | vcl/inc/vcl/tabctrl.hxx | 13 | ||||
-rw-r--r-- | vcl/source/control/tabctrl.cxx | 105 | ||||
-rw-r--r-- | vcl/source/window/layout.cxx | 53 | ||||
-rw-r--r-- | vcl/source/window/window2.cxx | 38 |
5 files changed, 134 insertions, 80 deletions
diff --git a/vcl/inc/vcl/layout.hxx b/vcl/inc/vcl/layout.hxx index 42071ce4f4cd..c7af5b95bff4 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 1710ec84d0cc..cc3d78b1124e 100644 --- a/vcl/inc/vcl/tabctrl.hxx +++ b/vcl/inc/vcl/tabctrl.hxx @@ -66,6 +66,7 @@ private: sal_Bool mbRestoreHelpId; sal_Bool mbRestoreUnqId; sal_Bool mbSmallInvalidate; + bool mbLayoutDirty; Link maActivateHdl; Link maDeactivateHdl; @@ -195,6 +196,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 ff680ba60a9a..46bfbbd1d4bb 100644 --- a/vcl/source/control/tabctrl.cxx +++ b/vcl/source/control/tabctrl.cxx @@ -101,6 +101,8 @@ struct ImplTabCtrlData void TabControl::ImplInit( Window* pParent, WinBits nStyle ) { + mbLayoutDirty = true; + if ( !(nStyle & WB_NOTABSTOP) ) nStyle |= WB_TABSTOP; if ( !(nStyle & WB_NOGROUP) ) @@ -1225,7 +1227,7 @@ void TabControl::ImplPaint( const Rectangle& rRect, bool bLayout ) // ----------------------------------------------------------------------- -void TabControl::Resize() +void TabControl::setAllocation(const Size &rAllocation) { ImplFreeLayoutData(); @@ -1249,7 +1251,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 ) @@ -1282,6 +1284,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()); } // ----------------------------------------------------------------------- @@ -2125,57 +2150,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 67b4af8f5b1a..2290edd5a410 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 9b51446260dd..5e27f5eed9e7 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 |