Index: src/preferences/keymap/KeymapWindow.cpp =================================================================== --- src/preferences/keymap/KeymapWindow.cpp (revision 38092) +++ src/preferences/keymap/KeymapWindow.cpp (working copy) @@ -508,7 +508,8 @@ .Add(new BStringView("system", B_TRANSLATE("System:"))) .Add(systemScroller, 3) .Add(new BStringView("user", B_TRANSLATE("User:"))) - .Add(userScroller); + .Add(userScroller) + .TopView(); } Index: src/preferences/backgrounds/BackgroundsView.cpp =================================================================== --- src/preferences/backgrounds/BackgroundsView.cpp (revision 38092) +++ src/preferences/backgrounds/BackgroundsView.cpp (working copy) @@ -144,7 +144,7 @@ .AddGroup(B_VERTICAL, 20) .AddGroup(B_HORIZONTAL, 0) .AddGlue() - .AddGrid(0, 0) + .AddGrid(0, 0, 1) .Add(fTopLeft, 0, 0) .Add(fTop, 1, 0) .Add(fTopRight, 2, 0) Index: src/libs/alm/BALMLayout.cpp =================================================================== --- src/libs/alm/BALMLayout.cpp (revision 38092) +++ src/libs/alm/BALMLayout.cpp (working copy) @@ -20,7 +20,8 @@ * Creates new layout engine. */ BALMLayout::BALMLayout() - : BLayout(), + : + BAbstractLayout(), LinearSpec() { fLayoutStyle = FIT_TO_SIZE; @@ -189,7 +190,7 @@ { InvalidateLayout(); if (content != NULL) - View()->AddChild(content); + TargetView()->AddChild(content); Area* area = new Area(this, left, top, right, bottom, content, minContentSize); fAreas->AddItem(area); return area; @@ -211,7 +212,7 @@ { InvalidateLayout(); if (content != NULL) - View()->AddChild(content); + TargetView()->AddChild(content); Area* area = new Area(this, row, column, content, minContentSize); fAreas->AddItem(area); return area; @@ -234,7 +235,7 @@ { InvalidateLayout(); if (content != NULL) - View()->AddChild(content); + TargetView()->AddChild(content); Area* area = new Area(this, left, top, right, bottom, content, BSize(0, 0)); area->SetDefaultBehavior(); area->SetAutoPreferredContentSize(false); @@ -256,7 +257,7 @@ { InvalidateLayout(); if (content != NULL) - View()->AddChild(content); + TargetView()->AddChild(content); Area* area = new Area(this, row, column, content, BSize(0, 0)); area->SetDefaultBehavior(); area->SetAutoPreferredContentSize(false); @@ -435,9 +436,10 @@ /** - * Sets and gets minimum size. + * Gets minimum size. */ -BSize BALMLayout::MinSize() { +BSize +BALMLayout::BaseMinSize() { if (fMinSize == Area::kUndefinedSize) fMinSize = CalculateMinSize(); return fMinSize; @@ -445,10 +447,10 @@ /** - * Sets and gets maximum size. + * Gets maximum size. */ BSize -BALMLayout::MaxSize() +BALMLayout::BaseMaxSize() { if (fMaxSize == Area::kUndefinedSize) fMaxSize = CalculateMaxSize(); @@ -457,10 +459,10 @@ /** - * Sets and gets preferred size. + * Gets preferred size. */ BSize -BALMLayout::PreferredSize() +BALMLayout::BasePreferredSize() { if (fPreferredSize == Area::kUndefinedSize) fPreferredSize = CalculatePreferredSize(); @@ -472,7 +474,7 @@ * Gets the alignment. */ BAlignment -BALMLayout::Alignment() +BALMLayout::BaseAlignment() { BAlignment alignment; alignment.SetHorizontal(B_ALIGN_HORIZONTAL_CENTER); @@ -492,7 +494,7 @@ /** - * Sets whether the height of the layout depends on its width. + * Gets height constraints for a given width. */ void BALMLayout::GetHeightForWidth(float width, float* min, float* max, float* preferred) {} @@ -503,8 +505,9 @@ * Resets minimum/maximum/preferred size. */ void -BALMLayout::InvalidateLayout() +BALMLayout::InvalidateLayout(bool children) { + BLayout::InvalidateLayout(children); fMinSize = Area::kUndefinedSize; fMaxSize = Area::kUndefinedSize; fPreferredSize = Area::kUndefinedSize; @@ -516,25 +519,28 @@ * If no layout specification is given, a specification is reverse engineered automatically. */ void -BALMLayout::LayoutView() +BALMLayout::DerivedLayoutItems() { + // TODO: modify to allow for viewlessness // make sure that layout events occuring during layout are ignored - // i.e. activated is set to false during layout caluclation + // i.e. activated is set to false during layout calculation if (!fActivated) return; fActivated = false; - if (View() == NULL) + if (Owner() == NULL) return; // reverse engineer a layout specification if none was given //~ if (this == NULL) RecoverLayout(View()); // if the layout engine is set to fit the GUI to the given size, - // then the given size is enforced by setting absolute positions for Right and Bottom + // then the given size is enforced by setting absolute positions + // for Right and Bottom if (fLayoutStyle == FIT_TO_SIZE) { - Right()->SetRange(View()->Bounds().Width(), View()->Bounds().Width()); - Bottom()->SetRange(View()->Bounds().Height(), View()->Bounds().Height()); + BSize layoutSize(LayoutArea().Size()); + Right()->SetRange(layoutSize.width, layoutSize.width); + Bottom()->SetRange(layoutSize.height, layoutSize.height); } SolveLayout(); @@ -554,7 +560,7 @@ // change the size of the GUI according to the calculated size // if the layout engine was configured to do so if (fLayoutStyle == ADJUST_SIZE) { - View()->ResizeTo(floor(Right()->Value() - Left()->Value() + 0.5), + Owner()->ResizeTo(floor(Right()->Value() - Left()->Value() + 0.5), floor(Bottom()->Value() - Top()->Value() + 0.5)); } Index: src/kits/interface/AbstractLayout.cpp =================================================================== --- src/kits/interface/AbstractLayout.cpp (revision 0) +++ src/kits/interface/AbstractLayout.cpp (revision 0) @@ -0,0 +1,468 @@ +/* + * Copyright 2010, Haiku, Inc. + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include + + +namespace { + const char* const kSizesField = "BAbstractLayout:sizes"; + // kSizesField == {min, max, preferred} + const char* const kAlignmentField = "BAbstractLayout:alignment"; + const char* const kFrameField = "BAbstractLayout:frame"; + const char* const kVisibleField = "BAbstractLayout:visible"; + + enum proxy_type { VIEW_PROXY_TYPE, DATA_PROXY_TYPE }; +} + + +struct BAbstractLayout::Proxy { + + Proxy(proxy_type type) + : + type(type) + { + } + + virtual BSize MinSize() const = 0; + virtual void SetMinSize(const BSize&) = 0; + + virtual BSize MaxSize() const = 0; + virtual void SetMaxSize(const BSize&) = 0; + + virtual BSize PreferredSize() const = 0; + virtual void SetPreferredSize(const BSize&) = 0; + + virtual BAlignment Alignment() const = 0; + virtual void SetAlignment(const BAlignment&) = 0; + + virtual BRect Frame() const = 0; + virtual void SetFrame(const BRect& frame) = 0; + + virtual bool IsVisible(bool ancestorHidden) const = 0; + virtual void SetVisible(bool visible) = 0; + + virtual status_t AddDataToArchive(BMessage* archive, + bool ancestorHidden) = 0; + virtual status_t RestoreDataFromArchive(const BMessage* archive) = 0; + + proxy_type type; +}; + + +struct BAbstractLayout::DataProxy : Proxy { + + DataProxy() + : + Proxy(DATA_PROXY_TYPE), + minSize(), + maxSize(), + preferredSize(), + alignment(), + frame(-1, -1, 0, 0), + visible(true) + { + } + + BSize MinSize() const + { + return minSize; + } + + void SetMinSize(const BSize& min) + { + minSize = min; + } + + BSize MaxSize() const + { + return maxSize; + } + + void SetMaxSize(const BSize& max) + { + maxSize = max; + } + + BSize PreferredSize() const + { + return preferredSize; + } + + void SetPreferredSize(const BSize& preferred) + { + preferredSize = preferred; + } + + BAlignment Alignment() const + { + return this->alignment; + } + + void SetAlignment(const BAlignment& align) + { + this->alignment = align; + } + + BRect Frame() const + { + return frame; + } + + void SetFrame(const BRect& frame) + { + if (frame == this->frame) + return; + this->frame = frame; + } + + bool IsVisible(bool) const + { + return visible; + } + + void SetVisible(bool visible) + { + this->visible = visible; + } + + status_t AddDataToArchive(BMessage* archive, bool ancestorHidden) + { + status_t err = archive->AddSize(kSizesField, minSize); + if (err == B_OK) + err = archive->AddSize(kSizesField, maxSize); + if (err == B_OK) + err = archive->AddSize(kSizesField, preferredSize); + if (err == B_OK) + err = archive->AddAlignment(kAlignmentField, alignment); + if (err == B_OK) + err = archive->AddRect(kFrameField, frame); + if (err == B_OK) + err = archive->AddBool(kVisibleField, visible); + + return err; + } + + status_t RestoreDataFromArchive(const BMessage* archive) + { + status_t err = archive->FindSize(kSizesField, 0, &minSize); + if (err == B_OK) + err = archive->FindSize(kSizesField, 1, &maxSize); + if (err == B_OK) + err = archive->FindSize(kSizesField, 2, &preferredSize); + if (err == B_OK) + err = archive->FindAlignment(kAlignmentField, &alignment); + if (err == B_OK) + err = archive->FindRect(kFrameField, &frame); + if (err == B_OK) + err = archive->FindBool(kVisibleField, &visible); + + return err; + } + + BSize minSize; + BSize maxSize; + BSize preferredSize; + BAlignment alignment; + BRect frame; + bool visible; +}; + + +struct BAbstractLayout::ViewProxy : Proxy { + ViewProxy(BView* target) + : + Proxy(VIEW_PROXY_TYPE), + view(target) + { + } + + BSize MinSize() const + { + return view->ExplicitMinSize(); + } + + void SetMinSize(const BSize& min) + { + view->SetExplicitMinSize(min); + } + + BSize MaxSize() const + { + return view->ExplicitMaxSize(); + } + + void SetMaxSize(const BSize& min) + { + view->SetExplicitMaxSize(min); + } + + BSize PreferredSize() const + { + return view->ExplicitPreferredSize(); + } + + void SetPreferredSize(const BSize& preferred) + { + view->SetExplicitPreferredSize(preferred); + } + + BAlignment Alignment() const + { + return view->ExplicitAlignment(); + } + + void SetAlignment(const BAlignment& alignment) + { + view->SetExplicitAlignment(alignment); + } + + BRect Frame() const + { + return view->Frame(); + } + + void SetFrame(const BRect& frame) + { + view->MoveTo(frame.LeftTop()); + view->ResizeTo(frame.Width(), frame.Height()); + } + + bool IsVisible(bool ancestorsVisible) const + { + int16 showLevel = BView::Private(view).ShowLevel(); + return (showLevel - (ancestorsVisible) ? 0 : 1) <= 0; + } + + void SetVisible(bool visible) + { + // No need to check that we are not re-hiding, that is done + // for us. + if (visible) + view->Show(); + else + view->Hide(); + } + + status_t AddDataToArchive(BMessage* archive, bool ancestorHidden) + { + return B_OK; + } + + status_t RestoreDataFromArchive(const BMessage* archive) + { + return B_OK; + } + + BView* view; +}; + + +BAbstractLayout::BAbstractLayout() + : + fExplicitData(new BAbstractLayout::DataProxy()) +{ +} + + +BAbstractLayout::BAbstractLayout(BMessage* from) + : + BLayout(BUnarchiver::PrepareArchive(from)), + fExplicitData(new DataProxy()) +{ + BUnarchiver(from).Finish(); +} + + +BAbstractLayout::~BAbstractLayout() +{ + delete fExplicitData; +} + + +BSize +BAbstractLayout::MinSize() +{ + return BLayoutUtils::ComposeSize(fExplicitData->MinSize(), BaseMinSize()); +} + + +BSize +BAbstractLayout::MaxSize() +{ + return BLayoutUtils::ComposeSize(fExplicitData->MaxSize(), BaseMaxSize()); +} + + +BSize +BAbstractLayout::PreferredSize() +{ + return BLayoutUtils::ComposeSize(fExplicitData->PreferredSize(), + BasePreferredSize()); +} + + +BAlignment +BAbstractLayout::Alignment() +{ + return BLayoutUtils::ComposeAlignment(fExplicitData->Alignment(), + BaseAlignment()); +} + + +void +BAbstractLayout::SetExplicitMinSize(BSize size) +{ + fExplicitData->SetMinSize(size); +} + + +void +BAbstractLayout::SetExplicitMaxSize(BSize size) +{ + fExplicitData->SetMaxSize(size); +} + + +void +BAbstractLayout::SetExplicitPreferredSize(BSize size) +{ + fExplicitData->SetPreferredSize(size); +} + + +void +BAbstractLayout::SetExplicitAlignment(BAlignment alignment) +{ + fExplicitData->SetAlignment(alignment); +} + + +BSize +BAbstractLayout::BaseMinSize() +{ + return BSize(0, 0); +} + + +BSize +BAbstractLayout::BaseMaxSize() +{ + return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); +} + + +BSize +BAbstractLayout::BasePreferredSize() +{ + return BSize(0, 0); +} + + +BAlignment +BAbstractLayout::BaseAlignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + + +BRect +BAbstractLayout::Frame() +{ + return fExplicitData->Frame(); +} + + +void +BAbstractLayout::SetFrame(BRect frame) +{ + if (frame != fExplicitData->Frame()) { + fExplicitData->SetFrame(frame); + if (!Owner()) + Relayout(); + } +} + + +bool +BAbstractLayout::IsVisible() +{ + return fExplicitData->IsVisible(AncestorsVisible()); +} + + +void +BAbstractLayout::SetVisible(bool visible) +{ + if (visible != fExplicitData->IsVisible(AncestorsVisible())) { + fExplicitData->SetVisible(visible); + if (Layout()) + Layout()->InvalidateLayout(false); + VisibilityChanged(visible); + } +} + + +status_t +BAbstractLayout::Archive(BMessage* into, bool deep) const +{ + BArchiver archiver(into); + status_t err = BLayout::Archive(into, deep); + + return archiver.Finish(err); +} + + +status_t +BAbstractLayout::AllUnarchived(const BMessage* from) +{ + if (Owner()) { + ViewProxy* proxy = dynamic_cast(fExplicitData); + if (!proxy) { + delete fExplicitData; + proxy = new ViewProxy(Owner()); + } + proxy->view = Owner(); + } else { + fExplicitData = new DataProxy(); + return fExplicitData->RestoreDataFromArchive(from); + } + + return BLayout::AllUnarchived(from); +} + + +void +BAbstractLayout::OwnerChanged(BView* was) +{ + if (was) { + static_cast(fExplicitData)->view = Owner(); + return; + } + + delete fExplicitData; + fExplicitData = new ViewProxy(Owner()); +} + + +void +BAbstractLayout::AncestorVisibilityChanged(bool shown) +{ + if (AncestorsVisible() == shown) + return; + + if (BView* owner = Owner()) { + if (shown) + owner->Show(); + else + owner->Hide(); + } + BLayout::AncestorVisibilityChanged(shown); +} + Index: src/kits/interface/ViewLayoutItem.h =================================================================== --- src/kits/interface/ViewLayoutItem.h (revision 38092) +++ src/kits/interface/ViewLayoutItem.h (working copy) @@ -36,15 +36,20 @@ virtual BView* View(); - virtual void InvalidateLayout(); + virtual void InvalidateLayout(bool children = false); + virtual void Relayout(bool immediate = false); virtual status_t Archive(BMessage* into, bool deep = true) const; virtual status_t AllArchived(BMessage* into) const; virtual status_t AllUnarchived(const BMessage* from); static BArchivable* Instantiate(BMessage* from); +protected: + virtual void AncestorVisibilityChanged(bool shown); + private: BView* fView; + int32 fAncestorsVisible; }; #endif // _VIEW_LAYOUT_ITEM_H Index: src/kits/interface/View.cpp =================================================================== --- src/kits/interface/View.cpp (revision 38092) +++ src/kits/interface/View.cpp (working copy) @@ -648,7 +648,7 @@ err = unarchiver.FindObject(kLayoutField, layout); if (err == B_OK && layout) { fFlags |= B_SUPPORTS_LAYOUT; - fLayoutData->fLayout->BLayout::SetView(this); + fLayoutData->fLayout->SetOwner(this); } } @@ -997,7 +997,7 @@ fShowLevel++; if (fShowLevel == 1 && fParent) - fParent->InvalidateLayout(); + _InvalidateParentLayout(); } @@ -1012,7 +1012,7 @@ } if (fShowLevel == 0 && fParent) - fParent->InvalidateLayout(); + _InvalidateParentLayout(); } @@ -4020,7 +4020,7 @@ BView::RemoveSelf() { if (fParent && fParent->fLayoutData->fLayout) - return fParent->fLayoutData->fLayout->RemoveView(this); + return fParent->fLayoutData->fLayout->RemoveViewRecursive(this); return _RemoveSelf(); } @@ -4643,18 +4643,21 @@ if (layout == fLayoutData->fLayout) return; + if (layout && layout->Layout()) + debugger("BView::SetLayout() failed, layout is already in use."); + fFlags |= B_SUPPORTS_LAYOUT; // unset and delete the old layout if (fLayoutData->fLayout) { - fLayoutData->fLayout->SetView(NULL); + fLayoutData->fLayout->SetOwner(NULL); delete fLayoutData->fLayout; } fLayoutData->fLayout = layout; if (fLayoutData->fLayout) { - fLayoutData->fLayout->SetView(this); + fLayoutData->fLayout->SetOwner(this); // add all children int count = CountChildren(); @@ -4676,23 +4679,29 @@ void BView::InvalidateLayout(bool descendants) { + // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n", + // this, descendants, fLayoutData->fLayoutValid, + // fLayoutData->fLayoutInProgress); + if (fLayoutData->fMinMaxValid && !fLayoutData->fLayoutInProgress - && fLayoutData->fLayoutInvalidationDisabled == 0) { - if (fParent && fParent->fLayoutData->fMinMaxValid) - fParent->InvalidateLayout(false); + && fLayoutData->fLayoutInvalidationDisabled == 0) { fLayoutData->fLayoutValid = false; fLayoutData->fMinMaxValid = false; - if (fLayoutData->fLayout) - fLayoutData->fLayout->InvalidateLayout(); - if (descendants) { - int count = CountChildren(); - for (int i = 0; i < count; i++) - ChildAt(i)->InvalidateLayout(descendants); + for (BView* child = fFirstChild; + child; child = child->fNextSibling) { + child->InvalidateLayout(descendants); + } } + if (fLayoutData->fLayout && fLayoutData->fLayout->InvalidationLegal()) + fLayoutData->fLayout->InvalidateLayout(descendants); + else if (!fLayoutData->fLayout && fParent) { + _InvalidateParentLayout(); + } + if (fTopLevelView) { // trigger layout process if (fOwner) @@ -4724,15 +4733,12 @@ } -/*! \brief Service call for BLayout derived classes reenabling +/*! \brief Service call for BView 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 + BLayout & BView will avoid calling InvalidateLayout on views that have + already been invalidated, but if the view caches internal layout information + which it updates in methds other than DoLayout(), it has to invoke this method, when it has done so, since otherwise the information might become obsolete without the layout noticing. */ @@ -4763,6 +4769,8 @@ { if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { fLayoutData->fNeedsRelayout = true; + if (fLayoutData->fLayout) + fLayoutData->fLayout->RequireLayout(); // Layout() is recursive, that is if the parent view is currently laid // out, we don't call layout() on this view, but wait for the parent's @@ -4777,7 +4785,7 @@ BView::DoLayout() { if (fLayoutData->fLayout) - fLayoutData->fLayout->LayoutView(); + fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext()); } @@ -4881,9 +4889,7 @@ fLayoutData->fNeedsRelayout = false; // layout children - int32 childCount = CountChildren(); - for (int32 i = 0; i < childCount; i++) { - BView* child = ChildAt(i); + for(BView* child = fFirstChild; child; child = child->fNextSibling) { if (!child->IsHidden(child)) child->_Layout(force, context); } @@ -4897,6 +4903,34 @@ } +void +BView::_LayoutLeft(BLayout* deleted) +{ + // If our layout is added to another layout (via BLayout::AddItem()) + // then we share ownership of our layout. In the event that our layout gets + // deleted by the layout it has been added to, this method is called so + // that we don't double-delete our layout. + if (fLayoutData->fLayout == deleted) + fLayoutData->fLayout = NULL; + InvalidateLayout(); +} + + +void +BView::_InvalidateParentLayout() +{ + BLayout* layout = fLayoutData->fLayout; + BLayout* layoutParent = layout ? layout->Layout() : NULL; + if (layoutParent && layoutParent->InvalidationLegal()) { + layout->Layout()->InvalidateLayout(); + } else if (fParent && fParent->fLayoutData->fLayout) { + fParent->fLayoutData->fLayout->InvalidateLayoutsForView(this); + } else if (fParent) { + fParent->InvalidateLayout(); + } +} + + // #pragma mark - Private Functions @@ -5920,3 +5954,13 @@ } } } + + +// #pragma mark - + + +bool +BView::Private::MinMaxValid() +{ + return fView->fLayoutData->fMinMaxValid; +} Index: src/kits/interface/Layout.cpp =================================================================== --- src/kits/interface/Layout.cpp (revision 38092) +++ src/kits/interface/Layout.cpp (working copy) @@ -7,26 +7,50 @@ #include +#include +#include #include -#include +#include #include #include +#include #include "ViewLayoutItem.h" using std::nothrow; +using std::swap; namespace { + // flags for our state + const uint32 B_LAYOUT_INVALID = 0x80000000UL; // needs layout + const uint32 B_LAYOUT_CACHE_INVALID = 0x40000000UL; // needs recalculation + const uint32 B_LAYOUT_REQUIRED = 0x20000000UL; // needs layout + const uint32 B_LAYOUT_IN_PROGRESS = 0x10000000UL; + const uint32 B_LAYOUT_ALL_CLEAR = 0UL; + + // handy masks to check various states + const uint32 B_LAYOUT_INVALIDATION_ILLEGAL + = B_LAYOUT_CACHE_INVALID | B_LAYOUT_IN_PROGRESS; + const uint32 B_LAYOUT_NECESSARY + = B_LAYOUT_INVALID | B_LAYOUT_REQUIRED | B_LAYOUT_CACHE_INVALID; + const uint32 B_RELAYOUT_NOT_OK + = B_LAYOUT_INVALID | B_LAYOUT_IN_PROGRESS; + const char* const kLayoutItemField = "BLayout:items"; } BLayout::BLayout() : - fView(NULL), + fState(B_LAYOUT_ALL_CLEAR), + fAncestorsVisible(true), + fInvalidationDisabled(0), + fContext(NULL), + fOwner(NULL), + fTarget(NULL), fItems(20) { } @@ -34,8 +58,13 @@ BLayout::BLayout(BMessage* from) : - BArchivable(BUnarchiver::PrepareArchive(from)), - fView(NULL), + BLayoutItem(BUnarchiver::PrepareArchive(from)), + fState(B_LAYOUT_ALL_CLEAR), + fAncestorsVisible(true), + fInvalidationDisabled(0), + fContext(NULL), + fOwner(NULL), + fTarget(NULL), fItems(20) { BUnarchiver unarchiver(from); @@ -48,18 +77,39 @@ BLayout::~BLayout() { - // this deletes all items - SetView(NULL); + // in case we have a view, but have been added to a layout as a BLayoutItem + // we will get deleted before our view, so we should tell it that we're + // going, so that we aren't double-freed. + if (fOwner && this == fOwner->GetLayout()) + fOwner->_LayoutLeft(this); + + // removes and deletes all items + if (fTarget) + SetTarget(NULL); } BView* -BLayout::View() const +BLayout::Owner() const { - return fView; + return fOwner; } +BView* +BLayout::TargetView() const +{ + return fTarget; +} + + +BView* +BLayout::View() +{ + return fOwner; +} + + BLayoutItem* BLayout::AddView(BView* child) { @@ -70,11 +120,15 @@ BLayoutItem* BLayout::AddView(int32 index, BView* child) { - if (BViewLayoutItem* item = new(nothrow) BViewLayoutItem(child)) { - if (AddItem(index, item)) - return item; + BLayoutItem* item = child->GetLayout(); + if (!item) + item = new(nothrow) BViewLayoutItem(child); + + if (item && AddItem(index, item)) + return item; + + if (!child->GetLayout()) delete item; - } return NULL; } @@ -89,15 +143,15 @@ bool BLayout::AddItem(int32 index, BLayoutItem* item) { - if (!fView || !item || fItems.HasItem(item)) + if (!fTarget || !item || fItems.HasItem(item)) return false; // if the item refers to a BView, we make sure it is added to the parent // view bool addedView = false; BView* view = item->View(); - if (view && view->fParent != fView - && !(addedView = fView->_AddChild(view, NULL))) + if (view && view->fParent != fTarget + && !(addedView = fTarget->_AddChild(view, NULL))) return false; // validate the index @@ -106,6 +160,8 @@ if (fItems.AddItem(item, index) && ItemAdded(item, index)) { item->SetLayout(this); + if (!fAncestorsVisible) + item->AncestorVisibilityChanged(fAncestorsVisible); InvalidateLayout(); return true; } else { @@ -160,11 +216,11 @@ // if the item refers to a BView, we make sure, it is removed from the // parent view BView* view = item->View(); - if (view && view->fParent == fView) + if (view && view->fParent == fTarget) view->_RemoveSelf(); + ItemRemoved(item, index); item->SetLayout(NULL); - ItemRemoved(item, index); InvalidateLayout(); return item; @@ -206,19 +262,158 @@ } +bool +BLayout::AncestorsVisible() +{ + return fAncestorsVisible; +} + + void -BLayout::InvalidateLayout() +BLayout::InvalidateLayout(bool children) { - if (fView) - fView->InvalidateLayout(); + // printf("BLayout(%p)::InvalidateLayout(%i) : state %x, disabled %li\n", + // this, children, (unsigned int)fState, fInvalidationDisabled); + + if (!InvalidationLegal()) + return; + + fState |= B_LAYOUT_NECESSARY; + + if (children) { + for (int32 i = CountItems() - 1; i >= 0; i--) + ItemAt(i)->InvalidateLayout(children); + } + + if (fOwner && BView::Private(fOwner).MinMaxValid()) + fOwner->InvalidateLayout(children); + + if (BLayout* nestedIn = Layout()) { + if (nestedIn->InvalidationLegal()) + nestedIn->InvalidateLayout(); + } else if (fOwner) { + // If we weren't added as a BLayoutItem, we still have to invalidate + // whatever layout our owner is in. + BView* ownerParent = fOwner->fParent; + if (ownerParent) { + BLayout* layout = ownerParent->GetLayout(); + if (layout && layout->fNestedLayouts.CountItems() > 0) + layout->InvalidateLayoutsForView(fOwner); + else if (BView::Private(ownerParent).MinMaxValid()) + ownerParent->InvalidateLayout(false); + } + } } +void +BLayout::RequireLayout() +{ + fState |= B_LAYOUT_REQUIRED; +} + + +bool +BLayout::IsValid() +{ + return (fState & B_LAYOUT_INVALID) == 0; +} + + +void +BLayout::DisableLayoutInvalidation() +{ + fInvalidationDisabled++; +} + + +void +BLayout::EnableLayoutInvalidation() +{ + if (fInvalidationDisabled > 0) + fInvalidationDisabled--; +} + + +void +BLayout::LayoutItems(bool force) +{ + if ((fState & B_LAYOUT_NECESSARY) == 0 && !force) + return; + + if (Layout() && (Layout()->fState & B_LAYOUT_IN_PROGRESS) != 0) + return; // wait for parent layout to lay us out. + + if (fTarget && fTarget->LayoutContext()) + return; + + BLayoutContext context; + _LayoutWithinContext(force, &context); +} + + +void +BLayout::Relayout(bool immediate) +{ + if ((fState & B_RELAYOUT_NOT_OK) == 0 || immediate) { + fState |= B_LAYOUT_REQUIRED; + LayoutItems(false); + } +} + + + +void +BLayout::_LayoutWithinContext(bool force, BLayoutContext* context) +{ +// printf("BLayout(%p)::_LayoutWithinContext(%i, %p), state %x, fContext %p\n", +// this, force, context, (unsigned int)fState, fContext); + + if ((fState & B_LAYOUT_NECESSARY) == 0 && !force) + return; + + BLayoutContext* oldContext = fContext; + fContext = context; + + if (fOwner && fOwner->LayoutContext() != context) { + // in this case, let our owner decide whether or not to have us + // do our layout, if they do, we won't end up here again. + fOwner->_Layout(force, context); + } else { + fState |= B_LAYOUT_IN_PROGRESS; + DerivedLayoutItems(); + // we must ensure that all items are laid out, layouts with a view will + // have their layout process triggered by their view, but nested + // view-less layouts must have their layout triggered here (if it hasn't + // already been triggered). + int32 nestedLayoutCount = fNestedLayouts.CountItems(); + for (int32 i = 0; i < nestedLayoutCount; i++) { + BLayout* layout = (BLayout*)fNestedLayouts.ItemAt(i); + if ((layout->fState & B_LAYOUT_NECESSARY) != 0) + layout->_LayoutWithinContext(force, context); + } + fState = B_LAYOUT_ALL_CLEAR; + } + + fContext = oldContext; +} + + +BRect +BLayout::LayoutArea() +{ + BRect area(Frame()); + if (fOwner) + area.OffsetTo(B_ORIGIN); + return area; +} + + status_t BLayout::Archive(BMessage* into, bool deep) const { BArchiver archiver(into); - status_t err = BArchivable::Archive(into, deep); + status_t err = BLayoutItem::Archive(into, deep); if (deep) { int32 count = CountItems(); @@ -242,7 +437,7 @@ BLayout::AllUnarchived(const BMessage* from) { BUnarchiver unarchiver(from); - status_t err = BArchivable::AllUnarchived(from); + status_t err = BLayoutItem::AllUnarchived(from); if (err != B_OK) return err; @@ -304,16 +499,138 @@ void -BLayout::SetView(BView* view) +BLayout::OwnerChanged(BView* was) { - if (view != fView) { - fView = NULL; +} + +void +BLayout::AttachedToLayout() +{ + if (!fOwner) { + Layout()->fNestedLayouts.AddItem(this); + SetTarget(Layout()->TargetView()); + } +} + + +void +BLayout::DetachedFromLayout(BLayout* from) +{ + if (!fOwner) { + from->fNestedLayouts.RemoveItem(this); + SetTarget(NULL); + } +} + + +void +BLayout::AncestorVisibilityChanged(bool shown) +{ + if (fAncestorsVisible == shown) + return; + + fAncestorsVisible = shown; + VisibilityChanged(shown); +} + + +void +BLayout::VisibilityChanged(bool show) +{ + if (fOwner) + return; + + for (int32 i = CountItems() - 1; i >= 0; i--) + ItemAt(i)->AncestorVisibilityChanged(show); +} + + +void +BLayout::ResetLayoutInvalidation() +{ + fState &= ~B_LAYOUT_CACHE_INVALID; +} + + +BLayoutContext* +BLayout::LayoutContext() +{ + return fContext; +} + + +bool +BLayout::RemoveViewRecursive(BView* view) +{ + bool removed = RemoveView(view); + for (int32 i = fNestedLayouts.CountItems() - 1; i >= 0; i--) { + BLayout* nested = (BLayout*)fNestedLayouts.ItemAt(i); + removed |= nested->RemoveViewRecursive(view); + } + return removed; +} + + +bool +BLayout::InvalidateLayoutsForView(BView* view) +{ + bool found = false; + for (int32 i = fNestedLayouts.CountItems() - 1; i >= 0; i--) { + BLayout* layout = (BLayout*)fNestedLayouts.ItemAt(i); + found |= layout->InvalidateLayoutsForView(view); + } + + if (found) + return found; + + if (!InvalidationLegal()) + return false; + + for (int32 i = CountItems() - 1; i >= 0; i--) { + if (ItemAt(i)->View() == view) { + InvalidateLayout(); + return true; + } + } + return found; +} + + +bool +BLayout::InvalidationLegal() +{ + return fInvalidationDisabled <= 0 + && (fState & B_LAYOUT_INVALIDATION_ILLEGAL) == 0; +} + + +void +BLayout::SetOwner(BView* owner) +{ + if (fOwner == owner) + return; + + SetTarget(owner); + swap(fOwner, owner); + + OwnerChanged(owner); + // call hook +} + + +void +BLayout::SetTarget(BView* target) +{ + if (fTarget != target) { + fTarget = NULL; + // only remove items, not views + // remove and delete all items for (int32 i = CountItems() - 1; i >= 0; i--) delete RemoveItem(i); - fView = view; + fTarget = target; InvalidateLayout(); } Index: src/kits/interface/ViewLayoutItem.cpp =================================================================== --- src/kits/interface/ViewLayoutItem.cpp (revision 38092) +++ src/kits/interface/ViewLayoutItem.cpp (working copy) @@ -11,6 +11,7 @@ #include #include +#include namespace { @@ -20,7 +21,8 @@ BViewLayoutItem::BViewLayoutItem(BView* view) : - fView(view) + fView(view), + fAncestorsVisible(true) { } @@ -28,7 +30,8 @@ BViewLayoutItem::BViewLayoutItem(BMessage* from) : BLayoutItem(BUnarchiver::PrepareArchive(from)), - fView(NULL) + fView(NULL), + fAncestorsVisible(true) { BUnarchiver unarchiver(from); unarchiver.Finish(unarchiver.FindObject(kViewField, 0, @@ -100,7 +103,8 @@ bool BViewLayoutItem::IsVisible() { - return !fView->IsHidden(fView); + int16 showLevel = BView::Private(fView).ShowLevel(); + return showLevel - (fAncestorsVisible ? 0 : 1) <= 0; } @@ -154,12 +158,22 @@ void -BViewLayoutItem::InvalidateLayout() +BViewLayoutItem::InvalidateLayout(bool children) { - fView->InvalidateLayout(); + fView->InvalidateLayout(children); } +void +BViewLayoutItem::Relayout(bool immediate) +{ + if (immediate) + fView->Layout(false); + else + fView->Relayout(); +} + + status_t BViewLayoutItem::Archive(BMessage* into, bool deep) const { @@ -204,3 +218,18 @@ return new(std::nothrow) BViewLayoutItem(from); return NULL; } + + +void +BViewLayoutItem::AncestorVisibilityChanged(bool shown) +{ + if (fAncestorsVisible == shown) + return; + + fAncestorsVisible = shown; + if (shown) + fView->Show(); + if (!shown) + fView->Hide(); +} + Index: src/kits/interface/LayoutItem.cpp =================================================================== --- src/kits/interface/LayoutItem.cpp (revision 38092) +++ src/kits/interface/LayoutItem.cpp (working copy) @@ -8,8 +8,11 @@ #include #include +#include +#include + BLayoutItem::BLayoutItem() : fLayout(NULL), @@ -30,6 +33,8 @@ BLayoutItem::~BLayoutItem() { + if (fLayout) + fLayout->RemoveItem(this); } @@ -64,13 +69,24 @@ void -BLayoutItem::InvalidateLayout() +BLayoutItem::InvalidateLayout(bool children) { if (fLayout) - fLayout->InvalidateLayout(); + fLayout->InvalidateLayout(children); } +void +BLayoutItem::Relayout(bool immediate) +{ + BView* view = View(); + if (view && !immediate) + view->Relayout(); + else if (view && immediate) + view->Layout(false); +} + + void* BLayoutItem::LayoutData() const { @@ -144,5 +160,35 @@ void BLayoutItem::SetLayout(BLayout* layout) { - fLayout = layout; + if (layout == fLayout) + return; + + std::swap(fLayout, layout); + if (layout) + DetachedFromLayout(layout); + + if (fLayout) + AttachedToLayout(); } + + +void +BLayoutItem::AttachedToLayout() +{ + // hook method +} + + +void +BLayoutItem::DetachedFromLayout(BLayout* oldLayout) +{ + // hook method +} + + +void +BLayoutItem::AncestorVisibilityChanged(bool shown) +{ + // hook method +} + Index: src/kits/interface/SplitLayout.h =================================================================== --- src/kits/interface/SplitLayout.h (revision 38092) +++ src/kits/interface/SplitLayout.h (working copy) @@ -6,7 +6,7 @@ #define _SPLIT_LAYOUT_H -#include +#include #include @@ -21,7 +21,7 @@ using BPrivate::Layout::LayoutInfo; -class BSplitLayout : public BLayout { +class BSplitLayout : public BAbstractLayout { public: BSplitLayout(enum orientation orientation, float spacing = 0.0f); @@ -66,18 +66,18 @@ void SetCollapsible(int32 first, int32 last, bool collapsible); - virtual BSize MinSize(); - virtual BSize MaxSize(); - virtual BSize PreferredSize(); - virtual BAlignment Alignment(); + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); virtual bool HasHeightForWidth(); virtual void GetHeightForWidth(float width, float* min, float* max, float* preferred); - virtual void InvalidateLayout(); + virtual void InvalidateLayout(bool children = false); - virtual void LayoutView(); + virtual void DerivedLayoutItems(); // interface for BSplitView BRect SplitterItemFrame(int32 index) const; @@ -106,7 +106,8 @@ class ValueRange; class SplitterItem; - void _InvalidateLayout(bool invalidateView); + void _InvalidateLayout(bool invalidateView, + bool children = false); void _InvalidateCachedHeightForWidth(); SplitterItem* _SplitterItemAt(const BPoint& point, Index: src/kits/interface/GroupLayoutBuilder.cpp =================================================================== --- src/kits/interface/GroupLayoutBuilder.cpp (revision 38092) +++ src/kits/interface/GroupLayoutBuilder.cpp (working copy) @@ -28,7 +28,6 @@ _PushLayout(fRootLayout); } - // constructor BGroupLayoutBuilder::BGroupLayoutBuilder(BGroupView* view) : fRootLayout(view->GroupLayout()) @@ -64,7 +63,7 @@ BView* BGroupLayoutBuilder::TopView() const { - return TopLayout()->View(); + return TopLayout()->Owner(); } // GetTopView @@ -72,7 +71,7 @@ BGroupLayoutBuilder::GetTopView(BView** _view) { if (BGroupLayout* layout = TopLayout()) - *_view = layout->View(); + *_view = layout->Owner(); else *_view = NULL; @@ -181,12 +180,6 @@ return fRootLayout; } -// cast operator BView* -BGroupLayoutBuilder::operator BView*() -{ - return fRootLayout->View(); -} - // _PushLayout bool BGroupLayoutBuilder::_PushLayout(BGroupLayout* layout) Index: src/kits/interface/CardLayout.cpp =================================================================== --- src/kits/interface/CardLayout.cpp (revision 38092) +++ src/kits/interface/CardLayout.cpp (working copy) @@ -17,7 +17,7 @@ BCardLayout::BCardLayout() : - BLayout(), + BAbstractLayout(), fMin(0, 0), fMax(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED), fPreferred(0, 0), @@ -29,7 +29,7 @@ BCardLayout::BCardLayout(BMessage* from) : - BLayout(BUnarchiver::PrepareArchive(from)), + BAbstractLayout(BUnarchiver::PrepareArchive(from)), fMin(0, 0), fMax(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED), fPreferred(0, 0), @@ -83,13 +83,13 @@ if (fVisibleItem != NULL) { fVisibleItem->SetVisible(true); - LayoutView(); + Relayout(); } } BSize -BCardLayout::MinSize() +BCardLayout::BaseMinSize() { _ValidateMinMax(); return fMin; @@ -97,7 +97,7 @@ BSize -BCardLayout::MaxSize() +BCardLayout::BaseMaxSize() { _ValidateMinMax(); return fMax; @@ -105,7 +105,7 @@ BSize -BCardLayout::PreferredSize() +BCardLayout::BasePreferredSize() { _ValidateMinMax(); return fPreferred; @@ -113,7 +113,7 @@ BAlignment -BCardLayout::Alignment() +BCardLayout::BaseAlignment() { return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); } @@ -174,25 +174,30 @@ void -BCardLayout::InvalidateLayout() +BCardLayout::InvalidateLayout(bool children) { - BLayout::InvalidateLayout(); + BLayout::InvalidateLayout(children); fMinMaxValid = false; } void -BCardLayout::LayoutView() +BCardLayout::DerivedLayoutItems() { _ValidateMinMax(); - BSize size = View()->Bounds().Size(); - size.width = max_c(size.width, fMin.width); - size.height = max_c(size.height, fMin.height); + BSize size(LayoutArea().Size()); - if (fVisibleItem != NULL) - fVisibleItem->AlignInFrame(BRect(0, 0, size.width, size.height)); + // this cannot be done when we are viewless, as our children + // would not get cut off in the right place. + if (Owner()) { + size.width = max_c(size.width, fMin.width); + size.height = max_c(size.height, fMin.height); + } + + if (fVisibleItem != NULL) + fVisibleItem->AlignInFrame(BRect(LayoutArea().LeftTop(), size)); } @@ -200,7 +205,7 @@ BCardLayout::Archive(BMessage* into, bool deep) const { BArchiver archiver(into); - status_t err = BLayout::Archive(into, deep); + status_t err = BAbstractLayout::Archive(into, deep); if (err == B_OK && deep) err = into->AddInt32(kVisibleItemField, IndexOfItem(fVisibleItem)); @@ -292,7 +297,5 @@ fPreferred.height = min_c(fPreferred.height, fMax.height); fMinMaxValid = true; - - if (BView* view = View()) - view->ResetLayoutInvalidation(); + ResetLayoutInvalidation(); } Index: src/kits/interface/Jamfile =================================================================== --- src/kits/interface/Jamfile (revision 38092) +++ src/kits/interface/Jamfile (working copy) @@ -31,6 +31,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) layouter ] ; MergeObject interface_kit.o : + AbstractLayout.cpp AbstractLayoutItem.cpp AffineTransform.cpp Alert.cpp Index: src/kits/interface/SplitLayout.cpp =================================================================== --- src/kits/interface/SplitLayout.cpp (revision 38092) +++ src/kits/interface/SplitLayout.cpp (working copy) @@ -196,7 +196,7 @@ BSplitLayout::BSplitLayout(BMessage* from) : - BLayout(BUnarchiver::PrepareArchive(from)), + BAbstractLayout(BUnarchiver::PrepareArchive(from)), fSplitterItems(), fVisibleItems(), fMin(), @@ -340,14 +340,14 @@ BLayoutItem* BSplitLayout::AddView(BView* child) { - return BLayout::AddView(child); + return BAbstractLayout::AddView(child); } BLayoutItem* BSplitLayout::AddView(int32 index, BView* child) { - return BLayout::AddView(index, child); + return BAbstractLayout::AddView(index, child); } @@ -372,14 +372,14 @@ bool BSplitLayout::AddItem(BLayoutItem* item) { - return BLayout::AddItem(item); + return BAbstractLayout::AddItem(item); } bool BSplitLayout::AddItem(int32 index, BLayoutItem* item) { - return BLayout::AddItem(index, item); + return BAbstractLayout::AddItem(index, item); } @@ -480,7 +480,7 @@ BSize -BSplitLayout::MinSize() +BSplitLayout::BaseMinSize() { _ValidateMinMax(); @@ -489,7 +489,7 @@ BSize -BSplitLayout::MaxSize() +BSplitLayout::BaseMaxSize() { _ValidateMinMax(); @@ -498,7 +498,7 @@ BSize -BSplitLayout::PreferredSize() +BSplitLayout::BasePreferredSize() { _ValidateMinMax(); @@ -507,9 +507,9 @@ BAlignment -BSplitLayout::Alignment() +BSplitLayout::BaseAlignment() { - return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); + return BAbstractLayout::BaseAlignment(); } @@ -536,19 +536,19 @@ void -BSplitLayout::InvalidateLayout() +BSplitLayout::InvalidateLayout(bool children) { - _InvalidateLayout(true); + _InvalidateLayout(true, children); } void -BSplitLayout::LayoutView() +BSplitLayout::DerivedLayoutItems() { _ValidateMinMax(); // layout the elements - BSize size = _SubtractInsets(View()->Bounds().Size()); + BSize size = _SubtractInsets(LayoutArea().Size()); fHorizontalLayouter->Layout(fHorizontalLayoutInfo, size.width); Layouter* verticalLayouter; @@ -647,7 +647,7 @@ return false; // Things shouldn't be draggable, if we have a >= max layout. - BSize size = _SubtractInsets(View()->Frame().Size()); + BSize size = _SubtractInsets(LayoutArea().Size()); if ((fOrientation == B_HORIZONTAL && size.width >= fMax.width) || (fOrientation == B_VERTICAL && size.height >= fMax.height)) { return false; @@ -655,7 +655,7 @@ int32 index = -1; if (_SplitterItemAt(point, &index) != NULL) { - fDraggingStartPoint = View()->ConvertToScreen(point); + fDraggingStartPoint = Owner()->ConvertToScreen(point); fDraggingStartValue = _SplitterValue(index); fDraggingCurrentValue = fDraggingStartValue; fDraggingSplitterIndex = index; @@ -673,7 +673,7 @@ if (fDraggingSplitterIndex < 0) return false; - point = View()->ConvertToScreen(point); + point = Owner()->ConvertToScreen(point); int32 valueDiff; if (fOrientation == B_HORIZONTAL) @@ -712,7 +712,7 @@ BSplitLayout::Archive(BMessage* into, bool deep) const { BArchiver archiver(into); - status_t err = BLayout::Archive(into, deep); + status_t err = BAbstractLayout::Archive(into, deep); if (err == B_OK) err = into->AddBool(kIsVerticalField, fOrientation == B_VERTICAL); @@ -811,10 +811,10 @@ void -BSplitLayout::_InvalidateLayout(bool invalidateView) +BSplitLayout::_InvalidateLayout(bool invalidateView, bool children) { if (invalidateView) - BLayout::InvalidateLayout(); + BAbstractLayout::InvalidateLayout(children); delete fHorizontalLayouter; delete fVerticalLayouter; @@ -929,7 +929,7 @@ info->max = item->MaxSize(); if (item->HasHeightForWidth()) { - BSize size = _SubtractInsets(View()->Frame().Size()); + BSize size = _SubtractInsets(LayoutArea().Size()); float minHeight, maxHeight; item->GetHeightForWidth(size.width, &minHeight, &maxHeight, NULL); info->min.height = max_c(info->min.height, minHeight); @@ -958,9 +958,9 @@ item->AlignInFrame(info->layoutFrame); // if the item became visible, we need to update its internal layout - if (visibilityChanged) { - if (BView* itemView = item->View()) - itemView->Layout(false); + if (visibilityChanged && fOrientation != B_HORIZONTAL + && !HasHeightForWidth()) { + item->Relayout(true); } } @@ -1216,7 +1216,7 @@ } // Just updating the splitter weights is fine in principle. The next - // LayoutView() will use the correct values. But, if our orientation is + // LayoutItems() will use the correct values. But, if our orientation is // vertical, the cached height for width info needs to be flushed, or the // obsolete cached values will be used. if (fOrientation == B_VERTICAL) @@ -1293,8 +1293,7 @@ if (fHeightForWidthItems.IsEmpty()) fVerticalLayoutInfo = fVerticalLayouter->CreateLayoutInfo(); - if (BView* view = View()) - view->ResetLayoutInvalidation(); + ResetLayoutInvalidation(); } Index: src/kits/interface/TwoDimensionalLayout.cpp =================================================================== --- src/kits/interface/TwoDimensionalLayout.cpp (revision 38092) +++ src/kits/interface/TwoDimensionalLayout.cpp (working copy) @@ -258,7 +258,7 @@ BTwoDimensionalLayout::BTwoDimensionalLayout(BMessage* from) : - BLayout(from), + BAbstractLayout(from), fLeftInset(0), fRightInset(0), fTopInset(0), @@ -324,7 +324,7 @@ BSize -BTwoDimensionalLayout::MinSize() +BTwoDimensionalLayout::BaseMinSize() { _ValidateMinMax(); return AddInsets(fLocalLayouter->MinSize()); @@ -332,7 +332,7 @@ BSize -BTwoDimensionalLayout::MaxSize() +BTwoDimensionalLayout::BaseMaxSize() { _ValidateMinMax(); return AddInsets(fLocalLayouter->MaxSize()); @@ -340,7 +340,7 @@ BSize -BTwoDimensionalLayout::PreferredSize() +BTwoDimensionalLayout::BasePreferredSize() { _ValidateMinMax(); return AddInsets(fLocalLayouter->PreferredSize()); @@ -348,9 +348,9 @@ BAlignment -BTwoDimensionalLayout::Alignment() +BTwoDimensionalLayout::BaseAlignment() { - return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); + return BAbstractLayout::BaseAlignment(); } @@ -377,72 +377,25 @@ void -BTwoDimensionalLayout::InvalidateLayout() +BTwoDimensionalLayout::SetFrame(BRect frame) { - BLayout::InvalidateLayout(); - - fLocalLayouter->InvalidateLayout(); + BAbstractLayout::SetFrame(frame); } void -BTwoDimensionalLayout::LayoutView() +BTwoDimensionalLayout::InvalidateLayout(bool children) { - _ValidateMinMax(); - - // layout the horizontal/vertical elements - BSize size = SubtractInsets(View()->Frame().Size()); - -#ifdef DEBUG_LAYOUT -printf("BTwoDimensionalLayout::LayoutView(%p): size: (%.1f, %.1f)\n", -View(), size.width, size.height); -#endif - - fLocalLayouter->Layout(size); - - // layout the items - int itemCount = CountItems(); - for (int i = 0; i < itemCount; i++) { - BLayoutItem* item = ItemAt(i); - if (item->IsVisible()) { - Dimensions itemDimensions; - GetItemDimensions(item, &itemDimensions); - BRect frame = fLocalLayouter->ItemFrame(itemDimensions); - frame.left += fLeftInset; - frame.top += fTopInset; - frame.right += fLeftInset; - frame.bottom += fTopInset; -{ -#ifdef DEBUG_LAYOUT -printf(" frame for item %2d (view: %p): ", i, item->View()); -frame.PrintToStream(); -#endif -//BSize min(item->MinSize()); -//BSize max(item->MaxSize()); -//printf(" min: (%.1f, %.1f), max: (%.1f, %.1f)\n", min.width, min.height, -// max.width, max.height); -//if (item->HasHeightForWidth()) { -//float minHeight, maxHeight, preferredHeight; -//item->GetHeightForWidth(frame.Width(), &minHeight, &maxHeight, -// &preferredHeight); -//printf(" hfw: min: %.1f, max: %.1f, pref: %.1f\n", minHeight, maxHeight, -// preferredHeight); -//} + BLayout::InvalidateLayout(children); + fLocalLayouter->InvalidateLayout(); } - item->AlignInFrame(frame); - } -//else -//printf(" item %2d not visible", i); - } -} - status_t BTwoDimensionalLayout::Archive(BMessage* into, bool deep) const { BArchiver archiver(into); - status_t err = BLayout::Archive(into, deep); + status_t err = BAbstractLayout::Archive(into, deep); if (err == B_OK) { BRect insets(fLeftInset, fTopInset, fRightInset, fBottomInset); @@ -487,6 +440,61 @@ } +void +BTwoDimensionalLayout::DerivedLayoutItems() +{ + _ValidateMinMax(); + + // layout the horizontal/vertical elements + BSize size(SubtractInsets(LayoutArea().Size())); + +#ifdef DEBUG_LAYOUT +printf("BTwoDimensionalLayout::DerivedLayoutItems(): view: %p" + " size: (%.1f, %.1f)\n", View(), size.Width(), size.Height()); +#endif + + fLocalLayouter->Layout(size); + + // layout the items + BPoint itemOffset(LayoutArea().LeftTop()); + int itemCount = CountItems(); + for (int i = 0; i < itemCount; i++) { + BLayoutItem* item = ItemAt(i); + if (item->IsVisible()) { + Dimensions itemDimensions; + GetItemDimensions(item, &itemDimensions); + BRect frame = fLocalLayouter->ItemFrame(itemDimensions); + frame.left += fLeftInset; + frame.top += fTopInset; + frame.right += fLeftInset; + frame.bottom += fTopInset; + frame.OffsetBy(itemOffset); +{ +#ifdef DEBUG_LAYOUT +printf(" frame for item %2d (view: %p): ", i, item->View()); +frame.PrintToStream(); +#endif +//BSize min(item->MinSize()); +//BSize max(item->MaxSize()); +//printf(" min: (%.1f, %.1f), max: (%.1f, %.1f)\n", min.width, min.height, +// max.width, max.height); +//if (item->HasHeightForWidth()) { +//float minHeight, maxHeight, preferredHeight; +//item->GetHeightForWidth(frame.Width(), &minHeight, &maxHeight, +// &preferredHeight); +//printf(" hfw: min: %.1f, max: %.1f, pref: %.1f\n", minHeight, maxHeight, +// preferredHeight); +//} +} + + item->AlignInFrame(frame); + } +//else +//printf(" item %2d not visible", i); + } +} + + BSize BTwoDimensionalLayout::AddInsets(BSize size) { @@ -547,20 +555,9 @@ BTwoDimensionalLayout::_ValidateMinMax() { fLocalLayouter->ValidateMinMax(); - - if (BView* view = View()) - view->ResetLayoutInvalidation(); } -BLayoutContext* -BTwoDimensionalLayout::_CurrentLayoutContext() -{ - BView* view = View(); - return (view ? view->LayoutContext() : NULL); -} - - // #pragma mark - CompoundLayouter @@ -1060,7 +1057,7 @@ BTwoDimensionalLayout::LocalLayouter::Layout(BSize size) { DoHorizontalLayout(size.width); - fVLayouter->Layout(size.height, this, fLayout->_CurrentLayoutContext()); + fVLayouter->Layout(size.height, this, fLayout->LayoutContext()); } @@ -1092,13 +1089,14 @@ fHLayouter->ValidateMinMax(); fVLayouter->ValidateMinMax(); + fLayout->ResetLayoutInvalidation(); } void BTwoDimensionalLayout::LocalLayouter::DoHorizontalLayout(float width) { - BLayoutContext* context = fLayout->_CurrentLayoutContext(); + BLayoutContext* context = fLayout->LayoutContext(); if (fHorizontalLayoutContext != context || width != fHorizontalLayoutWidth) { _SetHorizontalLayoutContext(context, width); Index: src/kits/interface/Window.cpp =================================================================== --- src/kits/interface/Window.cpp (revision 38092) +++ src/kits/interface/Window.cpp (working copy) @@ -543,6 +543,15 @@ } +void +BWindow::AddChild(BLayoutItem* child) +{ + BAutolock locker(this); + if (locker.IsLocked()) + fTopView->AddChild(child); +} + + bool BWindow::RemoveChild(BView* child) { Index: src/kits/interface/GridLayoutBuilder.cpp =================================================================== --- src/kits/interface/GridLayoutBuilder.cpp (revision 38092) +++ src/kits/interface/GridLayoutBuilder.cpp (working copy) @@ -45,7 +45,7 @@ BView* BGridLayoutBuilder::View() const { - return fLayout->View(); + return fLayout->Owner(); } // GetGridLayout @@ -60,7 +60,7 @@ BGridLayoutBuilder& BGridLayoutBuilder::GetView(BView** _view) { - *_view = fLayout->View(); + *_view = fLayout->Owner(); return *this; } @@ -112,8 +112,3 @@ return fLayout; } -// cast operator BView* -BGridLayoutBuilder::operator BView*() -{ - return fLayout->View(); -} Index: headers/os/interface/TwoDimensionalLayout.h =================================================================== --- headers/os/interface/TwoDimensionalLayout.h (revision 38092) +++ headers/os/interface/TwoDimensionalLayout.h (working copy) @@ -6,12 +6,12 @@ #define _TWO_DIMENSIONAL_LAYOUT_H -#include +#include class BLayoutContext; -class BTwoDimensionalLayout : public BLayout { +class BTwoDimensionalLayout : public BAbstractLayout { public: BTwoDimensionalLayout(); BTwoDimensionalLayout(BMessage* from); @@ -25,18 +25,18 @@ void AlignLayoutWith(BTwoDimensionalLayout* other, enum orientation orientation); - virtual BSize MinSize(); - virtual BSize MaxSize(); - virtual BSize PreferredSize(); - virtual BAlignment Alignment(); + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); virtual bool HasHeightForWidth(); virtual void GetHeightForWidth(float width, float* min, float* max, float* preferred); - virtual void InvalidateLayout(); + virtual void SetFrame(BRect frame); - virtual void LayoutView(); + virtual void InvalidateLayout(bool children = false); virtual status_t Archive(BMessage* into, bool deep = true) const; virtual status_t AllArchived(BMessage* into) const; @@ -56,6 +56,8 @@ int32 height; }; + virtual void DerivedLayoutItems(); + BSize AddInsets(BSize size); void AddInsets(float* minHeight, float* maxHeight, float* preferredHeight); @@ -82,7 +84,6 @@ friend class LocalLayouter; void _ValidateMinMax(); - BLayoutContext* _CurrentLayoutContext(); protected: float fLeftInset; Index: headers/os/interface/Layout.h =================================================================== --- headers/os/interface/Layout.h (revision 38092) +++ headers/os/interface/Layout.h (working copy) @@ -8,22 +8,27 @@ #include #include +#include #include #include +class BLayoutContext; class BLayoutItem; class BView; -class BLayout : public BArchivable { +class BLayout : public BLayoutItem { public: BLayout(); BLayout(BMessage* archive); virtual ~BLayout(); - BView* View() const; + BView* Owner() const; + BView* TargetView() const; + virtual BView* View(); // from BLayoutItem + // methods dealing with items virtual BLayoutItem* AddView(BView* child); virtual BLayoutItem* AddView(int32 index, BView* child); @@ -39,19 +44,23 @@ int32 IndexOfItem(const BLayoutItem* item) const; int32 IndexOfView(BView* child) const; - virtual BSize MinSize() = 0; - virtual BSize MaxSize() = 0; - virtual BSize PreferredSize() = 0; - virtual BAlignment Alignment() = 0; + bool AncestorsVisible(); - virtual bool HasHeightForWidth() = 0; - virtual void GetHeightForWidth(float width, float* min, - float* max, float* preferred) = 0; + // Layouting related methods - virtual void InvalidateLayout(); + virtual void InvalidateLayout(bool children = false); + virtual void Relayout(bool immediate = false); + void RequireLayout(); + bool IsValid(); + void EnableLayoutInvalidation(); + void DisableLayoutInvalidation(); - virtual void LayoutView() = 0; + void LayoutItems(bool force = false); + BRect LayoutArea(); + BLayoutContext* LayoutContext(); + // Archiving methods + virtual status_t Archive(BMessage* into, bool deep = true) const; virtual status_t AllUnarchived(const BMessage* from); @@ -59,17 +68,44 @@ int32 index) const; virtual status_t ItemUnarchived(const BMessage* from, BLayoutItem* item, int32 index); + protected: + // BLayout hook methods virtual bool ItemAdded(BLayoutItem* item, int32 atIndex); virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex); + virtual void DerivedLayoutItems() = 0; + virtual void OwnerChanged(BView* was); + // BLayoutItem hook methods + virtual void AttachedToLayout(); + virtual void DetachedFromLayout(BLayout* layout); + virtual void AncestorVisibilityChanged(bool shown); + + // To be called by sub-classes in SetVisible(). + void VisibilityChanged(bool show); + // To be called when layout data is known to be good + void ResetLayoutInvalidation(); + private: friend class BView; - void SetView(BView* view); + bool RemoveViewRecursive(BView* view); + bool InvalidateLayoutsForView(BView* view); + bool InvalidationLegal(); + void SetOwner(BView* owner); + void SetTarget(BView* target); - BView* fView; + void _LayoutWithinContext(bool force, + BLayoutContext* context); + + uint32 fState; + bool fAncestorsVisible; + int32 fInvalidationDisabled; + BLayoutContext* fContext; + BView* fOwner; + BView* fTarget; BList fItems; + BList fNestedLayouts; }; Index: headers/os/interface/LayoutBuilder.h =================================================================== --- headers/os/interface/LayoutBuilder.h (revision 38092) +++ headers/os/interface/LayoutBuilder.h (working copy) @@ -33,7 +33,6 @@ public: inline void SetParent(ParentBuilder* parent); // conceptually private - inline ParentBuilder& End(); protected: @@ -71,11 +70,23 @@ inline GroupBuilder AddGroup(enum orientation orientation, float spacing = 0.0f, float weight = 1.0f); + inline GroupBuilder AddGroup(BGroupView* groupView, + float weight = 1.0f); + inline GroupBuilder AddGroup(BGroupLayout* groupLayout, + float weight = 1.0f); + inline GridBuilder AddGrid(float horizontalSpacing = 0.0f, float verticalSpacing = 0.0f, float weight = 1.0f); + inline GridBuilder AddGrid(BGridLayout* gridLayout, + float weight = 1.0f); + inline GridBuilder AddGrid(BGridView* gridView, + float weight = 1.0f); + inline SplitBuilder AddSplit(enum orientation orientation, float spacing = 0.0f, float weight = 1.0f); + inline SplitBuilder AddSplit(BSplitView* splitView, + float weight = 1.0f); inline ThisBuilder& AddGlue(float weight = 1.0f); inline ThisBuilder& AddStrut(float size); @@ -84,7 +95,6 @@ float bottom); inline operator BGroupLayout*(); - inline operator BView*(); private: BGroupLayout* fLayout; @@ -131,13 +141,30 @@ inline GroupBuilder AddGroup(enum orientation orientation, float spacing, int32 column, int32 row, int32 columnCount = 1, int32 rowCount = 1); + inline GroupBuilder AddGroup(BGroupView* groupView, int32 column, + int32 row, int32 columnCount = 1, + int32 rowCount = 1); + inline GroupBuilder AddGroup(BGroupLayout* groupLayout, + int32 column, int32 row, + int32 columnCount = 1, int32 rowCount = 1); + inline GridBuilder AddGrid(float horizontalSpacing, float verticalSpacing, int32 column, int32 row, int32 columnCount = 1, int32 rowCount = 1); + inline GridBuilder AddGrid(BGridLayout* gridLayout, + int32 column, int32 row, + int32 columnCount = 1, int32 rowCount = 1); + inline GridBuilder AddGrid(BGridView* gridView, + int32 column, int32 row, + int32 columnCount = 1, int32 rowCount = 1); + inline SplitBuilder AddSplit(enum orientation orientation, float spacing, int32 column, int32 row, int32 columnCount = 1, int32 rowCount = 1); + inline SplitBuilder AddSplit(BSplitView* splitView, int32 column, + int32 row, int32 columnCount = 1, + int32 rowCount = 1); inline ThisBuilder& SetColumnWeight(int32 column, float weight); inline ThisBuilder& SetRowWeight(int32 row, float weight); @@ -146,7 +173,6 @@ float bottom); inline operator BGridLayout*(); - inline operator BView*(); private: BGridLayout* fLayout; @@ -168,7 +194,8 @@ inline Split(BSplitView* view); inline BSplitView* View() const; - inline ThisBuilder& GetView(BSplitView** _view); + inline ThisBuilder& GetView(BView** _view); + inline ThisBuilder& GetSplitView(BSplitView** _view); inline ThisBuilder& Add(BView* view); inline ThisBuilder& Add(BView* view, float weight); @@ -177,11 +204,23 @@ inline GroupBuilder AddGroup(enum orientation orientation, float spacing = 0.0f, float weight = 1.0f); + inline GroupBuilder AddGroup(BGroupView* groupView, + float weight = 1.0f); + inline GroupBuilder AddGroup(BGroupLayout* groupLayout, + float weight = 1.0f); + inline GridBuilder AddGrid(float horizontalSpacing = 0.0f, float verticalSpacing = 0.0f, float weight = 1.0f); + inline GridBuilder AddGrid(BGridView* gridView, + float weight = 1.0f); + inline GridBuilder AddGrid(BGridLayout* gridLayout, + float weight = 1.0f); + inline SplitBuilder AddSplit(enum orientation orientation, float spacing = 0.0f, float weight = 1.0f); + inline SplitBuilder AddSplit(BSplitView* splitView, + float weight = 1.0f); inline ThisBuilder& SetCollapsible(bool collapsible); inline ThisBuilder& SetCollapsible(int32 index, bool collapsible); @@ -244,7 +283,7 @@ { window->SetLayout(fLayout); - fLayout->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + fLayout->Owner()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); // TODO: we get a white background if we don't do this } @@ -277,7 +316,7 @@ BView* Group::View() const { - return fLayout->View(); + return fLayout->Owner(); } @@ -294,7 +333,7 @@ typename Group::ThisBuilder& Group::GetView(BView** _view) { - *_view = fLayout->View(); + *_view = fLayout->Owner(); return *this; } @@ -340,26 +379,70 @@ Group::AddGroup(enum orientation orientation, float spacing, float weight) { - GroupBuilder builder(orientation, spacing); + GroupBuilder builder(new BGroupLayout(orientation, spacing)); builder.SetParent(this); - fLayout->AddView(builder.View(), weight); + fLayout->AddItem(builder.Layout(), weight); return builder; } template +typename Group::GroupBuilder +Group::AddGroup(BGroupView* groupView, float weight) +{ + GroupBuilder builder(groupView); + builder.SetParent(this); + fLayout->AddItem(builder.Layout(), weight); + return builder; +} + + +template +typename Group::GroupBuilder +Group::AddGroup(BGroupLayout* groupLayout, float weight) +{ + GroupBuilder builder(groupLayout); + builder.SetParent(this); + fLayout->AddItem(builder.Layout(), weight); + return builder; +} + + +template typename Group::GridBuilder -Group::AddGrid(float horizontalSpacing, float verticalSpacing, - float weight) +Group::AddGrid(float horizontalSpacing, + float verticalSpacing, float weight) { - GridBuilder builder(horizontalSpacing, verticalSpacing); + GridBuilder builder(new BGridLayout(horizontalSpacing, verticalSpacing)); builder.SetParent(this); - fLayout->AddView(builder.View(), weight); + fLayout->AddItem(builder.Layout(), weight); return builder; } template +typename Group::GridBuilder +Group::AddGrid(BGridLayout* gridLayout, float weight) +{ + GridBuilder builder(gridLayout); + builder.SetParent(this); + fLayout->AddItem(builder.Layout(), weight); + return builder; +} + + +template +typename Group::GridBuilder +Group::AddGrid(BGridView* gridView, float weight) +{ + GridBuilder builder(gridView); + builder.SetParent(this); + fLayout->AddItem(builder.Layout(), weight); + return builder; +} + + +template typename Group::SplitBuilder Group::AddSplit(enum orientation orientation, float spacing, float weight) @@ -372,6 +455,17 @@ template +typename Group::SplitBuilder +Group::AddSplit(BSplitView* splitView, float weight) +{ + SplitBuilder builder(splitView); + builder.SetParent(this); + fLayout->AddView(builder.View(), weight); + return builder; +} + + +template typename Group::ThisBuilder& Group::AddGlue(float weight) { @@ -410,13 +504,6 @@ } -template -Group::operator BView*() -{ - return fLayout->View(); -} - - // #pragma mark - Grid @@ -436,7 +523,7 @@ { window->SetLayout(fLayout); - fLayout->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + fLayout->Owner()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); // TODO: we get a white background if we don't do this } @@ -469,7 +556,7 @@ BView* Grid::View() const { - return fLayout->View(); + return fLayout->Owner(); } @@ -486,7 +573,7 @@ typename Grid::ThisBuilder& Grid::GetView(BView** _view) { - *_view = fLayout->View(); + *_view = fLayout->Owner(); return *this; } @@ -546,20 +633,56 @@ Grid::AddGroup(enum orientation orientation, float spacing, int32 column, int32 row, int32 columnCount, int32 rowCount) { - GroupBuilder builder(orientation, spacing); + GroupBuilder builder(new BGroupLayout(orientation, spacing)); builder.SetParent(this); - fLayout->AddView(builder.View(), column, row, columnCount, rowCount); + fLayout->AddItem(builder.Layout(), column, row, columnCount, rowCount); return builder; } template +typename Grid::GroupBuilder +Grid::AddGroup(BGroupView* groupView, int32 column, int32 row, + int32 columnCount, int32 rowCount) +{ + GroupBuilder builder(groupView); + builder.SetParent(this); + fLayout->AddItem(builder.Layout(), column, row, columnCount, rowCount); + return builder; +} + + +template +typename Grid::GroupBuilder +Grid::AddGroup(BGroupLayout* groupLayout, int32 column, + int32 row, int32 columnCount, int32 rowCount) +{ + GroupBuilder builder(groupLayout); + builder.SetParent(this); + fLayout->AddItem(builder.Layout(), column, row, columnCount, rowCount); + return builder; +} + + +template typename Grid::GridBuilder Grid::AddGrid(float horizontalSpacing, float verticalSpacing, int32 column, int32 row, int32 columnCount, int32 rowCount) { - GridBuilder builder(horizontalSpacing, verticalSpacing); + GridBuilder builder(new BGridLayout(horizontalSpacing, verticalSpacing)); builder.SetParent(this); + fLayout->AddItem(builder.Layout(), column, row, columnCount, rowCount); + return builder; +} + + +template +typename Grid::GridBuilder +Grid::AddGrid(BGridView* gridView, int32 column, int32 row, + int32 columnCount, int32 rowCount) +{ + GridBuilder builder(gridView); + builder.SetParent(this); fLayout->AddView(builder.View(), column, row, columnCount, rowCount); return builder; } @@ -574,10 +697,22 @@ builder.SetParent(this); fLayout->AddView(builder.View(), column, row, columnCount, rowCount); return builder; -} +} template +typename Grid::SplitBuilder +Grid::AddSplit(BSplitView* splitView, int32 column, int32 row, + int32 columnCount, int32 rowCount) +{ + SplitBuilder builder(splitView); + builder.SetParent(this); + fLayout->AddView(builder.View(), column, row, columnCount, rowCount); + return builder; +} + + +template typename Grid::ThisBuilder& Grid::SetColumnWeight(int32 column, float weight) { @@ -612,13 +747,6 @@ } -template -Grid::operator BView*() -{ - return fLayout->View(); -} - - // #pragma mark - Split @@ -648,7 +776,7 @@ template typename Split::ThisBuilder& -Split::GetView(BSplitView** _view) +Split::GetView(BView** _view) { *_view = fView; return *this; @@ -657,6 +785,15 @@ template typename Split::ThisBuilder& +Split::GetSplitView(BSplitView** _view) +{ + *_view = fView; + return *this; +} + + +template +typename Split::ThisBuilder& Split::Add(BView* view) { fView->AddChild(view); @@ -696,26 +833,70 @@ Split::AddGroup(enum orientation orientation, float spacing, float weight) { - GroupBuilder builder(orientation, spacing); + GroupBuilder builder(new BGroupLayout(orientation, spacing)); builder.SetParent(this); - fView->AddChild(builder.View(), weight); + fView->AddChild(builder.Layout(), weight); return builder; } template +typename Split::GroupBuilder +Split::AddGroup(BGroupView* groupView, float weight) +{ + GroupBuilder builder(groupView); + builder.SetParent(this); + fView->AddChild(builder.Layout(), weight); + return builder; +} + + +template +typename Split::GroupBuilder +Split::AddGroup(BGroupLayout* groupLayout, float weight) +{ + GroupBuilder builder(groupLayout); + builder.SetParent(this); + fView->AddChild(builder.Layout(), weight); + return builder; +} + + +template typename Split::GridBuilder Split::AddGrid(float horizontalSpacing, float verticalSpacing, float weight) { - GridBuilder builder(horizontalSpacing, verticalSpacing); + GridBuilder builder(new BGridLayout(horizontalSpacing, verticalSpacing)); builder.SetParent(this); - fView->AddChild(builder.View(), weight); + fView->AddChild(builder.Layout(), weight); return builder; } template +typename Split::GridBuilder +Split::AddGrid(BGridView* gridView, float weight) +{ + GridBuilder builder(gridView); + builder.SetParent(this); + fView->AddChild(builder.Layout(), weight); + return builder; +} + + +template +typename Split::GridBuilder +Split::AddGrid(BGridLayout* layout, float weight) +{ + GridBuilder builder(layout); + builder.SetParent(this); + fView->AddChild(builder.Layout(), weight); + return builder; +} + + +template typename Split::SplitBuilder Split::AddSplit(enum orientation orientation, float spacing, float weight) Index: headers/os/interface/GridLayoutBuilder.h =================================================================== --- headers/os/interface/GridLayoutBuilder.h (revision 38092) +++ headers/os/interface/GridLayoutBuilder.h (working copy) @@ -16,9 +16,9 @@ BGridLayoutBuilder(BGridView* view); BGridLayout* GridLayout() const; - BView* View() const; BGridLayoutBuilder& GetGridLayout(BGridLayout** _layout); - BGridLayoutBuilder& GetView(BView** _view); + BView* View() const; + BGridLayoutBuilder& GetView(BView** _view); BGridLayoutBuilder& Add(BView* view, int32 column, int32 row, int32 columnCount = 1, int32 rowCount = 1); @@ -32,7 +32,6 @@ float bottom); operator BGridLayout*(); - operator BView*(); private: BGridLayout* fLayout; Index: headers/os/interface/GroupLayoutBuilder.h =================================================================== --- headers/os/interface/GroupLayoutBuilder.h (revision 38092) +++ headers/os/interface/GroupLayoutBuilder.h (working copy) @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All rights reserved. + * Copyright 2006-2010, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef _GROUP_LAYOUT_BUILDER_H @@ -39,7 +39,6 @@ float bottom); operator BGroupLayout*(); - operator BView*(); private: bool _PushLayout(BGroupLayout* layout); Index: headers/os/interface/CardLayout.h =================================================================== --- headers/os/interface/CardLayout.h (revision 38092) +++ headers/os/interface/CardLayout.h (working copy) @@ -5,10 +5,10 @@ #ifndef _CARD_LAYOUT_H #define _CARD_LAYOUT_H -#include +#include -class BCardLayout : public BLayout { +class BCardLayout : public BAbstractLayout { public: BCardLayout(); BCardLayout(BMessage* from); @@ -19,23 +19,23 @@ void SetVisibleItem(int32 index); void SetVisibleItem(BLayoutItem* item); - virtual BSize MinSize(); - virtual BSize MaxSize(); - virtual BSize PreferredSize(); - virtual BAlignment Alignment(); + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); virtual bool HasHeightForWidth(); virtual void GetHeightForWidth(float width, float* min, float* max, float* preferred); - virtual void InvalidateLayout(); - virtual void LayoutView(); + virtual void InvalidateLayout(bool children = false); virtual status_t Archive(BMessage* into, bool deep = true) const; virtual status_t AllUnarchived(const BMessage* from); static BArchivable* Instantiate(BMessage* from); protected: + virtual void DerivedLayoutItems(); virtual bool ItemAdded(BLayoutItem* item, int32 atIndex); virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex); Index: headers/os/interface/Window.h =================================================================== --- headers/os/interface/Window.h (revision 38092) +++ headers/os/interface/Window.h (working copy) @@ -103,6 +103,7 @@ void Close() { Quit(); } void AddChild(BView* child, BView* before = NULL); + void AddChild(BLayoutItem* child); bool RemoveChild(BView* child); int32 CountChildren() const; BView* ChildAt(int32 index) const; Index: headers/os/interface/View.h =================================================================== --- headers/os/interface/View.h (revision 38092) +++ headers/os/interface/View.h (working copy) @@ -562,6 +562,8 @@ void Layout(bool force); void Relayout(); + class Private; + protected: virtual void DoLayout(); @@ -580,6 +582,8 @@ private: void _Layout(bool force, BLayoutContext* context); + void _LayoutLeft(BLayout* deleted); + void _InvalidateParentLayout(); private: // FBC padding and forbidden methods @@ -595,6 +599,7 @@ private: struct LayoutData; + friend class Private; friend class BBitmap; friend class BLayout; friend class BPrintJob; Index: headers/os/interface/LayoutItem.h =================================================================== --- headers/os/interface/LayoutItem.h (revision 38092) +++ headers/os/interface/LayoutItem.h (working copy) @@ -16,7 +16,7 @@ class BView; -class BLayoutItem: public BArchivable { +class BLayoutItem : public BArchivable { public: BLayoutItem(); BLayoutItem(BMessage* from); @@ -46,7 +46,8 @@ virtual BView* View(); - virtual void InvalidateLayout(); + virtual void InvalidateLayout(bool children = false); + virtual void Relayout(bool immediate = false); void* LayoutData() const; void SetLayoutData(void* data); @@ -57,11 +58,19 @@ virtual status_t AllArchived(BMessage* into) const; virtual status_t AllUnarchived(const BMessage* from); +protected: + + void SetLayout(BLayout* layout); + + // hook methods + virtual void AttachedToLayout(); + virtual void DetachedFromLayout(BLayout* layout); + + virtual void AncestorVisibilityChanged(bool shown); + private: friend class BLayout; - void SetLayout(BLayout* layout); - BLayout* fLayout; void* fLayoutData; }; Index: headers/os/interface/AbstractLayout.h =================================================================== --- headers/os/interface/AbstractLayout.h (revision 0) +++ headers/os/interface/AbstractLayout.h (revision 0) @@ -0,0 +1,54 @@ +/* + * Copyright 2010, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _ABSTRACT_LAYOUT_H +#define _ABSTRACT_LAYOUT_H + +#include +#include +#include + +class BAbstractLayout : public BLayout { +public: + BAbstractLayout(); + BAbstractLayout(BMessage* from); + virtual ~BAbstractLayout(); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + virtual void SetExplicitMinSize(BSize size); + virtual void SetExplicitMaxSize(BSize size); + virtual void SetExplicitPreferredSize(BSize size); + virtual void SetExplicitAlignment(BAlignment alignment); + + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); + + virtual BRect Frame(); + virtual void SetFrame(BRect frame); + + virtual bool IsVisible(); + virtual void SetVisible(bool visible); + + virtual status_t Archive(BMessage* into, bool deep = true) const; + virtual status_t AllUnarchived(const BMessage* from); + +protected: + virtual void OwnerChanged(BView* was); + virtual void AncestorVisibilityChanged(bool shown); + +private: + struct Proxy; + struct ViewProxy; + struct DataProxy; + + Proxy* fExplicitData; +}; + +#endif // _ABSTRACT_LAYOUT_ITEM_H Index: headers/libs/alm/BALMLayout.h =================================================================== --- headers/libs/alm/BALMLayout.h (revision 38092) +++ headers/libs/alm/BALMLayout.h (working copy) @@ -7,8 +7,8 @@ #ifndef BALM_LAYOUT_H #define BALM_LAYOUT_H +#include #include -#include #include #include #include @@ -29,7 +29,7 @@ /** * A GUI layout engine using the ALM. */ -class BALMLayout : public BLayout, public LinearSpec { +class BALMLayout : public BAbstractLayout, public LinearSpec { public: BALMLayout(); @@ -70,15 +70,15 @@ bool RemoveItem(BLayoutItem* item); BLayoutItem* RemoveItem(int32 index); - BSize MinSize(); - BSize MaxSize(); - BSize PreferredSize(); - BAlignment Alignment(); + BSize BaseMinSize(); + BSize BaseMaxSize(); + BSize BasePreferredSize(); + BAlignment BaseAlignment(); bool HasHeightForWidth(); void GetHeightForWidth(float width, float* min, float* max, float* preferred); - void InvalidateLayout(); - void LayoutView(); + void InvalidateLayout(bool children = false); + virtual void DerivedLayoutItems(); char* PerformancePath() const; void SetPerformancePath(char* path); Index: headers/private/interface/ViewPrivate.h =================================================================== --- headers/private/interface/ViewPrivate.h (revision 38092) +++ headers/private/interface/ViewPrivate.h (working copy) @@ -16,6 +16,7 @@ #include #include #include +#include const static uint32 kDeleteReplicant = 'JAHA'; @@ -48,6 +49,25 @@ }; +class BView::Private { +public: + Private(BView* view) + : + fView(view) + { + } + + int16 ShowLevel() + { + return fView->fShowLevel; + } + + bool MinMaxValid(); + + BView* fView; +}; + + namespace BPrivate { class PortLink;