xref: /haiku/src/tests/servers/app/newClipping/Layer.cpp (revision 8dbc637219753881e558557493b55ae74accfe02)
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 &reg, 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(&regZ);
301 
302 			// intersect that with this'(not lay's) fullVisible region
303 			regZ.IntersectWith(&fFullVisible);
304 			reg.Include(&regZ);
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 &reg, 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 &reg) // TAKE?
498 {
499 	get_user_regions(reg);
500 }
501 
502 void
get_user_regions(BRegion & reg)503 Layer::get_user_regions(BRegion &reg)
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 &reg)
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