libroot_debug: Merge guarded heap into libroot_debug.
[haiku.git] / src / tests / servers / app / newClipping / Layer.cpp
blob486237a5f171a01ce7eed342623c2613821d4056
1 #include <OS.h>
2 #include <Region.h>
3 #include <Rect.h>
4 #include <stdio.h>
5 #include <strings.h>
7 #include <Window.h>
9 #include "Layer.h"
10 #include "MyView.h"
12 extern BWindow* wind;
14 Layer::Layer(BRect frame, const char* name, uint32 rm, uint32 flags, rgb_color c)
16 fFrame = frame;
17 fOrigin.Set(0.0f, 0.0f);
18 fResizeMode = rm;
19 fFlags = flags;
20 fColor = c;
22 fBottom = NULL;
23 fUpper = NULL;
24 fLower = NULL;
25 fTop = NULL;
26 fParent = NULL;
27 fView = NULL;
28 fCurrent = NULL;
29 fHidden = false;
31 strcpy(fName, name);
34 Layer::~Layer()
36 Layer *c = fBottom;
37 Layer *toast;
38 while (c) {
39 toast = c;
40 c = c->fUpper;
41 delete toast;
45 void
46 Layer::ConvertToScreen2(BRect* rect) const
48 if (GetRootLayer())
49 if (fParent) {
50 rect->OffsetBy(-fOrigin.x, -fOrigin.y);
51 rect->OffsetBy(fFrame.left, fFrame.top);
53 fParent->ConvertToScreen2(rect);
57 void
58 Layer::ConvertToScreen2(BRegion* reg) const
60 if (GetRootLayer())
61 if (fParent) {
62 reg->OffsetBy(-fOrigin.x, -fOrigin.y);
63 reg->OffsetBy(fFrame.left, fFrame.top);
65 fParent->ConvertToScreen2(reg);
69 MyView*
70 Layer::GetRootLayer() const // we already have
72 if (fView)
73 return fView;
74 else
75 if (fParent)
76 return fParent->GetRootLayer();
77 else
78 return NULL;
81 Layer*
82 Layer::BottomChild() const // we already have
84 fCurrent = fBottom;
85 return fCurrent;
88 Layer*
89 Layer::TopChild() const// we already have
91 fCurrent = fTop;
92 return fCurrent;
95 Layer*
96 Layer::UpperSibling() const// we already have
98 fCurrent = fCurrent->fUpper;
99 return fCurrent;
102 Layer*
103 Layer::LowerSibling() const// we already have
105 fCurrent = fCurrent->fLower;
106 return fCurrent;
109 void
110 Layer::AddLayer(Layer* layer)// we already have
112 if( layer->fParent != NULL ) {
113 printf("ERROR: Layer already has a parent\n");
114 return;
117 layer->fParent = this;
119 if (!fBottom) {
120 fBottom = layer;
121 fTop = layer;
122 return;
124 fBottom->fLower = layer;
125 layer->fUpper = fBottom;
126 fBottom = layer;
129 bool
130 Layer::RemLayer(Layer* layer)// we already have
132 if(!layer->fParent || layer->fParent != this) {
133 printf("ERROR: Rem: Layer doesn't have a fParent or !=this\n");
134 return false;
137 layer->fParent = NULL;
139 if(fTop == layer)
140 fTop = layer->fLower;
142 if(fBottom == layer )
143 fBottom = layer->fUpper;
145 if(layer->fUpper != NULL)
146 layer->fUpper->fLower = layer->fLower;
148 if(layer->fLower != NULL)
149 layer->fLower->fUpper = layer->fUpper;
151 layer->fUpper = NULL;
152 layer->fLower = NULL;
154 layer->clear_visible_regions(); // TAKE
156 return true;
159 bool
160 Layer::IsHidden() const
162 if (fHidden)
163 return true;
165 // TODO: remove the following 2 lines when for real.
166 if (fView)
167 return false;
169 if (fParent)
170 return fParent->IsHidden();
172 return fHidden;
175 void
176 Layer::Hide()
178 fHidden = true;
180 if (fParent && !fParent->IsHidden() && GetRootLayer()) {
181 // save fullVisible so we know what to invalidate
182 BRegion invalid(fFullVisible);
184 clear_visible_regions();
186 if (invalid.Frame().IsValid())
187 fParent->Invalidate(invalid, this);
191 void
192 Layer::Show()
194 fHidden = false;
196 if (fParent && !fParent->IsHidden() && GetRootLayer()) {
197 BRegion invalid;
199 get_user_regions(invalid);
201 if (invalid.CountRects() > 0)
202 fParent->Invalidate(invalid, this);
206 void
207 Layer::Invalidate(const BRegion &invalid, const Layer *startFrom)
209 BRegion localVisible(fFullVisible);
210 localVisible.IntersectWith(&invalid);
211 rebuild_visible_regions(invalid, localVisible,
212 startFrom? startFrom: BottomChild());
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)?
219 inline void
220 Layer::resize_layer_frame_by(float x, float y)
222 uint16 rm = fResizeMode & 0x0000FFFF;
223 BRect newFrame = fFrame;
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;
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;
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;
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;
253 if (newFrame != fFrame) {
254 float dx, dy;
256 dx = newFrame.Width() - fFrame.Width();
257 dy = newFrame.Height() - fFrame.Height();
259 fFrame = newFrame;
261 if (dx != 0.0f || dy != 0.0f) {
262 // call hook function
263 ResizedByHook(dx, dy, true); // automatic
265 for (Layer *lay = BottomChild(); lay; lay = UpperSibling())
266 lay->resize_layer_frame_by(dx, dy);
268 else
269 MovedByHook(dx, dy);
273 inline void
274 Layer::rezize_layer_redraw_more(BRegion &reg, float dx, float dy)
276 if (dx == 0 && dy == 0)
277 return;
279 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) {
280 uint16 rm = lay->fResizeMode & 0x0000FFFF;
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.
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;
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());
300 lay->ConvertToScreen2(&regZ);
302 // intersect that with this'(not lay's) fullVisible region
303 regZ.IntersectWith(&fFullVisible);
304 reg.Include(&regZ);
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);
310 // above, OR this:
311 // reg.Include(&lay->fFullVisible);
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))
319 reg.Include(&lay->fFullVisible);
324 inline void
325 Layer::resize_layer_full_update_on_resize(BRegion &reg, float dx, float dy)
327 if (dx == 0 && dy == 0)
328 return;
330 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) {
331 uint16 rm = lay->fResizeMode & 0x0000FFFF;
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);
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);
344 void
345 Layer::ResizeBy(float dx, float dy)
347 fFrame.Set(fFrame.left, fFrame.top, fFrame.right+dx, fFrame.bottom+dy);
349 // resize children using their resize_mask.
350 for (Layer *lay = BottomChild(); lay; lay = UpperSibling())
351 lay->resize_layer_frame_by(dx, dy);
353 // call hook function
354 if (dx != 0.0f || dy != 0.0f)
355 ResizedByHook(dx, dy, false); // manual
357 if (!IsHidden() && GetRootLayer()) {
358 BRegion oldFullVisible(fFullVisible);
359 // this is required to invalidate the old border
360 BRegion oldVisible(fVisible);
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);
366 // we'll invalidate the old area and the new, maxmial one.
367 BRegion invalid;
368 get_user_regions(invalid);
369 invalid.Include(&fFullVisible);
371 clear_visible_regions();
373 fParent->RebuildVisibleRegions(invalid, this);
375 // done rebuilding regions, now redraw regions that became visible
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);
387 // for center, right and bottom alligned layers, redraw their old positions
388 redrawReg.Include(&redrawMore);
390 // layers that had their frame modified must be entirely redrawn.
391 rezize_layer_redraw_more(redrawReg, dx, dy);
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);
399 GetRootLayer()->fRedrawReg.Include(&fVisible);
400 GetRootLayer()->fRedrawReg.Include(&oldVisible);
402 // clear canvas and set invalid regions for affected WinBorders
403 GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)?
407 void Layer::MoveBy(float dx, float dy)
409 if (dx == 0.0f && dy == 0.0f)
410 return;
412 // fFrame.Set(fFrame.left+dx, fFrame.top+dy, fFrame.right+dx, fFrame.bottom+dy);
413 fFrame.OffsetBy(dx, dy);
415 // call hook function
416 MovedByHook(dx, dy);
418 if (!IsHidden() && GetRootLayer()) {
419 BRegion oldFullVisible(fFullVisible);
421 // we'll invalidate the old position and the new, maxmial one.
422 BRegion invalid;
423 get_user_regions(invalid);
424 invalid.Include(&fFullVisible);
426 clear_visible_regions();
428 fParent->RebuildVisibleRegions(invalid, this);
430 // done rebuilding regions, now copy common parts and redraw regions that became visible
432 // include the actual and the old fullVisible regions. later, we'll exclude the common parts.
433 BRegion redrawReg(fFullVisible);
434 redrawReg.Include(&oldFullVisible);
436 // offset to layer's new location so that we can calculate the common region.
437 oldFullVisible.OffsetBy(dx, dy);
439 // finally we have the region that needs to be redrawn.
440 redrawReg.Exclude(&oldFullVisible);
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);
446 // offset back and instruct the HW to do the actual copying.
447 oldFullVisible.OffsetBy(-dx, -dy);
448 GetRootLayer()->CopyRegion(&oldFullVisible, dx, dy);
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)?
456 void
457 Layer::ScrollBy(float dx, float dy)
459 fOrigin.Set(fOrigin.x + dx, fOrigin.y + dy);
461 if (!IsHidden() && GetRootLayer()) {
462 // set the region to be invalidated.
463 BRegion invalid(fFullVisible);
465 clear_visible_regions();
467 rebuild_visible_regions(invalid, invalid, BottomChild());
469 // for the moment we say that the whole surface needs to be redraw.
470 BRegion redrawReg(fFullVisible);
472 // offset old region so that we can start comparing.
473 invalid.OffsetBy(dx, dy);
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);
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);
484 GetRootLayer()->fRedrawReg.Include(&redrawReg);
485 GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)?
488 if (dx != 0.0f || dy != 0.0f)
489 ScrolledByHook(dx, dy);
496 void
497 Layer::GetWantedRegion(BRegion &reg) // TAKE?
499 get_user_regions(reg);
502 void
503 Layer::get_user_regions(BRegion &reg)
505 // 1) set to frame in screen coords
506 BRect screenFrame(Bounds());
507 ConvertToScreen2(&screenFrame);
508 reg.Set(screenFrame);
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);
517 // TODO: you MUST at some point uncomment this block!
519 // 3) impose user constrained regions
520 LayerData *stackData = fLayerData;
521 while (stackData)
523 // transform in screen coords
524 BRegion screenReg(stackData->ClippingRegion());
525 ConvertToScreen2(&screenReg);
526 reg.IntersectWith(&screenReg);
527 stackData = stackData->prevState;
532 void
533 Layer::RebuildVisibleRegions(const BRegion &invalid, const Layer *startFrom)
535 BRegion localVisible(fFullVisible);
536 localVisible.IntersectWith(&invalid);
537 rebuild_visible_regions(invalid, localVisible, startFrom);
540 void
541 Layer::rebuild_visible_regions(const BRegion &invalid,
542 const BRegion &parentLocalVisible,
543 const Layer *startFrom)
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;
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;
555 bool fullRebuild = false;
557 // intersect maximum wanted region with the invalid region
558 BRegion common;
559 get_user_regions(common);
560 common.IntersectWith(&invalid);
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;
567 // now intersect with parent's visible part of the region that was/is invalidated
568 common.IntersectWith(&parentLocalVisible);
570 // exclude the invalid region
571 fFullVisible.Exclude(&invalid);
572 fVisible.Exclude(&invalid);
574 // put in what's really visible
575 fFullVisible.Include(&common);
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);
582 for (Layer *lay = BottomChild(); lay; lay = UpperSibling()) {
583 if (lay == startFrom)
584 fullRebuild = true;
586 if (fullRebuild)
587 lay->rebuild_visible_regions(invalid, common, lay->BottomChild());
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);
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);
605 bool
606 Layer::alter_visible_for_children(BRegion &reg)
608 // Empty Hook function
609 return false;
612 void
613 Layer::clear_visible_regions()
615 // OPT: maybe we should uncomment these lines for performance
616 //if (fFullVisible.CountRects() <= 0)
617 // return;
619 fVisible.MakeEmpty();
620 fFullVisible.MakeEmpty();
621 for (Layer *child = BottomChild(); child; child = UpperSibling())
622 child->clear_visible_regions();
625 void
626 Layer::PrintToStream() const
628 printf("-> %s\n", fName);
629 fVisible.PrintToStream();
630 fFullVisible.PrintToStream();
631 for (Layer *child = BottomChild(); child; child = UpperSibling())
632 child->PrintToStream();