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
Layer(BRect frame,const char * name,uint32 rm,uint32 flags,rgb_color c)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
~Layer()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
ConvertToScreen2(BRect * rect) const46 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
ConvertToScreen2(BRegion * reg) const58 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*
GetRootLayer() const70 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*
BottomChild() const82 Layer::BottomChild() const // we already have
83 {
84 fCurrent = fBottom;
85 return fCurrent;
86 }
87
88 Layer*
TopChild() const89 Layer::TopChild() const// we already have
90 {
91 fCurrent = fTop;
92 return fCurrent;
93 }
94
95 Layer*
UpperSibling() const96 Layer::UpperSibling() const// we already have
97 {
98 fCurrent = fCurrent->fUpper;
99 return fCurrent;
100 }
101
102 Layer*
LowerSibling() const103 Layer::LowerSibling() const// we already have
104 {
105 fCurrent = fCurrent->fLower;
106 return fCurrent;
107 }
108
109 void
AddLayer(Layer * layer)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
RemLayer(Layer * layer)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
IsHidden() const160 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
Hide()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
Show()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
Invalidate(const BRegion & invalid,const Layer * startFrom)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
resize_layer_frame_by(float x,float y)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
rezize_layer_redraw_more(BRegion & reg,float dx,float dy)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
resize_layer_full_update_on_resize(BRegion & reg,float dx,float dy)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
ResizeBy(float dx,float dy)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
MoveBy(float dx,float dy)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
ScrollBy(float dx,float dy)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
GetWantedRegion(BRegion & reg)497 Layer::GetWantedRegion(BRegion ®) // TAKE?
498 {
499 get_user_regions(reg);
500 }
501
502 void
get_user_regions(BRegion & reg)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
RebuildVisibleRegions(const BRegion & invalid,const Layer * startFrom)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
rebuild_visible_regions(const BRegion & invalid,const BRegion & parentLocalVisible,const Layer * startFrom)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
alter_visible_for_children(BRegion & reg)606 Layer::alter_visible_for_children(BRegion ®)
607 {
608 // Empty Hook function
609 return false;
610 }
611
612 void
clear_visible_regions()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
PrintToStream() const626 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