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 14View::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 25View::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 36View::~View() 37{ 38 // delete children 39 for (int32 i = CountChildren() - 1; i >= 0; i--) 40 delete RemoveChild(i); 41} 42 43 44void 45View::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 64BRect 65View::Frame() const 66{ 67 return fFrame; 68} 69 70 71BRect 72View::Bounds() const 73{ 74 return BRect(fFrame).OffsetToCopy(B_ORIGIN); 75} 76 77 78void 79View::SetLocation(BPoint location) 80{ 81 SetFrame(fFrame.OffsetToCopy(location)); 82} 83 84 85BPoint 86View::Location() const 87{ 88 return fFrame.LeftTop(); 89} 90 91 92void 93View::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 102BSize 103View::Size() const 104{ 105 return Frame().Size(); 106} 107 108 109BSize 110View::MinSize() 111{ 112 return BSize(-1, -1); 113} 114 115 116BSize 117View::MaxSize() 118{ 119 return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); 120} 121 122 123BSize 124View::PreferredSize() 125{ 126 return MinSize(); 127} 128 129 130BAlignment 131View::Alignment() 132{ 133 return BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER); 134} 135 136 137BPoint 138View::LocationInContainer() const 139{ 140 BPoint location = fFrame.LeftTop(); 141 return (fParent ? fParent->LocationInContainer() + location : location); 142} 143 144 145BRect 146View::FrameInContainer() const 147{ 148 BRect frame(fFrame); 149 return frame.OffsetToCopy(LocationInContainer()); 150} 151 152 153BPoint 154View::ConvertFromContainer(BPoint point) const 155{ 156 return point - LocationInContainer(); 157} 158 159 160BRect 161View::ConvertFromContainer(BRect rect) const 162{ 163 return rect.OffsetBySelf(-LocationInContainer()); 164} 165 166 167BPoint 168View::ConvertToContainer(BPoint point) const 169{ 170 return point + LocationInContainer(); 171} 172 173 174BRect 175View::ConvertToContainer(BRect rect) const 176{ 177 return rect.OffsetBySelf(LocationInContainer()); 178} 179 180 181View* 182View::Parent() const 183{ 184 return fParent; 185} 186 187 188BView* 189View::Container() const 190{ 191 return fContainer; 192} 193 194 195bool 196View::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 219bool 220View::RemoveChild(View* child) 221{ 222 if (!child) 223 return false; 224 225 return RemoveChild(IndexOfChild(child)); 226} 227 228 229View* 230View::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 246int32 247View::CountChildren() const 248{ 249 return fChildren.CountItems(); 250} 251 252 253View* 254View::ChildAt(int32 index) const 255{ 256 return (View*)fChildren.ItemAt(index); 257} 258 259 260View* 261View::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 272View* 273View::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 296int32 297View::IndexOfChild(View* child) const 298{ 299 return (child ? fChildren.IndexOf(child) : -1); 300} 301 302 303void 304View::Invalidate(BRect rect) 305{ 306 if (fContainer) { 307 rect = rect & Bounds(); 308 fContainer->Invalidate(rect.OffsetByCopy(LocationInContainer())); 309 } 310} 311 312 313void 314View::Invalidate() 315{ 316 Invalidate(Bounds()); 317} 318 319 320void 321View::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 332bool 333View::IsLayoutValid() const 334{ 335 return fLayoutValid; 336} 337 338 339void 340View::SetViewColor(rgb_color color) 341{ 342 fViewColor = color; 343} 344 345 346void 347View::Draw(BView* container, BRect updateRect) 348{ 349} 350 351 352void 353View::MouseDown(BPoint where, uint32 buttons, int32 modifiers) 354{ 355} 356 357 358void 359View::MouseUp(BPoint where, uint32 buttons, int32 modifiers) 360{ 361} 362 363 364void 365View::MouseMoved(BPoint where, uint32 buttons, int32 modifiers) 366{ 367} 368 369 370void 371View::AddedToContainer() 372{ 373} 374 375 376void 377View::RemovingFromContainer() 378{ 379} 380 381 382void 383View::FrameChanged(BRect oldFrame, BRect newFrame) 384{ 385} 386 387 388void 389View::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 397void 398View::_AddedToParent(View* parent) 399{ 400 fParent = parent; 401 402 if (parent->Container()) { 403 Invalidate(); 404 _AddedToContainer(parent->Container()); 405 } 406} 407 408 409void 410View::_RemovingFromParent() 411{ 412 if (fContainer) 413 _RemovingFromContainer(); 414 415 fParent = NULL; 416} 417 418 419void 420View::_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 431void 432View::_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 443void 444View::_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