diff --git a/headers/private/interface/ViewPort.h b/headers/private/interface/ViewPort.h new file mode 100644 index 0000000000..cee7afb36a --- /dev/null +++ b/headers/private/interface/ViewPort.h @@ -0,0 +1,53 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ +#ifndef _VIEW_PORT_H +#define _VIEW_PORT_H + + +#include + + +namespace BPrivate { + + +class BViewPort : public BView { +public: + BViewPort(BView* child = NULL); + BViewPort(BLayoutItem* child); + BViewPort(const char* name, + BView* child = NULL); + BViewPort(const char* name, + BLayoutItem* child); + virtual ~BViewPort(); + + BView* ChildView() const; + void SetChildView(BView* child); + + BLayoutItem* ChildItem() const; + void SetChildItem(BLayoutItem* child); + +private: + class ViewPortLayout; + friend class ViewPortLayout; + +private: + void _Init(); + +private: + ViewPortLayout* fLayout; + BLayoutItem* fChild; +}; + + +} // namespace BPrivate + + +using ::BPrivate::BViewPort; + + +#endif // _VIEW_PORT_H diff --git a/src/kits/interface/Jamfile b/src/kits/interface/Jamfile index 5fe62156ad..ad31fd28f3 100644 --- a/src/kits/interface/Jamfile +++ b/src/kits/interface/Jamfile @@ -129,6 +129,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { TwoDimensionalLayout.cpp View.cpp ViewLayoutItem.cpp + ViewPort.cpp Window.cpp WindowStack.cpp ZombieReplicantView.cpp diff --git a/src/kits/interface/ViewPort.cpp b/src/kits/interface/ViewPort.cpp new file mode 100644 index 0000000000..c2ea225611 --- /dev/null +++ b/src/kits/interface/ViewPort.cpp @@ -0,0 +1,306 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include +#include + +#include "ViewLayoutItem.h" + + +namespace BPrivate { + + +// #pragma mark - ViewPortLayout + + +class BViewPort::ViewPortLayout : public BAbstractLayout { +public: + ViewPortLayout(BViewPort* viewPort) + : + BAbstractLayout(), + fViewPort(viewPort), + fHasViewChild(false), + fIsCacheValid(false), + fMin(), + fMax(), + fPreferred() + { + } + + BView* ChildView() const + { + if (!fHasViewChild) + return NULL; + if (BViewLayoutItem* item = dynamic_cast(ItemAt(0))) + return item->View(); + return NULL; + } + + void SetChildView(BView* view) + { + _UnsetChild(); + + if (view != NULL && AddView(0, view) != NULL) + fHasViewChild = true; + } + + BLayoutItem* ChildItem() const + { + return ItemAt(0); + } + + void SetChildItem(BLayoutItem* item) + { + _UnsetChild(); + + if (item != NULL) + AddItem(0, item); + } + + virtual BSize BaseMinSize() + { + _ValidateMinMax(); + return fMin; + } + + virtual BSize BaseMaxSize() + { + _ValidateMinMax(); + return fMax; + } + + virtual BSize BasePreferredSize() + { + _ValidateMinMax(); + return fPreferred; + } + + virtual BAlignment BaseAlignment() + { + return BAbstractLayout::BaseAlignment(); + } + + virtual bool HasHeightForWidth() + { + _ValidateMinMax(); + return false; + // TODO: Support height-for-width! + } + + virtual void GetHeightForWidth(float width, float* min, float* max, + float* preferred) + { + if (!HasHeightForWidth()) + return; + + // TODO: Support height-for-width! + } + + virtual void LayoutInvalidated(bool children) + { + fIsCacheValid = false; + } + + virtual void DoLayout() + { + _ValidateMinMax(); + + BLayoutItem* child = ItemAt(0); + if (child == NULL) + return; + + // Determine the layout area: LayoutArea() will only give us the size + // of the view port's frame. + BSize viewSize = LayoutArea().Size(); + BSize layoutSize = viewSize; + + BSize childMin = child->MinSize(); + BSize childMax = child->MaxSize(); + + // apply the maximum constraints + layoutSize.width = std::min(layoutSize.width, childMax.width); + layoutSize.height = std::min(layoutSize.height, childMax.height); + + // apply the minimum constraints + layoutSize.width = std::max(layoutSize.width, childMin.width); + layoutSize.height = std::max(layoutSize.height, childMin.height); + + // TODO: Support height-for-width! + + child->AlignInFrame(BRect(BPoint(0, 0), layoutSize)); + + _UpdateScrollBar(fViewPort->ScrollBar(B_HORIZONTAL), viewSize.width, + layoutSize.width); + _UpdateScrollBar(fViewPort->ScrollBar(B_VERTICAL), viewSize.height, + layoutSize.height); + } + +private: + void _UnsetChild() + { + if (CountItems() > 0) { + BLayoutItem* item = RemoveItem((int32)0); + if (fHasViewChild) + delete item; + fHasViewChild = false; + } + } + + void _ValidateMinMax() + { + if (fIsCacheValid) + return; + + if (BLayoutItem* child = ItemAt(0)) { + fMin = child->MinSize(); + if (_IsHorizontallyScrollable()) + fMin.width = -1; + if (_IsVerticallyScrollable()) + fMin.height = -1; + fMax = child->MaxSize(); + fPreferred = child->PreferredSize(); + // TODO: Support height-for-width! + } else { + fMin.Set(-1, -1); + fMax.Set(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); + fPreferred.Set(20, 20); + } + + fIsCacheValid = true; + } + + bool _IsHorizontallyScrollable() const + { + return fViewPort->ScrollBar(B_HORIZONTAL) != NULL; + } + + bool _IsVerticallyScrollable() const + { + return fViewPort->ScrollBar(B_VERTICAL) != NULL; + } + + void _UpdateScrollBar(BScrollBar* scrollBar, float viewPortSize, + float dataSize) + { + if (scrollBar == NULL) + return; + + if (viewPortSize < dataSize) { + scrollBar->SetRange(0, dataSize - viewPortSize); + scrollBar->SetProportion(viewPortSize / dataSize); + float smallStep; + scrollBar->GetSteps(&smallStep, NULL); + scrollBar->SetSteps(smallStep, viewPortSize); + } else { + scrollBar->SetRange(0, 0); + scrollBar->SetProportion(1); + } + } + +private: + BViewPort* fViewPort; + bool fHasViewChild; + bool fIsCacheValid; + BSize fMin; + BSize fMax; + BSize fPreferred; +}; + + +// #pragma mark - BViewPort + + +BViewPort::BViewPort(BView* child) + : + BView(NULL, 0), + fChild(NULL) +{ + _Init(); + SetChildView(child); +} + + +BViewPort::BViewPort(BLayoutItem* child) + : + BView(NULL, 0), + fChild(NULL) +{ + _Init(); + SetChildItem(child); +} + + +BViewPort::BViewPort(const char* name, BView* child) + : + BView(name, 0), + fChild(NULL) +{ + _Init(); + SetChildView(child); +} + + +BViewPort::BViewPort(const char* name, BLayoutItem* child) + : + BView(name, 0), + fChild(NULL) +{ + _Init(); + SetChildItem(child); +} + + +BViewPort::~BViewPort() +{ +} + + +BView* +BViewPort::ChildView() const +{ + return fLayout->ChildView(); +} + + +void +BViewPort::SetChildView(BView* child) +{ + fLayout->SetChildView(child); + InvalidateLayout(); +} + + +BLayoutItem* +BViewPort::ChildItem() const +{ + return fLayout->ChildItem(); +} + + +void +BViewPort::SetChildItem(BLayoutItem* child) +{ + fLayout->SetChildItem(child); + InvalidateLayout(); +} + + +void +BViewPort::_Init() +{ + fLayout = new ViewPortLayout(this); + SetLayout(fLayout); +} + + +} // namespace BPrivate + + +using ::BPrivate::BViewPort;