1 #include <OS.h> 2 #include <Region.h> 3 #include <Rect.h> 4 #include <stdio.h> 5 #include <strings.h> 6 7 #include <Window.h> 8 9 #include "Layer.h" 10 #include "MyView.h" 11 12 extern BWindow* wind; 13 14 Layer::Layer(BRect frame, const char* name, uint32 rm, uint32 flags, rgb_color c) 15 { 16 fFrame = frame; 17 fOrigin.Set(0.0f, 0.0f); 18 fResizeMode = rm; 19 fFlags = flags; 20 fColor = c; 21 22 fBottom = NULL; 23 fUpper = NULL; 24 fLower = NULL; 25 fTop = NULL; 26 fParent = NULL; 27 fView = NULL; 28 fCurrent = NULL; 29 fHidden = false; 30 31 strcpy(fName, name); 32 } 33 34 Layer::~Layer() 35 { 36 Layer *c = fBottom; 37 Layer *toast; 38 while (c) { 39 toast = c; 40 c = c->fUpper; 41 delete toast; 42 } 43 } 44 45 void 46 Layer::ConvertToScreen2(BRect* rect) const 47 { 48 if (GetRootLayer()) 49 if (fParent) { 50 rect->OffsetBy(-fOrigin.x, -fOrigin.y); 51 rect->OffsetBy(fFrame.left, fFrame.top); 52 53 fParent->ConvertToScreen2(rect); 54 } 55 } 56 57 void 58 Layer::ConvertToScreen2(BRegion* reg) const 59 { 60 if (GetRootLayer()) 61 if (fParent) { 62 reg->OffsetBy(-fOrigin.x, -fOrigin.y); 63 reg->OffsetBy(fFrame.left, fFrame.top); 64 65 fParent->ConvertToScreen2(reg); 66 } 67 } 68 69 MyView* 70 Layer::GetRootLayer() const // we already have 71 { 72 if (fView) 73 return fView; 74 else 75 if (fParent) 76 return fParent->GetRootLayer(); 77 else 78 return NULL; 79 } 80 81 Layer* 82 Layer::BottomChild() const // we already have 83 { 84 fCurrent = fBottom; 85 return fCurrent; 86 } 87 88 Layer* 89 Layer::TopChild() const// we already have 90 { 91 fCurrent = fTop; 92 return fCurrent; 93 } 94 95 Layer* 96 Layer::UpperSibling() const// we already have 97 { 98 fCurrent = fCurrent->fUpper; 99 return fCurrent; 100 } 101 102 Layer* 103 Layer::LowerSibling() const// we already have 104 { 105 fCurrent = fCurrent->fLower; 106 return fCurrent; 107 } 108 109 void 110 Layer::AddLayer(Layer* layer)// we already have 111 { 112 if( layer->fParent != NULL ) { 113 printf("ERROR: Layer already has a parent\n"); 114 return; 115 } 116 117 layer->fParent = this; 118 119 if (!fBottom) { 120 fBottom = layer; 121 fTop = layer; 122 return; 123 } 124 fBottom->fLower = layer; 125 layer->fUpper = fBottom; 126 fBottom = layer; 127 } 128 129 bool 130 Layer::RemLayer(Layer* layer)// we already have 131 { 132 if(!layer->fParent || layer->fParent != this) { 133 printf("ERROR: Rem: Layer doesn't have a fParent or !=this\n"); 134 return false; 135 } 136 137 layer->fParent = NULL; 138 139 if(fTop == layer) 140 fTop = layer->fLower; 141 142 if(fBottom == layer ) 143 fBottom = layer->fUpper; 144 145 if(layer->fUpper != NULL) 146 layer->fUpper->fLower = layer->fLower; 147 148 if(layer->fLower != NULL) 149 layer->fLower->fUpper = layer->fUpper; 150 151 layer->fUpper = NULL; 152 layer->fLower = NULL; 153 154 layer->clear_visible_regions(); // TAKE 155 156 return true; 157 } 158 159 bool 160 Layer::IsHidden() const 161 { 162 if (fHidden) 163 return true; 164 165 // TODO: remove the following 2 lines when for real. 166 if (fView) 167 return false; 168 169 if (fParent) 170 return fParent->IsHidden(); 171 172 return fHidden; 173 } 174 175 void 176 Layer::Hide() 177 { 178 fHidden = true; 179 180 if (fParent && !fParent->IsHidden() && GetRootLayer()) { 181 // save fullVisible so we know what to invalidate 182 BRegion invalid(fFullVisible); 183 184 clear_visible_regions(); 185 186 if (invalid.Frame().IsValid()) 187 fParent->Invalidate(invalid, this); 188 } 189 } 190 191 void 192 Layer::Show() 193 { 194 fHidden = false; 195 196 if (fParent && !fParent->IsHidden() && GetRootLayer()) { 197 BRegion invalid; 198 199 get_user_regions(invalid); 200 201 if (invalid.CountRects() > 0) 202 fParent->Invalidate(invalid, this); 203 } 204 } 205 206 void 207 Layer::Invalidate(const BRegion &invalid, const Layer *startFrom) 208 { 209 BRegion localVisible(fFullVisible); 210 localVisible.IntersectWith(&invalid); 211 rebuild_visible_regions(invalid, localVisible, 212 startFrom? startFrom: BottomChild()); 213 214 // add localVisible to our RootLayer's redraw region. 215 GetRootLayer()->fRedrawReg.Include(&localVisible); 216 GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? 217 } 218 219 inline void 220 Layer::resize_layer_frame_by(float x, float y) 221 { 222 uint16 rm = fResizeMode & 0x0000FFFF; 223 BRect newFrame = fFrame; 224 225 if ((rm & 0x0F00U) == _VIEW_LEFT_ << 8) 226 newFrame.left += 0.0f; 227 else if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8) 228 newFrame.left += x; 229 else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8) 230 newFrame.left += x/2; 231 232 if ((rm & 0x000FU) == _VIEW_LEFT_) 233 newFrame.right += 0.0f; 234 else if ((rm & 0x000FU) == _VIEW_RIGHT_) 235 newFrame.right += x; 236 else if ((rm & 0x000FU) == _VIEW_CENTER_) 237 newFrame.right += x/2; 238 239 if ((rm & 0xF000U) == _VIEW_TOP_ << 12) 240 newFrame.top += 0.0f; 241 else if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12) 242 newFrame.top += y; 243 else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12) 244 newFrame.top += y/2; 245 246 if ((rm & 0x00F0U) == _VIEW_TOP_ << 4) 247 newFrame.bottom += 0.0f; 248 else if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4) 249 newFrame.bottom += y; 250 else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4) 251 newFrame.bottom += y/2; 252 253 if (newFrame != fFrame) { 254 float dx, dy; 255 256 dx = newFrame.Width() - fFrame.Width(); 257 dy = newFrame.Height() - fFrame.Height(); 258 259 fFrame = newFrame; 260 261 if (dx != 0.0f || dy != 0.0f) { 262 // call hook function 263 ResizedByHook(dx, dy, true); // automatic 264 265 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) 266 lay->resize_layer_frame_by(dx, dy); 267 } 268 else 269 MovedByHook(dx, dy); 270 } 271 } 272 273 inline void 274 Layer::rezize_layer_redraw_more(BRegion ®, float dx, float dy) 275 { 276 if (dx == 0 && dy == 0) 277 return; 278 279 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) { 280 uint16 rm = lay->fResizeMode & 0x0000FFFF; 281 282 if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) { 283 // NOTE: this is not exactly corect, but it works :-) 284 // Normaly we shoud've used the lay's old, required region - the one returned 285 // from get_user_region() with the old frame, and the current one. lay->Bounds() 286 // works for the moment so we leave it like this. 287 288 // calculate the old bounds. 289 BRect oldBounds(lay->Bounds()); 290 if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT) 291 oldBounds.right -=dx; 292 if ((rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) 293 oldBounds.bottom -=dy; 294 295 // compute the region that became visible because we got bigger OR smaller. 296 BRegion regZ(lay->Bounds()); 297 regZ.Include(oldBounds); 298 regZ.Exclude(oldBounds&lay->Bounds()); 299 300 lay->ConvertToScreen2(®Z); 301 302 // intersect that with this'(not lay's) fullVisible region 303 regZ.IntersectWith(&fFullVisible); 304 reg.Include(®Z); 305 306 lay->rezize_layer_redraw_more(reg, 307 (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0, 308 (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0); 309 310 // above, OR this: 311 // reg.Include(&lay->fFullVisible); 312 } 313 else 314 if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0) || 315 ((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0) || 316 ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0)|| 317 ((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0)) 318 { 319 reg.Include(&lay->fFullVisible); 320 } 321 } 322 } 323 324 inline void 325 Layer::resize_layer_full_update_on_resize(BRegion ®, float dx, float dy) 326 { 327 if (dx == 0 && dy == 0) 328 return; 329 330 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) { 331 uint16 rm = lay->fResizeMode & 0x0000FFFF; 332 333 if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) { 334 if (lay->fFlags & B_FULL_UPDATE_ON_RESIZE && lay->fVisible.CountRects() > 0) 335 reg.Include(&lay->fVisible); 336 337 lay->resize_layer_full_update_on_resize(reg, 338 (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0, 339 (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0); 340 } 341 } 342 } 343 344 void 345 Layer::ResizeBy(float dx, float dy) 346 { 347 fFrame.Set(fFrame.left, fFrame.top, fFrame.right+dx, fFrame.bottom+dy); 348 349 // resize children using their resize_mask. 350 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) 351 lay->resize_layer_frame_by(dx, dy); 352 353 // call hook function 354 if (dx != 0.0f || dy != 0.0f) 355 ResizedByHook(dx, dy, false); // manual 356 357 if (!IsHidden() && GetRootLayer()) { 358 BRegion oldFullVisible(fFullVisible); 359 // this is required to invalidate the old border 360 BRegion oldVisible(fVisible); 361 362 // in case they moved, bottom, right and center aligned layers must be redrawn 363 BRegion redrawMore; 364 rezize_layer_redraw_more(redrawMore, dx, dy); 365 366 // we'll invalidate the old area and the new, maxmial one. 367 BRegion invalid; 368 get_user_regions(invalid); 369 invalid.Include(&fFullVisible); 370 371 clear_visible_regions(); 372 373 fParent->RebuildVisibleRegions(invalid, this); 374 375 // done rebuilding regions, now redraw regions that became visible 376 377 // what's invalid, are the differences between to old and the new fullVisible region 378 // 1) in case we grow. 379 BRegion redrawReg(fFullVisible); 380 redrawReg.Exclude(&oldFullVisible); 381 // 2) in case we shrink 382 BRegion redrawReg2(oldFullVisible); 383 redrawReg2.Exclude(&fFullVisible); 384 // 3) combine. 385 redrawReg.Include(&redrawReg2); 386 387 // for center, right and bottom alligned layers, redraw their old positions 388 redrawReg.Include(&redrawMore); 389 390 // layers that had their frame modified must be entirely redrawn. 391 rezize_layer_redraw_more(redrawReg, dx, dy); 392 393 // add redrawReg to our RootLayer's redraw region. 394 GetRootLayer()->fRedrawReg.Include(&redrawReg); 395 // include layer's visible region in case we want a full update on resize 396 if (fFlags & B_FULL_UPDATE_ON_RESIZE && fVisible.Frame().IsValid()) { 397 resize_layer_full_update_on_resize(GetRootLayer()->fRedrawReg, dx, dy); 398 399 GetRootLayer()->fRedrawReg.Include(&fVisible); 400 GetRootLayer()->fRedrawReg.Include(&oldVisible); 401 } 402 // clear canvas and set invalid regions for affected WinBorders 403 GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? 404 } 405 } 406 407 void Layer::MoveBy(float dx, float dy) 408 { 409 if (dx == 0.0f && dy == 0.0f) 410 return; 411 412 // fFrame.Set(fFrame.left+dx, fFrame.top+dy, fFrame.right+dx, fFrame.bottom+dy); 413 fFrame.OffsetBy(dx, dy); 414 415 // call hook function 416 MovedByHook(dx, dy); 417 418 if (!IsHidden() && GetRootLayer()) { 419 BRegion oldFullVisible(fFullVisible); 420 421 // we'll invalidate the old position and the new, maxmial one. 422 BRegion invalid; 423 get_user_regions(invalid); 424 invalid.Include(&fFullVisible); 425 426 clear_visible_regions(); 427 428 fParent->RebuildVisibleRegions(invalid, this); 429 430 // done rebuilding regions, now copy common parts and redraw regions that became visible 431 432 // include the actual and the old fullVisible regions. later, we'll exclude the common parts. 433 BRegion redrawReg(fFullVisible); 434 redrawReg.Include(&oldFullVisible); 435 436 // offset to layer's new location so that we can calculate the common region. 437 oldFullVisible.OffsetBy(dx, dy); 438 439 // finally we have the region that needs to be redrawn. 440 redrawReg.Exclude(&oldFullVisible); 441 442 // by intersecting the old fullVisible offseted to layer's new location, with the current 443 // fullVisible, we'll have the common region which can be copied using HW acceleration. 444 oldFullVisible.IntersectWith(&fFullVisible); 445 446 // offset back and instruct the HW to do the actual copying. 447 oldFullVisible.OffsetBy(-dx, -dy); 448 GetRootLayer()->CopyRegion(&oldFullVisible, dx, dy); 449 450 // add redrawReg to our RootLayer's redraw region. 451 GetRootLayer()->fRedrawReg.Include(&redrawReg); 452 GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? 453 } 454 } 455 456 void 457 Layer::ScrollBy(float dx, float dy) 458 { 459 fOrigin.Set(fOrigin.x + dx, fOrigin.y + dy); 460 461 if (!IsHidden() && GetRootLayer()) { 462 // set the region to be invalidated. 463 BRegion invalid(fFullVisible); 464 465 clear_visible_regions(); 466 467 rebuild_visible_regions(invalid, invalid, BottomChild()); 468 469 // for the moment we say that the whole surface needs to be redraw. 470 BRegion redrawReg(fFullVisible); 471 472 // offset old region so that we can start comparing. 473 invalid.OffsetBy(dx, dy); 474 475 // compute the common region. we'll use HW acc to copy this to the new location. 476 invalid.IntersectWith(&fFullVisible); 477 GetRootLayer()->CopyRegion(&invalid, -dx, -dy); 478 479 // common region goes back to its original location. then, by excluding 480 // it from curent fullVisible we'll obtain the region that needs to be redrawn. 481 invalid.OffsetBy(-dx, -dy); 482 redrawReg.Exclude(&invalid); 483 484 GetRootLayer()->fRedrawReg.Include(&redrawReg); 485 GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? 486 } 487 488 if (dx != 0.0f || dy != 0.0f) 489 ScrolledByHook(dx, dy); 490 } 491 492 493 494 495 496 void 497 Layer::GetWantedRegion(BRegion ®) // TAKE? 498 { 499 get_user_regions(reg); 500 } 501 502 void 503 Layer::get_user_regions(BRegion ®) 504 { 505 // 1) set to frame in screen coords 506 BRect screenFrame(Bounds()); 507 ConvertToScreen2(&screenFrame); 508 reg.Set(screenFrame); 509 510 // 2) intersect with screen region 511 // TODO: remove locking when for real 512 wind->Lock(); 513 BRegion screenReg(GetRootLayer()->Bounds()); 514 wind->Unlock(); 515 reg.IntersectWith(&screenReg); 516 517 // TODO: you MUST at some point uncomment this block! 518 /* 519 // 3) impose user constrained regions 520 LayerData *stackData = fLayerData; 521 while (stackData) 522 { 523 // transform in screen coords 524 BRegion screenReg(stackData->ClippingRegion()); 525 ConvertToScreen2(&screenReg); 526 reg.IntersectWith(&screenReg); 527 stackData = stackData->prevState; 528 } 529 */ 530 } 531 532 void 533 Layer::RebuildVisibleRegions(const BRegion &invalid, const Layer *startFrom) 534 { 535 BRegion localVisible(fFullVisible); 536 localVisible.IntersectWith(&invalid); 537 rebuild_visible_regions(invalid, localVisible, startFrom); 538 } 539 540 void 541 Layer::rebuild_visible_regions(const BRegion &invalid, 542 const BRegion &parentLocalVisible, 543 const Layer *startFrom) 544 { 545 // no point in continuing if this layer is hidden. starting from here, all 546 // descendants have (and will have) invalid visible regions. 547 if (fHidden) 548 return; 549 550 // no need to go deeper if the parent doesn't have a visible region anymore 551 // and our fullVisible region is also empty. 552 if (!parentLocalVisible.Frame().IsValid() && !(fFullVisible.CountRects() > 0)) 553 return; 554 555 bool fullRebuild = false; 556 557 // intersect maximum wanted region with the invalid region 558 BRegion common; 559 get_user_regions(common); 560 common.IntersectWith(&invalid); 561 562 // if the resulted region is not valid, this layer is not in the catchment area 563 // of the region being invalidated 564 if (!common.CountRects() > 0) 565 return; 566 567 // now intersect with parent's visible part of the region that was/is invalidated 568 common.IntersectWith(&parentLocalVisible); 569 570 // exclude the invalid region 571 fFullVisible.Exclude(&invalid); 572 fVisible.Exclude(&invalid); 573 574 // put in what's really visible 575 fFullVisible.Include(&common); 576 577 // this is to allow a layer to hide some parts of itself so children 578 // won't take them. 579 BRegion unalteredVisible(common); 580 bool altered = alter_visible_for_children(common); 581 582 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) { 583 if (lay == startFrom) 584 fullRebuild = true; 585 586 if (fullRebuild) 587 lay->rebuild_visible_regions(invalid, common, lay->BottomChild()); 588 589 // to let children know much they can take from parent's visible region 590 common.Exclude(&lay->fFullVisible); 591 // we've hidden some parts of our visible region from our children, 592 // and we must be in sysnc with this region too... 593 if (altered) 594 unalteredVisible.Exclude(&lay->fFullVisible); 595 } 596 597 // the visible region of this layer is what left after all its children took 598 // what they could. 599 if (altered) 600 fVisible.Include(&unalteredVisible); 601 else 602 fVisible.Include(&common); 603 } 604 605 bool 606 Layer::alter_visible_for_children(BRegion ®) 607 { 608 // Empty Hook function 609 return false; 610 } 611 612 void 613 Layer::clear_visible_regions() 614 { 615 // OPT: maybe we should uncomment these lines for performance 616 //if (fFullVisible.CountRects() <= 0) 617 // return; 618 619 fVisible.MakeEmpty(); 620 fFullVisible.MakeEmpty(); 621 for (Layer *child = BottomChild(); child; child = UpperSibling()) 622 child->clear_visible_regions(); 623 } 624 625 void 626 Layer::PrintToStream() const 627 { 628 printf("-> %s\n", fName); 629 fVisible.PrintToStream(); 630 fFullVisible.PrintToStream(); 631 for (Layer *child = BottomChild(); child; child = UpperSibling()) 632 child->PrintToStream(); 633 } 634