root/src/apps/icon-o-matic/generic/gui/Group.cpp
/*
 * Copyright 2006, Haiku.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Stephan Aßmus <superstippi@gmx.de>
 */

#include "Group.h"

#include <stdio.h>

// constructor
Group::Group(BRect frame, const char* name, orientation direction)
        : BView(frame, name, B_FOLLOW_ALL, B_FRAME_EVENTS),
          fOrientation(direction),
          fInset(4.0),
          fSpacing(0.0)
{
        SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
}

// destructor
Group::~Group()
{
}

// AttachedToWindow
void
Group::AttachedToWindow()
{
        // trigger a layout
        FrameResized(Bounds().Width(), Bounds().Height());
}

// FrameResized
void
Group::FrameResized(float width, float height)
{
        // layout controls
        BRect r(Bounds());
        r.InsetBy(fInset, fInset);
        _LayoutControls(r);
}

// GetPreferredSize
void
Group::GetPreferredSize(float* width, float* height)
{
        BRect r(_MinFrame());

        if (width)
                *width = r.Width();
        if (height)
                *height = r.Height();
}

// #pragma mark -

void
Group::SetSpacing(float insetFromBorder, float childSpacing)
{
        if (fSpacing == childSpacing && fInset == insetFromBorder)
                return;

        fInset = insetFromBorder;
        fSpacing = childSpacing;
        // trigger a layout
        FrameResized(Bounds().Width(), Bounds().Height());
}

// #pragma mark -

// _LayoutControls
void
Group::_LayoutControls(BRect r) const
{
        if (fOrientation == B_HORIZONTAL) {
                r.left -= fSpacing;
                for (int32 i = 0; BView* child = ChildAt(i); i++) {
                        r.right = r.left + child->Bounds().Width() + 2 * fSpacing;
                        _LayoutControl(child, r);
                        r.left = r.right + 1.0 - fSpacing;
                }
        } else {
                r.top -= fSpacing;
                for (int32 i = 0; BView* child = ChildAt(i); i++) {
                        r.bottom = r.top + child->Bounds().Height() + 2 * fSpacing;
                        _LayoutControl(child, r);
                        r.top = r.bottom + 1.0 - fSpacing;
                }
        }
}

// _MinFrame
BRect           
Group::_MinFrame() const
{
        float minWidth = fInset * 2.0;
        float minHeight = fInset * 2.0;

        if (fOrientation == B_HORIZONTAL) {
                minWidth += fSpacing;
                for (int32 i = 0; BView* child = ChildAt(i); i++) {
                        minWidth += child->Bounds().Width() + 1 + fSpacing;
                        minHeight = max_c(minHeight,
                                                          child->Bounds().Height() + 1 + fInset * 2.0);
                }
        } else {
                minHeight += fSpacing;
                for (int32 i = 0; BView* child = ChildAt(i); i++) {
                        minHeight += child->Bounds().Height() + 1 + fSpacing;
                        minWidth = max_c(minWidth,
                                                         child->Bounds().Width() + 1 + fInset * 2.0);
                }
        }

        return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
}

// _LayoutControl
void
Group::_LayoutControl(BView* view, BRect frame,
                                          bool resizeWidth, bool resizeHeight) const
{
        if (!resizeHeight)
                // center vertically
                frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
        if (!resizeWidth)
                // center horizontally
                frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
        view->MoveTo(frame.LeftTop());
        float width = resizeWidth ? frame.Width() : view->Bounds().Width();
        float height = resizeHeight ? frame.Height() : view->Bounds().Height();
        if (resizeWidth || resizeHeight)
                view->ResizeTo(width, height);
}