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(®ion);
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(®ion);
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