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
12extern BWindow* wind;
13
14Layer::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
34Layer::~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
45void
46Layer::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
57void
58Layer::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
69MyView*
70Layer::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
81Layer*
82Layer::BottomChild() const // we already have
83{
84	fCurrent = fBottom;
85	return fCurrent;
86}
87
88Layer*
89Layer::TopChild() const// we already have
90{
91	fCurrent = fTop;
92	return fCurrent;
93}
94
95Layer*
96Layer::UpperSibling() const// we already have
97{
98	fCurrent = fCurrent->fUpper;
99	return fCurrent;
100}
101
102Layer*
103Layer::LowerSibling() const// we already have
104{
105	fCurrent = fCurrent->fLower;
106	return fCurrent;
107}
108
109void
110Layer::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
129bool
130Layer::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
159bool
160Layer::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
175void
176Layer::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
191void
192Layer::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
206void
207Layer::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
219inline void
220Layer::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
273inline void
274Layer::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
324inline void
325Layer::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
344void
345Layer::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
407void 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
456void
457Layer::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
496void
497Layer::GetWantedRegion(BRegion &reg) // TAKE?
498{
499	get_user_regions(reg);
500}
501
502void
503Layer::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
512wind->Lock();
513	BRegion			screenReg(GetRootLayer()->Bounds());
514wind->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
532void
533Layer::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
540void
541Layer::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
605bool
606Layer::alter_visible_for_children(BRegion &reg)
607{
608	// Empty Hook function
609	return false;
610}
611
612void
613Layer::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
625void
626Layer::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