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