After the first call to BView::InvalidateLayout() further invocations don't

invoke the layout's InvalidateLayout() anymore. This could cause problems when
the layout caches layout related information and also updates those on calls
other than LayoutView(). A call to such a method after an InvalidateLayout()
would mark the cached info valid and the layout would use the cached info
until the first InvalidateLayout() after the next LayoutView(), even if
BView::InvalidateLayout() had been called again in the meantime.

* Introduced a new method BView::ResetLayoutInvalidation(), which must be
  called by layout implementations whenever they have updated their cached
  information and need further InvalidateLayout() notifications.
* Adjusted the existing layout implementations to use the method.

Fixes bug #4047.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31316 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-06-29 14:18:12 +00:00
parent 23eb9a9e82
commit a0747aad3b
5 changed files with 45 additions and 12 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2006, Haiku.
* Copyright 2001-2009, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -532,6 +532,7 @@ public:
void EnableLayoutInvalidation();
void DisableLayoutInvalidation();
bool IsLayoutValid() const;
void ResetLayoutInvalidation();
BLayoutContext* LayoutContext() const;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* Copyright 2006-2009, Ingo Weinhold <ingo_weinhold@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@ -54,7 +54,7 @@ BCardLayout::SetVisibleItem(BLayoutItem* item)
if (item != NULL && IndexOfItem(item) < 0)
return;
if (fVisibleItem != NULL)
fVisibleItem->SetVisible(false);
@ -107,7 +107,7 @@ BCardLayout::HasHeightForWidth()
if (ItemAt(i)->HasHeightForWidth())
return true;
}
return false;
}
@ -157,7 +157,7 @@ void
BCardLayout::InvalidateLayout()
{
BLayout::InvalidateLayout();
fMinMaxValid = false;
}
@ -231,6 +231,9 @@ BCardLayout::_ValidateMinMax()
fPreferred.height = max_c(fPreferred.height, fMin.height);
fPreferred.width = min_c(fPreferred.width, fMax.width);
fPreferred.height = min_c(fPreferred.height, fMax.height);
fMinMaxValid = true;
if (BView* view = View())
view->ResetLayoutInvalidation();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* Copyright 2006-2009, Ingo Weinhold <ingo_weinhold@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@ -1147,6 +1147,9 @@ BSplitLayout::_ValidateMinMax()
fHorizontalLayoutInfo = fHorizontalLayouter->CreateLayoutInfo();
if (fHeightForWidthItems.IsEmpty())
fVerticalLayoutInfo = fVerticalLayouter->CreateLayoutInfo();
if (BView* view = View())
view->ResetLayoutInvalidation();
}
// _InternalGetHeightForWidth

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* Copyright 2006-2009, Ingo Weinhold <ingo_weinhold@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@ -448,6 +448,9 @@ void
BTwoDimensionalLayout::_ValidateMinMax()
{
fLocalLayouter->ValidateMinMax();
if (BView* view = View())
view->ResetLayoutInvalidation();
}
// _CurrentLayoutContext

View File

@ -6,7 +6,7 @@
* Adrian Oanca <adioanca@cotty.iren.ro>
* Axel Dörfler, axeld@pinc-software.de
* Stephan Aßmus <superstippi@gmx.de>
* Ingo Weinhold <bonefish@cs.tu-berlin.de>
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#include <View.h>
@ -323,7 +323,8 @@ struct BView::LayoutData {
fLayoutInvalidationDisabled(0),
fLayout(NULL),
fLayoutContext(NULL),
fLayoutValid(true), // <- TODO: Rethink this!
fLayoutValid(true), // TODO: Rethink these initial values!
fMinMaxValid(true), //
fLayoutInProgress(false),
fNeedsRelayout(true)
{
@ -337,6 +338,7 @@ struct BView::LayoutData {
BLayout* fLayout;
BLayoutContext* fLayoutContext;
bool fLayoutValid;
bool fMinMaxValid;
bool fLayoutInProgress;
bool fNeedsRelayout;
};
@ -4489,12 +4491,13 @@ BView::GetLayout() const
void
BView::InvalidateLayout(bool descendants)
{
if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress
if (fLayoutData->fMinMaxValid && !fLayoutData->fLayoutInProgress
&& fLayoutData->fLayoutInvalidationDisabled == 0) {
if (fParent && fParent->fLayoutData->fLayoutValid)
if (fParent && fParent->fLayoutData->fMinMaxValid)
fParent->InvalidateLayout(false);
fLayoutData->fLayoutValid = false;
fLayoutData->fMinMaxValid = false;
if (fLayoutData->fLayout)
fLayoutData->fLayout->InvalidateLayout();
@ -4536,6 +4539,25 @@ BView::IsLayoutValid() const
}
/*! \brief Service call for BLayout derived classes reenabling
InvalidateLayout() notifications.
BView::InvalidateLayout() invokes InvalidateLayout() on its layout the first
time, but suppresses further calls until Layout()/Relayout() has been
invoked. This method will reenable the notification for the next call of
BView::InvalidateLayout().
If the layout caches internal layout information and updates those
information also in methods other than LayoutView(), it has to invoke this
method, when it has done so, since otherwise the information might become
obsolete without the layout noticing.
*/
void
BView::ResetLayoutInvalidation()
{
fLayoutData->fMinMaxValid = true;
}
BLayoutContext*
BView::LayoutContext() const
{
@ -4594,6 +4616,7 @@ BView::_Layout(bool force, BLayoutContext* context)
fLayoutData->fLayoutInProgress = false;
fLayoutData->fLayoutValid = true;
fLayoutData->fMinMaxValid = true;
fLayoutData->fNeedsRelayout = false;
// layout children