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