xref: /haiku/src/tests/kits/interface/layout/widget_layout_test/View.cpp (revision 4b5501d29dca8c24507a125b2d3b7350e1cb727d)
1 /*
2  * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include "View.h"
7 
8 #include <stdio.h>
9 
10 #include <Region.h>
11 #include <View.h>
12 
13 
View()14 View::View()
15 	: fFrame(0, 0, 0, 0),
16 	  fContainer(NULL),
17 	  fParent(NULL),
18 	  fChildren(),
19 	  fViewColor(B_TRANSPARENT_32_BIT),
20 	  fLayoutValid(false)
21 {
22 }
23 
24 
View(BRect frame)25 View::View(BRect frame)
26 	: fFrame(frame),
27 	  fContainer(NULL),
28 	  fParent(NULL),
29 	  fChildren(),
30 	  fViewColor(B_TRANSPARENT_32_BIT),
31 	  fLayoutValid(false)
32 {
33 }
34 
35 
~View()36 View::~View()
37 {
38 	// delete children
39 	for (int32 i = CountChildren() - 1; i >= 0; i--)
40 		delete RemoveChild(i);
41 }
42 
43 
44 void
SetFrame(BRect frame)45 View::SetFrame(BRect frame)
46 {
47 	if (frame != fFrame && frame.IsValid()) {
48 		BRect oldFrame(frame);
49 		Invalidate();
50 		fFrame = frame;
51 		Invalidate();
52 
53 		FrameChanged(oldFrame, frame);
54 	}
55 
56 	// relayout if necessary
57 	if (!fLayoutValid) {
58 		Layout();
59 		fLayoutValid = true;
60 	}
61 }
62 
63 
64 BRect
Frame() const65 View::Frame() const
66 {
67 	return fFrame;
68 }
69 
70 
71 BRect
Bounds() const72 View::Bounds() const
73 {
74 	return BRect(fFrame).OffsetToCopy(B_ORIGIN);
75 }
76 
77 
78 void
SetLocation(BPoint location)79 View::SetLocation(BPoint location)
80 {
81 	SetFrame(fFrame.OffsetToCopy(location));
82 }
83 
84 
85 BPoint
Location() const86 View::Location() const
87 {
88 	return fFrame.LeftTop();
89 }
90 
91 
92 void
SetSize(BSize size)93 View::SetSize(BSize size)
94 {
95 	BRect frame(fFrame);
96 	frame.right = frame.left + size.width;
97 	frame.bottom = frame.top + size.height;
98 	SetFrame(frame);
99 }
100 
101 
102 BSize
Size() const103 View::Size() const
104 {
105 	return Frame().Size();
106 }
107 
108 
109 BSize
MinSize()110 View::MinSize()
111 {
112 	return BSize(-1, -1);
113 }
114 
115 
116 BSize
MaxSize()117 View::MaxSize()
118 {
119 	return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
120 }
121 
122 
123 BSize
PreferredSize()124 View::PreferredSize()
125 {
126 	return MinSize();
127 }
128 
129 
130 BAlignment
Alignment()131 View::Alignment()
132 {
133 	return BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER);
134 }
135 
136 
137 BPoint
LocationInContainer() const138 View::LocationInContainer() const
139 {
140 	BPoint location = fFrame.LeftTop();
141 	return (fParent ? fParent->LocationInContainer() + location : location);
142 }
143 
144 
145 BRect
FrameInContainer() const146 View::FrameInContainer() const
147 {
148 	BRect frame(fFrame);
149 	return frame.OffsetToCopy(LocationInContainer());
150 }
151 
152 
153 BPoint
ConvertFromContainer(BPoint point) const154 View::ConvertFromContainer(BPoint point) const
155 {
156 	return point - LocationInContainer();
157 }
158 
159 
160 BRect
ConvertFromContainer(BRect rect) const161 View::ConvertFromContainer(BRect rect) const
162 {
163 	return rect.OffsetBySelf(-LocationInContainer());
164 }
165 
166 
167 BPoint
ConvertToContainer(BPoint point) const168 View::ConvertToContainer(BPoint point) const
169 {
170 	return point + LocationInContainer();
171 }
172 
173 
174 BRect
ConvertToContainer(BRect rect) const175 View::ConvertToContainer(BRect rect) const
176 {
177 	return rect.OffsetBySelf(LocationInContainer());
178 }
179 
180 
181 View*
Parent() const182 View::Parent() const
183 {
184 	return fParent;
185 }
186 
187 
188 BView*
Container() const189 View::Container() const
190 {
191 	return fContainer;
192 }
193 
194 
195 bool
AddChild(View * child)196 View::AddChild(View* child)
197 {
198 	if (!child)
199 		return false;
200 
201 	if (child->Parent() || child->Container()) {
202 		fprintf(stderr, "View::AddChild(): view %p already has a parent "
203 			"or is the container view\n", child);
204 		return false;
205 	}
206 
207 	if (!fChildren.AddItem(child))
208 		return false;
209 
210 	child->_AddedToParent(this);
211 
212 	child->Invalidate();
213 	InvalidateLayout();
214 
215 	return true;
216 }
217 
218 
219 bool
RemoveChild(View * child)220 View::RemoveChild(View* child)
221 {
222 	if (!child)
223 		return false;
224 
225 	return RemoveChild(IndexOfChild(child));
226 }
227 
228 
229 View*
RemoveChild(int32 index)230 View::RemoveChild(int32 index)
231 {
232 	if (index < 0 || index >= fChildren.CountItems())
233 		return NULL;
234 
235 	View* child = ChildAt(index);
236 	child->Invalidate();
237 	child->_RemovingFromParent();
238 	fChildren.RemoveItem(index);
239 
240 	InvalidateLayout();
241 
242 	return child;
243 }
244 
245 
246 int32
CountChildren() const247 View::CountChildren() const
248 {
249 	return fChildren.CountItems();
250 }
251 
252 
253 View*
ChildAt(int32 index) const254 View::ChildAt(int32 index) const
255 {
256 	return (View*)fChildren.ItemAt(index);
257 }
258 
259 
260 View*
ChildAt(BPoint point) const261 View::ChildAt(BPoint point) const
262 {
263 	for (int32 i = 0; View* child = ChildAt(i); i++) {
264 		if (child->Frame().Contains(point))
265 			return child;
266 	}
267 
268 	return NULL;
269 }
270 
271 
272 View*
AncestorAt(BPoint point,BPoint * localPoint) const273 View::AncestorAt(BPoint point, BPoint* localPoint) const
274 {
275 	if (!Bounds().Contains(point))
276 		return NULL;
277 
278 	View* view = const_cast<View*>(this);
279 
280 	// Iterate deeper down the hierarchy, until we reach a view that
281 	// doesn't have a child at the location.
282 	while (true) {
283 		View* child = view->ChildAt(point);
284 		if (!child) {
285 			if (localPoint)
286 				*localPoint = point;
287 			return view;
288 		}
289 
290 		view = child;
291 		point -= view->Frame().LeftTop();
292 	}
293 }
294 
295 
296 int32
IndexOfChild(View * child) const297 View::IndexOfChild(View* child) const
298 {
299 	return (child ? fChildren.IndexOf(child) : -1);
300 }
301 
302 
303 void
Invalidate(BRect rect)304 View::Invalidate(BRect rect)
305 {
306 	if (fContainer) {
307 		rect = rect & Bounds();
308 		fContainer->Invalidate(rect.OffsetByCopy(LocationInContainer()));
309 	}
310 }
311 
312 
313 void
Invalidate()314 View::Invalidate()
315 {
316 	Invalidate(Bounds());
317 }
318 
319 
320 void
InvalidateLayout()321 View::InvalidateLayout()
322 {
323 //printf("%p->View::InvalidateLayout(): %d\n", this, fLayoutValid);
324 	if (fLayoutValid) {
325 		fLayoutValid = false;
326 		if (fParent)
327 			fParent->InvalidateLayout();
328 	}
329 }
330 
331 
332 bool
IsLayoutValid() const333 View::IsLayoutValid() const
334 {
335 	return fLayoutValid;
336 }
337 
338 
339 void
SetViewColor(rgb_color color)340 View::SetViewColor(rgb_color color)
341 {
342 	fViewColor = color;
343 }
344 
345 
346 void
Draw(BView * container,BRect updateRect)347 View::Draw(BView* container, BRect updateRect)
348 {
349 }
350 
351 
352 void
MouseDown(BPoint where,uint32 buttons,int32 modifiers)353 View::MouseDown(BPoint where, uint32 buttons, int32 modifiers)
354 {
355 }
356 
357 
358 void
MouseUp(BPoint where,uint32 buttons,int32 modifiers)359 View::MouseUp(BPoint where, uint32 buttons, int32 modifiers)
360 {
361 }
362 
363 
364 void
MouseMoved(BPoint where,uint32 buttons,int32 modifiers)365 View::MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
366 {
367 }
368 
369 
370 void
AddedToContainer()371 View::AddedToContainer()
372 {
373 }
374 
375 
376 void
RemovingFromContainer()377 View::RemovingFromContainer()
378 {
379 }
380 
381 
382 void
FrameChanged(BRect oldFrame,BRect newFrame)383 View::FrameChanged(BRect oldFrame, BRect newFrame)
384 {
385 }
386 
387 
388 void
Layout()389 View::Layout()
390 {
391 	// simply trigger relayouting the children
392 	for (int32 i = 0; View* child = ChildAt(i); i++)
393 		child->SetFrame(child->Frame());
394 }
395 
396 
397 void
_AddedToParent(View * parent)398 View::_AddedToParent(View* parent)
399 {
400 	fParent = parent;
401 
402 	if (parent->Container()) {
403 		Invalidate();
404 		_AddedToContainer(parent->Container());
405 	}
406 }
407 
408 
409 void
_RemovingFromParent()410 View::_RemovingFromParent()
411 {
412 	if (fContainer)
413 		_RemovingFromContainer();
414 
415 	fParent = NULL;
416 }
417 
418 
419 void
_AddedToContainer(BView * container)420 View::_AddedToContainer(BView* container)
421 {
422 	fContainer = container;
423 
424 	AddedToContainer();
425 
426 	for (int32 i = 0; View* child = ChildAt(i); i++)
427 		child->_AddedToContainer(fContainer);
428 }
429 
430 
431 void
_RemovingFromContainer()432 View::_RemovingFromContainer()
433 {
434 	for (int32 i = 0; View* child = ChildAt(i); i++)
435 		child->_RemovingFromContainer();
436 
437 	RemovingFromContainer();
438 
439 	fContainer = NULL;
440 }
441 
442 
443 void
_Draw(BView * container,BRect updateRect)444 View::_Draw(BView* container, BRect updateRect)
445 {
446 	// compute the clipping region
447 	BRegion region(Bounds());
448 	for (int32 i = 0; View* child = ChildAt(i); i++)
449 		region.Exclude(child->Frame());
450 
451 	if (region.Frame().IsValid()) {
452 		// set the clipping region
453 		container->ConstrainClippingRegion(&region);
454 
455 		// draw the background, if it isn't transparent
456 		if (fViewColor.alpha != 0) {
457 			container->SetLowColor(fViewColor);
458 			container->FillRect(updateRect, B_SOLID_LOW);
459 		}
460 
461 		// draw this view
462 		Draw(container, updateRect);
463 
464 		// revert the clipping region
465 		region.Set(Bounds());
466 		container->ConstrainClippingRegion(&region);
467 	}
468 
469 	// draw the children
470 	if (CountChildren() > 0) {
471 		container->PushState();
472 
473 		for (int32 i = 0; View* child = ChildAt(i); i++) {
474 			BRect childFrame = child->Frame();
475 			BRect childUpdateRect = updateRect & childFrame;
476 			if (childUpdateRect.IsValid()) {
477 				// set origin
478 				childUpdateRect.OffsetBy(-childFrame.LeftTop());
479 				container->SetOrigin(childFrame.LeftTop());
480 
481 				// draw
482 				child->_Draw(container, childUpdateRect);
483 			}
484 		}
485 
486 		container->PopState();
487 	}
488 }
489