headers/bsd: Add sys/queue.h.
[haiku.git] / src / tests / servers / app / newerClipping / ViewLayer.cpp
blob7aa9087963f89a69e01da964a26d245766718d9e
2 #include <stdio.h>
4 #include <List.h>
5 #include <View.h> // for resize modes
7 #include "Desktop.h"
8 #include "DrawingEngine.h"
9 #include "WindowLayer.h"
11 #include "ViewLayer.h"
13 extern BWindow* wind;
15 // constructor
16 ViewLayer::ViewLayer(BRect frame, const char* name,
17 uint32 resizeMode, uint32 flags,
18 rgb_color viewColor)
19 : fName(name),
21 fFrame(frame),
22 fScrollingOffset(0.0, 0.0),
24 fViewColor(viewColor),
26 fResizeMode(resizeMode),
27 fFlags(flags),
29 // ViewLayers start visible by default
30 fHidden(false),
31 fVisible(true),
33 fWindow(NULL),
34 fParent(NULL),
36 fFirstChild(NULL),
37 fPreviousSibling(NULL),
38 fNextSibling(NULL),
39 fLastChild(NULL),
41 fCurrentChild(NULL),
43 fLocalClipping(Bounds()),
44 fScreenClipping(),
45 fScreenClippingValid(false)
47 fFrame.left = float((int32)fFrame.left);
48 fFrame.top = float((int32)fFrame.top);
49 fFrame.right = float((int32)fFrame.right);
50 fFrame.bottom = float((int32)fFrame.bottom);
53 // destructor
54 ViewLayer::~ViewLayer()
56 // iterate over children and delete each one
57 ViewLayer* layer = fFirstChild;
58 while (layer) {
59 ViewLayer* toast = layer;
60 layer = layer->fNextSibling;
61 delete toast;
65 // Bounds
66 BRect
67 ViewLayer::Bounds() const
69 BRect bounds(fScrollingOffset.x, fScrollingOffset.y,
70 fScrollingOffset.x + fFrame.Width(),
71 fScrollingOffset.y + fFrame.Height());
72 return bounds;
75 // ConvertToVisibleInTopView
76 void
77 ViewLayer::ConvertToVisibleInTopView(BRect* bounds) const
79 *bounds = *bounds & Bounds();
80 // NOTE: this step is necessary even if we don't have a parent!
81 ConvertToParent(bounds);
83 if (fParent)
84 fParent->ConvertToVisibleInTopView(bounds);
87 // AttachedToWindow
88 void
89 ViewLayer::AttachedToWindow(WindowLayer* window)
91 fWindow = window;
93 for (ViewLayer* child = FirstChild(); child; child = NextChild())
94 child->AttachedToWindow(window);
98 // DetachedFromWindow
99 void
100 ViewLayer::DetachedFromWindow()
102 fWindow = NULL;
103 for (ViewLayer* child = FirstChild(); child; child = NextChild())
104 child->DetachedFromWindow();
107 // AddChild
108 void
109 ViewLayer::AddChild(ViewLayer* layer)
111 if (layer->fParent) {
112 printf("ViewLayer::AddChild() - ViewLayer already has a parent\n");
113 return;
116 layer->fParent = this;
118 if (!fLastChild) {
119 // no children yet
120 fFirstChild = layer;
121 } else {
122 // append layer to formerly last child
123 fLastChild->fNextSibling = layer;
124 layer->fPreviousSibling = fLastChild;
126 fLastChild = layer;
128 if (layer->IsVisible())
129 RebuildClipping(false);
131 if (fWindow) {
132 layer->AttachedToWindow(fWindow);
134 if (fVisible && layer->IsVisible()) {
135 // trigger redraw
136 BRect clippedFrame = layer->Frame();
137 ConvertToVisibleInTopView(&clippedFrame);
138 BRegion dirty(clippedFrame);
139 fWindow->MarkContentDirty(&dirty);
144 // RemoveChild
145 bool
146 ViewLayer::RemoveChild(ViewLayer* layer)
148 if (layer->fParent != this) {
149 printf("ViewLayer::RemoveChild(%p - %s) - ViewLayer is not child of this (%p) layer!\n", layer, layer ? layer->Name() : NULL, this);
150 return false;
153 layer->fParent = NULL;
155 if (fLastChild == layer)
156 fLastChild = layer->fPreviousSibling;
157 // layer->fNextSibling would be NULL
159 if (fFirstChild == layer )
160 fFirstChild = layer->fNextSibling;
161 // layer->fPreviousSibling would be NULL
163 // connect child before and after layer
164 if (layer->fPreviousSibling)
165 layer->fPreviousSibling->fNextSibling = layer->fNextSibling;
167 if (layer->fNextSibling)
168 layer->fNextSibling->fPreviousSibling = layer->fPreviousSibling;
170 // layer has no siblings anymore
171 layer->fPreviousSibling = NULL;
172 layer->fNextSibling = NULL;
174 if (layer->IsVisible())
175 RebuildClipping(false);
177 if (fWindow) {
178 layer->DetachedFromWindow();
180 if (fVisible && layer->IsVisible()) {
181 // trigger redraw
182 BRect clippedFrame = layer->Frame();
183 ConvertToVisibleInTopView(&clippedFrame);
184 BRegion dirty(clippedFrame);
185 fWindow->MarkContentDirty(&dirty);
189 return true;
192 // FirstChild
193 ViewLayer*
194 ViewLayer::FirstChild() const
196 fCurrentChild = fFirstChild;
197 return fCurrentChild;
200 // PreviousChild
201 ViewLayer*
202 ViewLayer::PreviousChild() const
204 fCurrentChild = fCurrentChild->fPreviousSibling;
205 return fCurrentChild;
208 // NextChild
209 ViewLayer*
210 ViewLayer::NextChild() const
212 fCurrentChild = fCurrentChild->fNextSibling;
213 return fCurrentChild;
216 // LastChild
217 ViewLayer*
218 ViewLayer::LastChild() const
220 fCurrentChild = fLastChild;
221 return fCurrentChild;
224 // TopLayer
225 ViewLayer*
226 ViewLayer::TopLayer()
228 // returns the top level view of the hirarchy,
229 // it doesn't have to be the top level of a window
231 if (fParent)
232 return fParent->TopLayer();
234 return this;
237 // CountChildren
238 uint32
239 ViewLayer::CountChildren(bool deep) const
241 uint32 count = 0;
242 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
243 count++;
244 if (deep) {
245 count += child->CountChildren(deep);
248 return count;
251 // CollectTokensForChildren
252 void
253 ViewLayer::CollectTokensForChildren(BList* tokenMap) const
255 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
256 tokenMap->AddItem((void*)child);
257 child->CollectTokensForChildren(tokenMap);
261 // ViewAt
262 ViewLayer*
263 ViewLayer::ViewAt(const BPoint& where, BRegion* windowContentClipping)
265 if (!fVisible)
266 return NULL;
268 if (ScreenClipping(windowContentClipping).Contains(where))
269 return this;
271 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
272 ViewLayer* layer = child->ViewAt(where, windowContentClipping);
273 if (layer)
274 return layer;
276 return NULL;
279 // ConvertToParent
280 void
281 ViewLayer::ConvertToParent(BPoint* point) const
283 // remove scrolling offset and convert to parent coordinate space
284 point->x += fFrame.left - fScrollingOffset.x;
285 point->y += fFrame.top - fScrollingOffset.y;
288 // ConvertToParent
289 void
290 ViewLayer::ConvertToParent(BRect* rect) const
292 // remove scrolling offset and convert to parent coordinate space
293 rect->OffsetBy(fFrame.left - fScrollingOffset.x,
294 fFrame.top - fScrollingOffset.y);
297 // ConvertToParent
298 void
299 ViewLayer::ConvertToParent(BRegion* region) const
301 // remove scrolling offset and convert to parent coordinate space
302 region->OffsetBy(fFrame.left - fScrollingOffset.x,
303 fFrame.top - fScrollingOffset.y);
306 // ConvertFromParent
307 void
308 ViewLayer::ConvertFromParent(BPoint* point) const
310 // remove scrolling offset and convert to parent coordinate space
311 point->x += fScrollingOffset.x - fFrame.left;
312 point->y += fScrollingOffset.y - fFrame.top;
315 // ConvertFromParent
316 void
317 ViewLayer::ConvertFromParent(BRect* rect) const
319 // remove scrolling offset and convert to parent coordinate space
320 rect->OffsetBy(fScrollingOffset.x - fFrame.left,
321 fScrollingOffset.y - fFrame.top);
324 // ConvertFromParent
325 void
326 ViewLayer::ConvertFromParent(BRegion* region) const
328 // remove scrolling offset and convert to parent coordinate space
329 region->OffsetBy(fScrollingOffset.x - fFrame.left,
330 fScrollingOffset.y - fFrame.top);
333 // ConvertToTop
334 void
335 ViewLayer::ConvertToTop(BPoint* point) const
337 ConvertToParent(point);
339 if (fParent)
340 fParent->ConvertToTop(point);
343 // ConvertToTop
344 void
345 ViewLayer::ConvertToTop(BRect* rect) const
347 ConvertToParent(rect);
349 if (fParent)
350 fParent->ConvertToTop(rect);
353 // ConvertToTop
354 void
355 ViewLayer::ConvertToTop(BRegion* region) const
357 ConvertToParent(region);
359 if (fParent)
360 fParent->ConvertToTop(region);
363 // ConvertFromTop
364 void
365 ViewLayer::ConvertFromTop(BPoint* point) const
367 ConvertFromParent(point);
369 if (fParent)
370 fParent->ConvertFromTop(point);
373 // ConvertFromTop
374 void
375 ViewLayer::ConvertFromTop(BRect* rect) const
377 ConvertFromParent(rect);
379 if (fParent)
380 fParent->ConvertFromTop(rect);
383 // ConvertFromTop
384 void
385 ViewLayer::ConvertFromTop(BRegion* region) const
387 ConvertFromParent(region);
389 if (fParent)
390 fParent->ConvertFromTop(region);
393 // SetName
394 void
395 ViewLayer::SetName(const char* string)
397 fName.SetTo(string);
400 // #pragma mark -
402 // MoveBy
403 void
404 ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
406 if (x == 0 && y == 0)
407 return;
409 fFrame.OffsetBy(x, y);
411 // to move on screen, we must not be hidden and we must have a parent
412 if (fVisible && fParent && dirtyRegion) {
413 #if 0
414 // based on redraw on new location
415 // the place were we are now visible
416 BRect newVisibleBounds = Bounds();
417 // we can use the frame of the old
418 // local clipping to see which parts need invalidation
419 BRect oldVisibleBounds(Bounds());
420 oldVisibleBounds.OffsetBy(-x, -y);
421 ConvertToTop(&oldVisibleBounds);
423 ConvertToVisibleInTopView(&newVisibleBounds);
425 dirtyRegion->Include(oldVisibleBounds);
426 // newVisibleBounds already is in screen coords
427 dirtyRegion->Include(newVisibleBounds);
428 #else
429 // blitting version, invalidates
430 // old contents
431 BRect oldVisibleBounds(Bounds());
432 oldVisibleBounds.OffsetBy(-x, -y);
433 ConvertToTop(&oldVisibleBounds);
435 BRect newVisibleBounds(Bounds());
436 // NOTE: using ConvertToVisibleInTopView()
437 // instead of ConvertToTop()! see below
438 ConvertToVisibleInTopView(&newVisibleBounds);
440 newVisibleBounds.OffsetBy(-x, -y);
442 // clipping oldVisibleBounds to newVisibleBounds
443 // makes sure we don't copy parts hidden under
444 // parent views
445 BRegion copyRegion(oldVisibleBounds & newVisibleBounds);
446 fWindow->CopyContents(&copyRegion, x, y);
448 BRegion dirty(oldVisibleBounds);
449 newVisibleBounds.OffsetBy(x, y);
450 dirty.Exclude(newVisibleBounds);
451 dirtyRegion->Include(&dirty);
452 #endif
455 if (!fParent) {
456 // the top view's screen clipping does not change,
457 // because no parts are clipped away from parent
458 // views
459 _MoveScreenClipping(x, y, true);
460 } else {
461 // parts might have been revealed from underneath
462 // the parent, or might now be hidden underneath
463 // the parent, this is taken care of when building
464 // the screen clipping
465 InvalidateScreenClipping(true);
469 // ResizeBy
470 void
471 ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
473 if (x == 0 && y == 0)
474 return;
476 fFrame.right += x;
477 fFrame.bottom += y;
479 if (fVisible && dirtyRegion) {
480 BRect oldBounds(Bounds());
481 oldBounds.right -= x;
482 oldBounds.bottom -= y;
484 BRegion dirty(Bounds());
485 dirty.Include(oldBounds);
487 if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) {
488 // the dirty region is just the difference of
489 // old and new bounds
490 dirty.Exclude(oldBounds & Bounds());
493 InvalidateScreenClipping(true);
495 if (dirty.CountRects() > 0) {
496 // exclude children, they are expected to
497 // include their own dirty regions in ParentResized()
498 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
499 if (child->IsVisible()) {
500 BRect previousChildVisible(child->Frame() & oldBounds & Bounds());
501 if (dirty.Frame().Intersects(previousChildVisible)) {
502 dirty.Exclude(previousChildVisible);
507 ConvertToTop(&dirty);
508 dirtyRegion->Include(&dirty);
512 // layout the children
513 for (ViewLayer* child = FirstChild(); child; child = NextChild())
514 child->ParentResized(x, y, dirtyRegion);
516 // at this point, children are at their new locations,
517 // so we can rebuild the clipping
518 // TODO: when the implementation of Hide() and Show() is
519 // complete, see if this should be avoided
520 RebuildClipping(false);
523 // ParentResized
524 void
525 ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
527 uint16 rm = fResizeMode & 0x0000FFFF;
528 BRect newFrame = fFrame;
530 // follow with left side
531 if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8)
532 newFrame.left += x;
533 else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8)
534 newFrame.left += x / 2;
536 // follow with right side
537 if ((rm & 0x000FU) == _VIEW_RIGHT_)
538 newFrame.right += x;
539 else if ((rm & 0x000FU) == _VIEW_CENTER_)
540 newFrame.right += x / 2;
542 // follow with top side
543 if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12)
544 newFrame.top += y;
545 else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12)
546 newFrame.top += y / 2;
548 // follow with bottom side
549 if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4)
550 newFrame.bottom += y;
551 else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4)
552 newFrame.bottom += y / 2;
554 if (newFrame != fFrame) {
555 // careful, MoveBy will change fFrame
556 int32 widthDiff = (int32)(newFrame.Width() - fFrame.Width());
557 int32 heightDiff = (int32)(newFrame.Height() - fFrame.Height());
559 MoveBy(newFrame.left - fFrame.left,
560 newFrame.top - fFrame.top, dirtyRegion);
562 ResizeBy(widthDiff, heightDiff, dirtyRegion);
566 // ScrollBy
567 void
568 ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
570 // blitting version, invalidates
571 // old contents
573 // remember old bounds for tracking dirty region
574 BRect oldBounds(Bounds());
575 // find the area of the view that can be scrolled,
576 // contents are shifted in the opposite direction from scrolling
577 BRect stillVisibleBounds(oldBounds);
578 stillVisibleBounds.OffsetBy(x, y);
580 // NOTE: using ConvertToVisibleInTopView()
581 // instead of ConvertToTop(), this makes
582 // sure we don't try to move or invalidate an
583 // area hidden underneath the parent view
584 ConvertToVisibleInTopView(&oldBounds);
585 ConvertToVisibleInTopView(&stillVisibleBounds);
587 fScrollingOffset.x += x;
588 fScrollingOffset.y += y;
590 // do the blit, this will make sure
591 // that other more complex dirty regions
592 // are taken care of
593 BRegion copyRegion(stillVisibleBounds);
594 fWindow->CopyContents(&copyRegion, -x, -y);
596 // find the dirty region as far as we are
597 // concerned
598 BRegion dirty(oldBounds);
599 stillVisibleBounds.OffsetBy(-x, -y);
600 dirty.Exclude(stillVisibleBounds);
601 dirtyRegion->Include(&dirty);
603 // the screen clipping of this view and it's
604 // childs is no longer valid
605 InvalidateScreenClipping(true);
606 RebuildClipping(false);
609 // #pragma mark -
611 // Draw
612 void
613 ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
614 BRegion* windowContentClipping, bool deep)
616 // we can only draw within our own area
617 BRegion redraw(ScreenClipping(windowContentClipping));
618 // add the current clipping
619 redraw.IntersectWith(effectiveClipping);
621 // fill visible region with white
622 drawingEngine->FillRegion(&redraw, (rgb_color){ 255, 255, 255, 255 });
624 // let children draw
625 if (deep) {
626 // before passing the clipping on to children, exclude our
627 // own region from the available clipping
628 effectiveClipping->Exclude(&ScreenClipping(windowContentClipping));
630 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
631 child->Draw(drawingEngine, effectiveClipping,
632 windowContentClipping, deep);
637 // ClientDraw
638 void
639 ViewLayer::ClientDraw(DrawingEngine* drawingEngine, BRegion* effectiveClipping)
641 BRect b(Bounds());
642 b.OffsetTo(0.0, 0.0);
643 ConvertToTop(&b);
645 if (drawingEngine->Lock()) {
646 drawingEngine->ConstrainClipping(effectiveClipping);
648 // draw a frame with the view color
649 drawingEngine->StrokeRect(b, fViewColor);
650 b.InsetBy(1, 1);
651 drawingEngine->StrokeRect(b, fViewColor);
652 b.InsetBy(1, 1);
653 drawingEngine->StrokeRect(b, fViewColor);
654 b.InsetBy(1, 1);
655 drawingEngine->StrokeLine(b.LeftTop(), b.RightBottom(), fViewColor);
657 drawingEngine->Unlock();
661 // #pragma mark -
663 // SetHidden
664 void
665 ViewLayer::SetHidden(bool hidden)
667 // TODO: test...
669 if (fHidden != hidden) {
670 fHidden = hidden;
672 // recurse into children and update their visible flag
673 if (fParent) {
674 bool olfVisible = fVisible;
675 UpdateVisibleDeep(fParent->IsVisible());
676 if (olfVisible != fVisible) {
677 // include or exclude us from the parent area
678 fParent->RebuildClipping(false);
679 if (fWindow) {
680 // trigger a redraw
681 BRect clippedBounds = Bounds();
682 ConvertToVisibleInTopView(&clippedBounds);
683 BRegion dirty(clippedBounds);
684 fWindow->MarkContentDirty(&dirty);
687 } else {
688 UpdateVisibleDeep(true);
693 // IsHidden
694 bool
695 ViewLayer::IsHidden() const
697 return fHidden;
700 // UpdateVisibleDeep
701 void
702 ViewLayer::UpdateVisibleDeep(bool parentVisible)
704 fVisible = parentVisible && !fHidden;
705 for (ViewLayer* child = FirstChild(); child; child = NextChild())
706 child->UpdateVisibleDeep(fVisible);
709 // PrintToStream
710 void
711 ViewLayer::PrintToStream() const
715 // RebuildClipping
716 void
717 ViewLayer::RebuildClipping(bool deep)
719 // the clipping spans over the bounds area
720 fLocalClipping.Set(Bounds());
722 // exclude all childs from the clipping
723 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
724 if (child->IsVisible())
725 fLocalClipping.Exclude(child->Frame());
727 if (deep)
728 child->RebuildClipping(deep);
731 fScreenClippingValid = false;
734 // ScreenClipping
735 BRegion&
736 ViewLayer::ScreenClipping(BRegion* windowContentClipping, bool force) const
738 if (!fScreenClippingValid || force) {
739 fScreenClipping = fLocalClipping;
740 ConvertToTop(&fScreenClipping);
742 // see if we parts of our bounds are hidden underneath
743 // the parent, the local clipping does not account for this
744 BRect clippedBounds = Bounds();
745 ConvertToVisibleInTopView(&clippedBounds);
746 if (clippedBounds.Width() < fScreenClipping.Frame().Width() ||
747 clippedBounds.Height() < fScreenClipping.Frame().Height()) {
748 BRegion temp(clippedBounds);
749 fScreenClipping.IntersectWith(&temp);
752 fScreenClipping.IntersectWith(windowContentClipping);
753 fScreenClippingValid = true;
755 return fScreenClipping;
758 // InvalidateScreenClipping
759 void
760 ViewLayer::InvalidateScreenClipping(bool deep)
762 fScreenClippingValid = false;
763 if (deep) {
764 // invalidate the childrens screen clipping as well
765 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
766 child->InvalidateScreenClipping(deep);
771 // _MoveScreenClipping
772 void
773 ViewLayer::_MoveScreenClipping(int32 x, int32 y, bool deep)
775 if (fScreenClippingValid)
776 fScreenClipping.OffsetBy(x, y);
778 if (deep) {
779 // move the childrens screen clipping as well
780 for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
781 child->_MoveScreenClipping(x, y, deep);