From 748533bbf95e758bb1d775b4f2b0770dd6b22722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Mon, 28 Nov 2005 19:28:38 +0000 Subject: [PATCH] figured out and solved several problems: * views are now correctly clipped when they are (partly) hidden under their parent(s) * removed fIsTopView, the top view in a window simply has no parent * introduced WindowLayer::CopyContents() which blits part of the contents to another location, while moving that part in the dirty regions. Since this is currently used from the Desktop thread, messing with the update session dirty regions requires now to lock the clipping * that feature is now used for blitting a view to its new location in ViewLayer::MoveBy(), which works for right and/or bottom aligned views just fine * I left the global dirty region in Desktop for now, moving it into each WindowLayer gave quite a slowdown and caused all kinds of other problems. * a view is now cleared to the background color right before the first drawing command from the client is executed for that view, this reduces flickering a lot because the content is drawn much more shortly after the background is cleared. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15201 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../servers/app/newerClipping/Desktop.cpp | 16 +- .../servers/app/newerClipping/ViewLayer.cpp | 264 ++++++++++-------- .../servers/app/newerClipping/ViewLayer.h | 11 +- .../servers/app/newerClipping/WindowLayer.cpp | 105 +++++-- .../servers/app/newerClipping/WindowLayer.h | 25 +- src/tests/servers/app/newerClipping/main.cpp | 6 +- 6 files changed, 273 insertions(+), 154 deletions(-) diff --git a/src/tests/servers/app/newerClipping/Desktop.cpp b/src/tests/servers/app/newerClipping/Desktop.cpp index 08fd756b40..e10278adff 100644 --- a/src/tests/servers/app/newerClipping/Desktop.cpp +++ b/src/tests/servers/app/newerClipping/Desktop.cpp @@ -159,13 +159,13 @@ Desktop::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) if (dx != 0 || dy != 0) { if (fClickedWindow) { -bigtime_t now = system_time(); +//bigtime_t now = system_time(); if (fResizing) { ResizeWindowBy(fClickedWindow, dx, dy); -printf("resizing: %lld\n", system_time() - now); +//printf("resizing: %lld\n", system_time() - now); } else { MoveWindowBy(fClickedWindow, dx, dy); -printf("moving: %lld\n", system_time() - now); +//printf("moving: %lld\n", system_time() - now); } } } @@ -358,6 +358,9 @@ Desktop::BottomWindow() const void Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y) { + if (!Lock()) + return; + if (LockClipping()) { // the dirty region starts with the visible area of the window being moved BRegion newDirtyRegion(window->VisibleRegion()); @@ -403,12 +406,17 @@ Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y) UnlockClipping(); } + + Unlock(); } // ResizeWindowBy void Desktop::ResizeWindowBy(WindowLayer* window, int32 x, int32 y) { + if (!Lock()) + return; + if (LockClipping()) { BRegion newDirtyRegion; BRegion previouslyOccupiedRegion(window->VisibleRegion()); @@ -428,6 +436,8 @@ Desktop::ResizeWindowBy(WindowLayer* window, int32 x, int32 y) UnlockClipping(); } + + Unlock(); } // BringToFront diff --git a/src/tests/servers/app/newerClipping/ViewLayer.cpp b/src/tests/servers/app/newerClipping/ViewLayer.cpp index 61490957c6..83180bd588 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.cpp +++ b/src/tests/servers/app/newerClipping/ViewLayer.cpp @@ -31,7 +31,6 @@ ViewLayer::ViewLayer(BRect frame, const char* name, fWindow(NULL), fParent(NULL), - fIsTopLayer(false), fFirstChild(NULL), fPreviousSibling(NULL), @@ -72,12 +71,23 @@ ViewLayer::Bounds() const return bounds; } +// ConvertToVisibleInTopView +void +ViewLayer::ConvertToVisibleInTopView(BRect* bounds) const +{ + *bounds = *bounds & Bounds(); + // NOTE: this step is necessary even if we don't have a parent! + ConvertToParent(bounds); + + if (fParent) + fParent->ConvertToVisibleInTopView(bounds); +} + // AttachedToWindow void -ViewLayer::AttachedToWindow(WindowLayer* window, bool topLayer) +ViewLayer::AttachedToWindow(WindowLayer* window) { fWindow = window; - fIsTopLayer = topLayer; for (ViewLayer* child = FirstChild(); child; child = NextChild()) child->AttachedToWindow(window); @@ -211,13 +221,13 @@ ViewLayer::LastChild() const ViewLayer* ViewLayer::TopLayer() { - if (fIsTopLayer) - return this; + // returns the top level view of the hirarchy, + // it doesn't have to be the top level of a window if (fParent) return fParent->TopLayer(); - else - return NULL; + + return this; } // CountChildren @@ -328,6 +338,36 @@ ViewLayer::ConvertToTop(BRegion* region) const fParent->ConvertToTop(region); } +// ConvertFromTop +void +ViewLayer::ConvertFromTop(BPoint* point) const +{ + ConvertFromParent(point); + + if (fParent) + fParent->ConvertFromTop(point); +} + +// ConvertFromTop +void +ViewLayer::ConvertFromTop(BRect* rect) const +{ + ConvertFromParent(rect); + + if (fParent) + fParent->ConvertFromTop(rect); +} + +// ConvertFromTop +void +ViewLayer::ConvertFromTop(BRegion* region) const +{ + ConvertFromParent(region); + + if (fParent) + fParent->ConvertFromTop(region); +} + // SetName void ViewLayer::SetName(const char* string) @@ -335,72 +375,7 @@ ViewLayer::SetName(const char* string) fName.SetTo(string); } -#if 0 -// MoveBy -void -ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) -{ - if (x == 0 && y == 0) - return; - - if (!fIsTopLayer && fWindow) { - // blit to new location (children as well) - BRect screenRect; -if (fParent) { - screenRect = fFrame & fParent->Bounds(); - fParent->ConvertToTop(&screenRect); -} else { - screenRect = Bounds(); - ConvertToTop(&screenRect); -} - - BRegion effectiveClippingRegion; - fWindow->GetContentRegion(&effectiveClippingRegion); - effectiveClippingRegion.IntersectWith(&fWindow->VisibleRegion()); - - BRegion copyRegion(screenRect); - copyRegion.IntersectWith(&effectiveClippingRegion); - - copyRegion.OffsetBy(x, y); - copyRegion.IntersectWith(&effectiveClippingRegion); - - BRegion alreadyDirty(screenRect); - { - BRegion windowDirty(fWindow->DirtyRegion()); - alreadyDirty.IntersectWith(&windowDirty); - } - - fFrame.OffsetBy(x, y); - _MoveScreenClipping(x, y, true); - -if (fParent) { - screenRect = fFrame & fParent->Bounds(); - fParent->ConvertToTop(&screenRect); -} else { - screenRect = Bounds(); - ConvertToTop(&screenRect); -} - BRegion dirtyRegion(screenRect); - dirtyRegion.Exclude(©Region); - - alreadyDirty.OffsetBy(x, y); - dirtyRegion.Include(&alreadyDirty); - - fWindow->MarkDirty(&dirtyRegion); - - copyRegion.OffsetBy(-x, -y); - - if (fWindow->GetDrawingEngine()->Lock()) { - fWindow->GetDrawingEngine()->CopyRegion(©Region, x, y); - fWindow->GetDrawingEngine()->Unlock(); - } - } else { - fFrame.OffsetBy(x, y); - _MoveScreenClipping(x, y, true); - } - fFrame.OffsetBy(x, y); -} -#else // 0 +#pragma mark - // MoveBy void @@ -410,28 +385,64 @@ ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) return; fFrame.OffsetBy(x, y); - InvalidateScreenClipping(true); // to move on screen, we must not be hidden and we must have a parent - if (!IsHidden() && fParent && !fIsTopLayer && dirtyRegion) { - // clip to parent - BRect oldScreenRect(Bounds()); - oldScreenRect.OffsetByCopy(-x, -y); - ConvertToParent(&oldScreenRect); + if (!IsHidden() && fParent && dirtyRegion) { +#if 0 +// based on redraw on new location + // the place were we are now visible + BRect newVisibleBounds = Bounds(); + // we can use the frame of the old + // local clipping to see which parts need invalidation + BRect oldVisibleBounds(Bounds()); + oldVisibleBounds.OffsetBy(-x, -y); + ConvertToTop(&oldVisibleBounds); - BRect screenRect(Bounds()); - ConvertToParent(&screenRect); + ConvertToVisibleInTopView(&newVisibleBounds); - // TODO: see AddChild - // TODO: shouldn't we use regions? - BRect dirty = oldScreenRect | screenRect; - dirty = dirty & fParent->Bounds(); - fParent->ConvertToTop(&dirty); - - dirtyRegion->Include(dirty); + dirtyRegion->Include(oldVisibleBounds); + // newVisibleBounds already is in screen coords + dirtyRegion->Include(newVisibleBounds); +#else +// blitting version, invalidates +// old contents + BRect oldVisibleBounds(Bounds()); + oldVisibleBounds.OffsetBy(-x, -y); + ConvertToTop(&oldVisibleBounds); + + BRect newVisibleBounds(Bounds()); + // NOTE: using ConvertToVisibleInTopView() + // instead of ConvertToTop()! see below + ConvertToVisibleInTopView(&newVisibleBounds); + + newVisibleBounds.OffsetBy(-x, -y); + + // clipping oldVisibleBounds to newVisibleBounds + // makes sure we don't copy parts hidden under + // parent views + BRegion copyRegion(oldVisibleBounds & newVisibleBounds); + fWindow->CopyContents(©Region, x, y); + + BRegion dirty(oldVisibleBounds); + newVisibleBounds.OffsetBy(x, y); + dirty.Exclude(newVisibleBounds); + dirtyRegion->Include(&dirty); +#endif + } + + if (!fParent) { + // the top view's screen clipping does not change, + // because no parts are clipped away from parent + // views + _MoveScreenClipping(x, y, true); + } else { + // parts might have been revealed from underneath + // the parent, or might now be hidden underneath + // the parent, this is taken care of when building + // the screen clipping + InvalidateScreenClipping(true); } } -#endif // 0 // ResizeBy void @@ -472,19 +483,17 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) ConvertToTop(&dirty); dirtyRegion->Include(&dirty); } - - // layout the children - for (ViewLayer* child = FirstChild(); child; child = NextChild()) - child->ParentResized(x, y, dirtyRegion); - - // at this point, children are at their new locations, - // so we can rebuild the clipping - RebuildClipping(false); - } else { - // just layout the children - for (ViewLayer* child = FirstChild(); child; child = NextChild()) - child->ParentResized(x, y, NULL); } + + // layout the children + for (ViewLayer* child = FirstChild(); child; child = NextChild()) + child->ParentResized(x, y, dirtyRegion); + + // at this point, children are at their new locations, + // so we can rebuild the clipping + // TODO: when the implementation of Hide() and Show() is + // complete, see if this should be avoided + RebuildClipping(false); } // ParentResized @@ -542,6 +551,8 @@ ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion) InvalidateScreenClipping(true); } +#pragma mark - + // Draw void ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, @@ -606,20 +617,17 @@ ViewLayer::ClientDraw(DrawingEngine* drawingEngine, BRegion* effectiveClipping) } } +#pragma mark - + // IsHidden bool ViewLayer::IsHidden() const { - // if we're explicitely hidden... + // if we're explicitely hidden, then we're hidden... if (fHidden) return true; - // if we don't have a window, or our window is hidden, - // then yes, we're hidden too - if (fWindow == NULL || (fWindow && fWindow->IsHidden())) - return true; - - // if we're not hidden yet, we might still be hidden if our parent is + // ...but if we're not hidden, we might still be hidden if our parent is if (fParent) return fParent->IsHidden(); @@ -631,18 +639,30 @@ ViewLayer::IsHidden() const void ViewLayer::Hide() { - fHidden = true; + if (!fHidden) { + fHidden = true; - // TODO: track regions + if (fParent && !fParent->IsHidden()) { + // TODO: track regions + // RebuildClipping() + // ... + } + } } // Show void ViewLayer::Show() { - fHidden = false; + if (fHidden) { + fHidden = false; - // TODO: track regions + if (fParent && !fParent->IsHidden()) { + // TODO: track regions + // RebuildClipping() + // ... + } + } } // PrintToStream @@ -655,9 +675,6 @@ ViewLayer::PrintToStream() const void ViewLayer::RebuildClipping(bool deep) { - // remember current local clipping in dirty region - BRegion oldLocalClipping(fLocalClipping); - // the clipping spans over the bounds area fLocalClipping.Set(Bounds()); @@ -678,13 +695,18 @@ ViewLayer::ScreenClipping(BRegion* windowContentClipping, bool force) const { if (!fScreenClippingValid || force) { fScreenClipping = fLocalClipping; - if (fParent) { - BRect parentWindow = fParent->Bounds(); - ConvertFromParent(&parentWindow); - BRegion visibleInParent(parentWindow); - fScreenClipping.IntersectWith(&visibleInParent); - } ConvertToTop(&fScreenClipping); + + // see if we parts of our bounds are hidden underneath + // the parent, the local clipping does not account for this + BRect clippedBounds = Bounds(); + ConvertToVisibleInTopView(&clippedBounds); + if (clippedBounds.Width() < fScreenClipping.Frame().Width() || + clippedBounds.Height() < fScreenClipping.Frame().Height()) { + BRegion temp(clippedBounds); + fScreenClipping.IntersectWith(&temp); + } + fScreenClipping.IntersectWith(windowContentClipping); fScreenClippingValid = true; } diff --git a/src/tests/servers/app/newerClipping/ViewLayer.h b/src/tests/servers/app/newerClipping/ViewLayer.h index cc4bcbc6b3..ccebad45b6 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.h +++ b/src/tests/servers/app/newerClipping/ViewLayer.h @@ -23,12 +23,14 @@ class ViewLayer { inline BRect Frame() const { return fFrame; } BRect Bounds() const; + // converts the given frame up the view hirarchy and + // clips to each views bounds + void ConvertToVisibleInTopView(BRect* bounds) const; inline rgb_color ViewColor() const { return fViewColor; } - void AttachedToWindow(WindowLayer* window, - bool topLayer = false); + void AttachedToWindow(WindowLayer* window); void DetachedFromWindow(); // tree stuff @@ -61,6 +63,10 @@ class ViewLayer { void ConvertToTop(BRect* rect) const; void ConvertToTop(BRegion* region) const; + void ConvertFromTop(BPoint* point) const; + void ConvertFromTop(BRect* rect) const; + void ConvertFromTop(BRegion* region) const; + // settings void SetName(const char* string); inline const char* Name() const @@ -120,7 +126,6 @@ private: WindowLayer* fWindow; ViewLayer* fParent; - bool fIsTopLayer; ViewLayer* fFirstChild; ViewLayer* fPreviousSibling; diff --git a/src/tests/servers/app/newerClipping/WindowLayer.cpp b/src/tests/servers/app/newerClipping/WindowLayer.cpp index 4eeaafbd02..7c8bda7015 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.cpp +++ b/src/tests/servers/app/newerClipping/WindowLayer.cpp @@ -56,7 +56,7 @@ WindowLayer::WindowLayer(BRect frame, const char* name, // fFrame as if it had fTopLayer = new(nothrow) ViewLayer(fFrame, "top view", B_FOLLOW_ALL, 0, (rgb_color){ 255, 255, 255, 255 }); - fTopLayer->AttachedToWindow(this, true); + fTopLayer->AttachedToWindow(this); fClient->Run(); } @@ -82,7 +82,7 @@ WindowLayer::MessageReceived(BMessage* message) } } _DrawBorder(); - _DrawContents(fTopLayer); + _TriggerContentRedraw(); fDesktop->ReadUnlockClipping(); } else { @@ -307,6 +307,7 @@ WindowLayer::Show() void WindowLayer::MarkDirty(BRegion* regionOnScreen) { + // for triggering MSG_REDRAW if (fDesktop) fDesktop->MarkDirty(regionOnScreen); } @@ -315,6 +316,7 @@ WindowLayer::MarkDirty(BRegion* regionOnScreen) void WindowLayer::MarkContentDirty(BRegion* regionOnScreen) { + // for triggering MSG_REDRAW if (fDesktop && fDesktop->LockClipping()) { regionOnScreen->IntersectWith(&fVisibleContentRegion); @@ -323,29 +325,65 @@ WindowLayer::MarkContentDirty(BRegion* regionOnScreen) fDesktop->UnlockClipping(); } } -/* -// DirtyRegion -BRegion -WindowLayer::DirtyRegion() -{ - BRegion dirty; - if (fDesktop->ReadLockClipping()) { - dirty = *fDesktop->DirtyRegion(); - fDesktop->ReadUnlockClipping(); - } - return dirty; -} -*/ + # pragma mark - -// _DrawContents +// CopyContents void -WindowLayer::_DrawContents(ViewLayer* layer) +WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset) +{ + // this function takes care of invalidating parts that could not be copied + + if (fDesktop->LockClipping()) { + + BRegion newDirty(*region); + + region->IntersectWith(&fVisibleContentRegion); + region->OffsetBy(xOffset, yOffset); + region->IntersectWith(&fVisibleContentRegion); + + region->OffsetBy(-xOffset, -yOffset); + + newDirty.Exclude(region); + + _ShiftPartOfRegion(fDesktop->DirtyRegion(), region, xOffset, yOffset); + if (fDrawingEngine->Lock()) { + fDrawingEngine->CopyRegion(region, xOffset, yOffset); + fDrawingEngine->Unlock(); + } + + if (fCurrentUpdateSession) + _ShiftPartOfRegion(&fCurrentUpdateSession->DirtyRegion(), region, xOffset, yOffset); + if (fPendingUpdateSession) + _ShiftPartOfRegion(&fPendingUpdateSession->DirtyRegion(), region, xOffset, yOffset); + + newDirty.OffsetBy(xOffset, yOffset); + newDirty.IntersectWith(&fVisibleContentRegion); + fDesktop->MarkDirty(&newDirty); + + fDesktop->UnlockClipping(); + } +} + +# pragma mark - + +// _ShiftPartOfRegion +void +WindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, + int32 xOffset, int32 yOffset) +{ + BRegion common(*region); + common.IntersectWith(regionToShift); + region->Exclude(&common); + common.OffsetBy(xOffset, yOffset); + region->Include(&common); +} + +// _TriggerContentRedraw +void +WindowLayer::_TriggerContentRedraw() { //printf("%s - DrawContents()\n", Name()); - if (!layer) - layer = fTopLayer; - if (fDesktop->ReadLockClipping()) { BRegion dirtyContentRegion(fVisibleContentRegion); @@ -367,8 +405,8 @@ if (fDrawingEngine->Lock()) { fDesktop->MarkClean(&dirtyContentRegion); - layer->Draw(fDrawingEngine, &dirtyContentRegion, - &fVisibleContentRegion, true); + fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion, + &fVisibleContentRegion, false); } fDesktop->ReadUnlockClipping(); @@ -398,8 +436,14 @@ WindowLayer::_DrawClient(int32 token) BRegion effectiveClipping(fEffectiveDrawingRegion); effectiveClipping.IntersectWith(&layer->ScreenClipping(&fVisibleContentRegion)); - + if (effectiveClipping.CountRects() > 0) { + // clear the back ground + // TODO: only if this is the first drawing command for + // this layer of course! + layer->Draw(fDrawingEngine, &effectiveClipping, + &fVisibleContentRegion, false); + layer->ClientDraw(fDrawingEngine, &effectiveClipping); } @@ -456,6 +500,8 @@ WindowLayer::_DrawBorder() void WindowLayer::_MarkContentDirty(BRegion* contentDirtyRegion) { +if (fDesktop->ReadLockClipping()) { + if (contentDirtyRegion->CountRects() <= 0) return; @@ -480,12 +526,17 @@ WindowLayer::_MarkContentDirty(BRegion* contentDirtyRegion) fClient->PostMessage(MSG_UPDATE); fUpdateRequested = true; } + +fDesktop->ReadUnlockClipping(); +} } // _BeginUpdate void WindowLayer::_BeginUpdate() { +if (fDesktop->ReadLockClipping()) { + if (fUpdateRequested && !fCurrentUpdateSession) { fCurrentUpdateSession = fPendingUpdateSession; fPendingUpdateSession = NULL; @@ -498,12 +549,17 @@ WindowLayer::_BeginUpdate() } fEffectiveDrawingRegionValid = false; } + +fDesktop->ReadUnlockClipping(); +} } // _EndUpdate void WindowLayer::_EndUpdate() { +if (fDesktop->ReadLockClipping()) { + if (fInUpdate) { delete fCurrentUpdateSession; fCurrentUpdateSession = NULL; @@ -518,6 +574,9 @@ WindowLayer::_EndUpdate() } else { fUpdateRequested = false; } + +fDesktop->ReadUnlockClipping(); +} } #pragma mark - diff --git a/src/tests/servers/app/newerClipping/WindowLayer.h b/src/tests/servers/app/newerClipping/WindowLayer.h index 8b4682c917..9785016821 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.h +++ b/src/tests/servers/app/newerClipping/WindowLayer.h @@ -74,13 +74,19 @@ class WindowLayer : public BLooper { DrawingEngine* GetDrawingEngine() const { return fDrawingEngine; } -// BRegion DirtyRegion(); + void CopyContents(BRegion* region, + int32 xOffset, int32 yOffset); private: - void _DrawContents(ViewLayer* layer = NULL); + void _ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, + int32 xOffset, int32 yOffset); + + // different types of drawing + void _TriggerContentRedraw(); void _DrawClient(int32 token); void _DrawBorder(); + // handling update sessions void _MarkContentDirty(BRegion* contentDirtyRegion); void _BeginUpdate(); void _EndUpdate(); @@ -110,11 +116,26 @@ class WindowLayer : public BLooper { DrawingEngine* fDrawingEngine; Desktop* fDesktop; + // for mapping drawing requests from the client + // to the local view pointers BList fTokenViewMap; + // the client looper, which will do asynchronous + // drawing (the window will clear the content + // and the client is supposed to draw onto + // the cleared regions) ClientLooper* fClient; + // The synchronization, which client drawing commands + // belong to the redraw of which region is handled + // through an UpdateSession. When the client has + // been informed that it should redraw stuff, then + // this is the current update session. All new + // redraw requests from the root layer will go + // into the pending update session. UpdateSession* fCurrentUpdateSession; UpdateSession* fPendingUpdateSession; + // these two flags are supposed to ensure a sane + // and consistent update session bool fUpdateRequested; bool fInUpdate; }; diff --git a/src/tests/servers/app/newerClipping/main.cpp b/src/tests/servers/app/newerClipping/main.cpp index ca1a9e266e..be19c388c6 100644 --- a/src/tests/servers/app/newerClipping/main.cpp +++ b/src/tests/servers/app/newerClipping/main.cpp @@ -144,13 +144,15 @@ Window::AddWindow(BRect frame, const char* name) f.OffsetBy(f.Width() + 6, 0); - layer = new ViewLayer(f, "View", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM, +// layer = new ViewLayer(f, "View", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM, + layer = new ViewLayer(f, "View", B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_FULL_UPDATE_ON_RESIZE, (rgb_color){ 120, 120, 120, 255 }); layer1->AddChild(layer); f.OffsetBy(f.Width() + 6, 0); - layer = new ViewLayer(f, "View", B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM, +// layer = new ViewLayer(f, "View", B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM, + layer = new ViewLayer(f, "View", B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_FULL_UPDATE_ON_RESIZE, (rgb_color){ 120, 120, 120, 255 }); layer1->AddChild(layer); }