xref: /haiku/src/kits/interface/ViewPort.cpp (revision 9f81ca838ce7b92b5689e57d3f86765db4705a7b)
1 /*
2  * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <ViewPort.h>
8 
9 #include <algorithm>
10 
11 #include <AbstractLayout.h>
12 #include <ScrollBar.h>
13 
14 #include "ViewLayoutItem.h"
15 
16 
17 namespace BPrivate {
18 
19 
20 // #pragma mark - ViewPortLayout
21 
22 
23 class BViewPort::ViewPortLayout : public BAbstractLayout {
24 public:
ViewPortLayout(BViewPort * viewPort)25 	ViewPortLayout(BViewPort* viewPort)
26 		:
27 		BAbstractLayout(),
28 		fViewPort(viewPort),
29 		fHasViewChild(false),
30 		fIsCacheValid(false),
31 		fMin(),
32 		fMax(),
33 		fPreferred()
34 	{
35 	}
36 
ChildView() const37 	BView* ChildView() const
38 	{
39 		if (!fHasViewChild)
40 			return NULL;
41 		if (BViewLayoutItem* item = dynamic_cast<BViewLayoutItem*>(ItemAt(0)))
42 			return item->View();
43 		return NULL;
44 	}
45 
SetChildView(BView * view)46 	void SetChildView(BView* view)
47 	{
48 		_UnsetChild();
49 
50 		if (view != NULL && AddView(0, view) != NULL)
51 			fHasViewChild = true;
52 	}
53 
ChildItem() const54 	BLayoutItem* ChildItem() const
55 	{
56 		return ItemAt(0);
57 	}
58 
SetChildItem(BLayoutItem * item)59 	void SetChildItem(BLayoutItem* item)
60 	{
61 		_UnsetChild();
62 
63 		if (item != NULL)
64 			AddItem(0, item);
65 	}
66 
BaseMinSize()67 	virtual BSize BaseMinSize()
68 	{
69 		_ValidateMinMax();
70 		return fMin;
71 	}
72 
BaseMaxSize()73 	virtual BSize BaseMaxSize()
74 	{
75 		_ValidateMinMax();
76 		return fMax;
77 	}
78 
BasePreferredSize()79 	virtual BSize BasePreferredSize()
80 	{
81 		_ValidateMinMax();
82 		return fPreferred;
83 	}
84 
BaseAlignment()85 	virtual BAlignment BaseAlignment()
86 	{
87 		return BAbstractLayout::BaseAlignment();
88 	}
89 
HasHeightForWidth()90 	virtual bool HasHeightForWidth()
91 	{
92 		_ValidateMinMax();
93 		return false;
94 		// TODO: Support height-for-width!
95 	}
96 
GetHeightForWidth(float width,float * min,float * max,float * preferred)97 	virtual void GetHeightForWidth(float width, float* min, float* max,
98 		float* preferred)
99 	{
100 		if (!HasHeightForWidth())
101 			return;
102 
103 		// TODO: Support height-for-width!
104 	}
105 
LayoutInvalidated(bool children)106 	virtual void LayoutInvalidated(bool children)
107 	{
108 		fIsCacheValid = false;
109 	}
110 
DoLayout()111 	virtual void DoLayout()
112 	{
113 		_ValidateMinMax();
114 
115 		BLayoutItem* child = ItemAt(0);
116 		if (child == NULL)
117 			return;
118 
119 		// Determine the layout area: LayoutArea() will only give us the size
120 		// of the view port's frame.
121 		BSize viewSize = LayoutArea().Size();
122 		BSize layoutSize = viewSize;
123 
124 		BSize childMin = child->MinSize();
125 		BSize childMax = child->MaxSize();
126 
127 		// apply the maximum constraints
128 		layoutSize.width = std::min(layoutSize.width, childMax.width);
129 		layoutSize.height = std::min(layoutSize.height, childMax.height);
130 
131 		// apply the minimum constraints
132 		layoutSize.width = std::max(layoutSize.width, childMin.width);
133 		layoutSize.height = std::max(layoutSize.height, childMin.height);
134 
135 		// TODO: Support height-for-width!
136 
137 		child->AlignInFrame(BRect(BPoint(0, 0), layoutSize));
138 
139 		_UpdateScrollBar(fViewPort->ScrollBar(B_HORIZONTAL), viewSize.width,
140 			layoutSize.width);
141 		_UpdateScrollBar(fViewPort->ScrollBar(B_VERTICAL), viewSize.height,
142 			layoutSize.height);
143 	}
144 
145 private:
_UnsetChild()146 	void _UnsetChild()
147 	{
148 		if (CountItems() > 0) {
149 			BLayoutItem* item = RemoveItem((int32)0);
150 			if (fHasViewChild)
151 				delete item;
152 			fHasViewChild = false;
153 		}
154 	}
155 
_ValidateMinMax()156 	void _ValidateMinMax()
157 	{
158 		if (fIsCacheValid)
159 			return;
160 
161 		if (BLayoutItem* child = ItemAt(0)) {
162 			fMin = child->MinSize();
163 			if (_IsHorizontallyScrollable())
164 				fMin.width = -1;
165 			if (_IsVerticallyScrollable())
166 				fMin.height = -1;
167 			fMax = child->MaxSize();
168 			fPreferred = child->PreferredSize();
169 			// TODO: Support height-for-width!
170 		} else {
171 			fMin.Set(-1, -1);
172 			fMax.Set(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
173 			fPreferred.Set(20, 20);
174 		}
175 
176 		fIsCacheValid = true;
177 	}
178 
_IsHorizontallyScrollable() const179 	bool _IsHorizontallyScrollable() const
180 	{
181 		return fViewPort->ScrollBar(B_HORIZONTAL) != NULL;
182 	}
183 
_IsVerticallyScrollable() const184 	bool _IsVerticallyScrollable() const
185 	{
186 		return fViewPort->ScrollBar(B_VERTICAL) != NULL;
187 	}
188 
_UpdateScrollBar(BScrollBar * scrollBar,float viewPortSize,float dataSize)189 	void _UpdateScrollBar(BScrollBar* scrollBar, float viewPortSize,
190 		float dataSize)
191 	{
192 		if (scrollBar == NULL)
193 			return;
194 
195 		if (viewPortSize < dataSize) {
196 			scrollBar->SetRange(0, dataSize - viewPortSize);
197 			scrollBar->SetProportion(viewPortSize / dataSize);
198 			float smallStep;
199 			scrollBar->GetSteps(&smallStep, NULL);
200 			scrollBar->SetSteps(smallStep, viewPortSize);
201 		} else {
202 			scrollBar->SetRange(0, 0);
203 			scrollBar->SetProportion(1);
204 		}
205 	}
206 
207 private:
208 	BViewPort*	fViewPort;
209 	bool		fHasViewChild;
210 	bool		fIsCacheValid;
211 	BSize		fMin;
212 	BSize		fMax;
213 	BSize		fPreferred;
214 };
215 
216 
217 // #pragma mark - BViewPort
218 
219 
BViewPort(BView * child)220 BViewPort::BViewPort(BView* child)
221 	:
222 	BView(NULL, 0),
223 	fChild(NULL)
224 {
225 	_Init();
226 	SetChildView(child);
227 }
228 
229 
BViewPort(BLayoutItem * child)230 BViewPort::BViewPort(BLayoutItem* child)
231 	:
232 	BView(NULL, 0),
233 	fChild(NULL)
234 {
235 	_Init();
236 	SetChildItem(child);
237 }
238 
239 
BViewPort(const char * name,BView * child)240 BViewPort::BViewPort(const char* name, BView* child)
241 	:
242 	BView(name, 0),
243 	fChild(NULL)
244 {
245 	_Init();
246 	SetChildView(child);
247 }
248 
249 
BViewPort(const char * name,BLayoutItem * child)250 BViewPort::BViewPort(const char* name, BLayoutItem* child)
251 	:
252 	BView(name, 0),
253 	fChild(NULL)
254 {
255 	_Init();
256 	SetChildItem(child);
257 }
258 
259 
~BViewPort()260 BViewPort::~BViewPort()
261 {
262 }
263 
264 
265 BView*
ChildView() const266 BViewPort::ChildView() const
267 {
268 	return fLayout->ChildView();
269 }
270 
271 
272 void
SetChildView(BView * child)273 BViewPort::SetChildView(BView* child)
274 {
275 	fLayout->SetChildView(child);
276 	InvalidateLayout();
277 }
278 
279 
280 BLayoutItem*
ChildItem() const281 BViewPort::ChildItem() const
282 {
283 	return fLayout->ChildItem();
284 }
285 
286 
287 void
SetChildItem(BLayoutItem * child)288 BViewPort::SetChildItem(BLayoutItem* child)
289 {
290 	fLayout->SetChildItem(child);
291 	InvalidateLayout();
292 }
293 
294 
295 void
_Init()296 BViewPort::_Init()
297 {
298 	fLayout = new ViewPortLayout(this);
299 	SetLayout(fLayout);
300 }
301 
302 
303 }	// namespace BPrivate
304 
305 
306 using ::BPrivate::BViewPort;
307