[haiku-development] Problem with layout and TabView

  • From: Sean Healy <jalopeura@xxxxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Thu, 09 Apr 2009 16:38:56 +0200

I'm having a problem that I believe is connected to the layout system. I have a GroupView within a ScrollView; if there is more than one group, each ScrollView gets placed into a TabView.


If there's only one group (and therefore no TabView), everything works fine. The scrollbar is the right size and I can scroll all the way to the bottom of the contained GroupView.

However, when there's a TabView involved, the ScrollView is taller than the TabView's container, and I can't figure out why. The scrollbar is one long button, and so I can't scroll to the stuff that doesn't fit in the TabView's dimensions.

Here is some output. Notice that even though the container is resized to dimensions that look okay, when the event gets to the ScrollView's FrameResized() function, the height is several times too large.

TabView ViewForTab resized to -000000006x-000000027
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: -000000006x-000000028
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: 0000000000x0000000000
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: 0000000000x0000000000
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: 0000000000x0000000000
DynamicScrollView frame resized in FrameResized to 0000000435x0000006104
DynamicScrollView: Updating bars
        Target:   0000000435x0000003044
        Scroller: 0000000435x0000006104
DynamicScrollView frame resized in FrameResized to 0000000435x0000006104
DynamicScrollView: Updating bars
        Target:   0000000420x0000006104
        Scroller: 0000000435x0000006104
TabView container resized to 0000000435x0000000584
DynamicScrollView frame resized in FrameResized to 0000000435x0000006104
DynamicScrollView: Updating bars
        Target:   0000000420x0000006104
        Scroller: 0000000435x0000006104
DynamicScrollView frame resized in FrameResized to 0000000435x0000006163
DynamicScrollView: Updating bars
        Target:   0000000435x0000003081
        Scroller: 0000000435x0000006163
TabView ViewForTab resized to -000000006x-000000027
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: -000000006x-000000028
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: 0000000000x0000000000
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: 0000000000x0000000000
DynamicScrollView: Updating bars
        Target:   0000000000x0000000000
        Scroller: 0000000000x0000000000
DynamicScrollView frame resized in FrameResized to 0000000435x0000006104
DynamicScrollView: Updating bars
        Target:   0000000435x0000003044
        Scroller: 0000000435x0000006104
DynamicScrollView frame resized in FrameResized to 0000000435x0000006104
DynamicScrollView: Updating bars
        Target:   0000000420x0000006104
        Scroller: 0000000435x0000006104
TabView container resized to 0000000435x0000000584
DynamicScrollView frame resized in FrameResized to 0000000435x0000006104
DynamicScrollView: Updating bars
        Target:   0000000420x0000006104
        Scroller: 0000000435x0000006104
DynamicScrollView frame resized in FrameResized to 0000000435x0000006163
DynamicScrollView: Updating bars
        Target:   0000000435x0000003081
        Scroller: 0000000435x0000006163



Here is the code for the three classes involved.


//      #pragma mark -


DynamicScrollView::DynamicScrollView(const char *name, BView *target)
//: BView(target->Frame(), name, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
        : BGroupView(B_VERTICAL, 0),    
        fHorizontalScrollBar(NULL),
        fVerticalScrollBar(NULL),
        fTarget(target),
        fIsDocumentScroller(false)
{
        SetName(name),
        SetFlags(B_WILL_DRAW | B_FRAME_EVENTS),
        //fContentBounds.Set(-1, -1, -1, -1);
        //SetViewColor(fTarget->ViewColor());
        SetViewColor(255,0,0);
        //target->MoveTo(B_ORIGIN);
        GetLayout()->AddView(target);
}


DynamicScrollView::~DynamicScrollView()
{
}


void
DynamicScrollView::AttachedToWindow(void)
{
        BRect frame = ConvertToScreen(Bounds());
        BRect windowFrame = Window()->Frame();

        fIsDocumentScroller = Parent() == NULL
                && Window() != NULL
                && Window()->Look() == B_DOCUMENT_WINDOW_LOOK
                && frame.right == windowFrame.right
                && frame.bottom == windowFrame.bottom;

        UpdateBars();
}


void
DynamicScrollView::FrameResized(float width, float height)
{
        
        ERROR("DynamicScrollView frame resized in FrameResized to 
%010dx%010d\n",
                int(width), int(height)
        );
        UpdateBars();
}


void
DynamicScrollView::FrameMoved(BPoint newPosition)
{
        UpdateBars();
}


void
DynamicScrollView::GetPreferredSize(float *_width, float *_height)
{
        float width = 50;
        if (fVerticalScrollBar)
                width += B_V_SCROLL_BAR_WIDTH;
        float height = 50;
        if (fHorizontalScrollBar)
                height += B_H_SCROLL_BAR_HEIGHT;
        if (_width)
                *_width = width;
        if (_height)
                *_height = height;
}


void
DynamicScrollView::SetContentBounds(BRect bounds)
{
        fContentBounds = bounds;
        if (Window())
                UpdateBars();
}


void
DynamicScrollView::UpdateBars()
{
        // we need the size that the view wants to have, and the one
        // it could have (without the space for the scroll bars)

        float width, height;
        //if (fContentBounds == BRect(-1, -1, -1, -1))
                fTarget->GetPreferredSize(&width, &height);
        //else {
        //      width = fContentBounds.Width();
        //      height = fContentBounds.Height();
        //}

        BRect bounds = Bounds();
        
ERROR("DynamicScrollView: Updating bars\n\tTarget: %010dx%010d\n\tScroller: %010dx%010d\n",
                int(width), int(height),
                int(bounds.Width()), int(bounds.Height())
        );

        // do we have to remove a scroll bar?

        bool horizontal = width > bounds.Width();
        bool vertical = height > bounds.Height();

// for testing  
vertical = true;

        if (!horizontal && fHorizontalScrollBar != NULL) {
                RemoveChild(fHorizontalScrollBar);
                delete fHorizontalScrollBar;
                fHorizontalScrollBar = NULL;
        }

        if (!vertical && fVerticalScrollBar != NULL) {
                RemoveChild(fVerticalScrollBar);
                delete fVerticalScrollBar;
                fVerticalScrollBar = NULL;
        }

        // or do we have to add a scroll bar?

        if (horizontal && fHorizontalScrollBar == NULL) {
                BRect rect = Bounds();
                rect.top = rect.bottom + 1 - B_H_SCROLL_BAR_HEIGHT;
                if (vertical || fIsDocumentScroller)
                        rect.right -= B_V_SCROLL_BAR_WIDTH;

                fHorizontalScrollBar = new BScrollBar(rect, "horizontal", 
fTarget, 0,
                        width, B_HORIZONTAL);
                AddChild(fHorizontalScrollBar);
        }

        if (vertical && fVerticalScrollBar == NULL) {
                BRect rect = Bounds();
                rect.left = rect.right + 1 - B_V_SCROLL_BAR_WIDTH;
                if (horizontal || fIsDocumentScroller)
                        rect.bottom -= B_H_SCROLL_BAR_HEIGHT;

                fVerticalScrollBar = new BScrollBar(rect, "vertical", fTarget, 
0,
                        height, B_VERTICAL);
                AddChild(fVerticalScrollBar);
        }

        // update the scroll bar range & proportions and layout views

        bounds = Bounds();
        if (fHorizontalScrollBar != NULL)
                bounds.bottom -= B_H_SCROLL_BAR_HEIGHT + 1;
        if (fVerticalScrollBar != NULL)
                bounds.right -= B_V_SCROLL_BAR_WIDTH + 1;

        fTarget->MoveTo(bounds.LeftTop());
        fTarget->ResizeTo(bounds.Width(), bounds.Height());

        if (fHorizontalScrollBar != NULL) {
                float delta = width - bounds.Width();
                if (delta < 0)
                        delta = 0;

                fHorizontalScrollBar->SetRange(0, delta);
                fHorizontalScrollBar->SetSteps(1, bounds.Width());
                fHorizontalScrollBar->SetProportion(bounds.Width() / width);

                float barWidth = Bounds().Width();
                if (vertical) {
                        // scrollbars overlap one pixel of the frame
                        barWidth += 1;
                }
                if (vertical || fIsDocumentScroller)
                        barWidth -= B_V_SCROLL_BAR_WIDTH + 1;
                
                fHorizontalScrollBar->MoveTo(bounds.left, bounds.bottom + 1);
                fHorizontalScrollBar->ResizeTo(barWidth, B_H_SCROLL_BAR_HEIGHT);
        }
        if (fVerticalScrollBar != NULL) {
                float delta = height - bounds.Height();
                if (delta < 0)
                        delta = 0;

                fVerticalScrollBar->SetRange(0, delta);
                fVerticalScrollBar->SetSteps(1, bounds.Height());
                fVerticalScrollBar->SetProportion(bounds.Height() / height);

                float barHeight = Bounds().Height();
                if (horizontal) {
                        // scrollbars overlap one pixel of the frame
                        barHeight += 1;
                }
                if (horizontal || fIsDocumentScroller)
                        barHeight -= B_H_SCROLL_BAR_HEIGHT + 1;

                fVerticalScrollBar->MoveTo(bounds.right + 1, bounds.top);
                fVerticalScrollBar->ResizeTo(B_V_SCROLL_BAR_WIDTH, barHeight);
        }
}


//      #pragma mark -

GroupView::GroupView(const char *name, enum orientation orientation, float spacing)
        : BGroupView(orientation, spacing)
{
        SetName(name);
        SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
        SetViewColor(0,255,0);
}


GroupView::~GroupView()
{
}


//      #pragma mark -


/** BTabView is really stupid - it doesn't even resize its content
 *      view when it is resized itself.
 *      This derived class fixes this issue, and also resizes all tab
 *      content views to the size of the container view when they are
 *      selected (does not take their resize flags into account, though).
 */

//TabView::TabView(BRect frame, const char *name, button_width width,
//      uint32 resizingMode, uint32 flags)
//      : BTabView(frame, name, width, resizingMode, flags)
TabView::TabView(const char *name, button_width width, uint32 flags)
        : BTabView(name, width, flags)
{
}


void
TabView::FrameResized(float width, float height)
{
        BRect rect = Bounds();
        rect.top += TabHeight();
        rect.InsetBy(3.0f, 3.0f);
                //ContainerView is inseted by 3.0 in BTabView::_InitObject()
        
        ERROR("TabView container resized to %010dx%010d\n",
                int(rect.Width()), int(rect.Height())
        );

        ContainerView()->ResizeTo(rect.Width(), rect.Height());
}


void
TabView::Select(int32 tab)
{
        BTabView::Select(tab);

        BView *view = ViewForTab(Selection());
        if (view != NULL) {
                //BRect rect = ContainerView()->Bounds();
                
                BRect rect = Bounds();
                rect.top += TabHeight();
                rect.InsetBy(3.0f, 3.0f);
                        //ContainerView is inseted by 3.0 in 
BTabView::_InitObject()
        
                ERROR("TabView ViewForTab resized to %010dx%010d\n",
                        int(rect.Width()), int(rect.Height())
                );
                
                view->ResizeTo(rect.Width(), rect.Height());
        }
}




Other related posts:

  • » [haiku-development] Problem with layout and TabView - Sean Healy