root/src/kits/interface/LayoutItem.cpp
/*
 * Copyright 2010-2012, Haiku, Inc.
 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
 * All rights reserved. Distributed under the terms of the MIT License.
 */


#include <LayoutItem.h>

#include <Layout.h>
#include <LayoutUtils.h>
#include <View.h>
#include <ViewPrivate.h>

#include <algorithm>


BLayoutItem::BLayoutItem()
        :
        fLayout(NULL),
        fLayoutData(NULL)
{
}


BLayoutItem::BLayoutItem(BMessage* from)
        :
        BArchivable(BUnarchiver::PrepareArchive(from)),
        fLayout(NULL),
        fLayoutData(NULL)
{
        BUnarchiver(from).Finish();
}


BLayoutItem::~BLayoutItem()
{
        if (fLayout != NULL) {
                debugger("Deleting a BLayoutItem that is still attached to a layout. "
                        "Call RemoveSelf first.");
        }
}


BLayout*
BLayoutItem::Layout() const
{
        return fLayout;
}


bool
BLayoutItem::RemoveSelf()
{
        return Layout() != NULL && Layout()->RemoveItem(this);
}


void
BLayoutItem::SetExplicitSize(BSize size)
{
        SetExplicitMinSize(size);
        SetExplicitMaxSize(size);
        SetExplicitPreferredSize(size);
}


bool
BLayoutItem::HasHeightForWidth()
{
        // no "height for width" by default
        return false;
}


void
BLayoutItem::GetHeightForWidth(float width, float* min, float* max,
        float* preferred)
{
        // no "height for width" by default
}


BView*
BLayoutItem::View()
{
        return NULL;
}


void
BLayoutItem::InvalidateLayout(bool children)
{
        LayoutInvalidated(children);
        if (fLayout)
                fLayout->InvalidateLayout(children);
}


void
BLayoutItem::Relayout(bool immediate)
{
        BView* view = View();
        if (view && !immediate)
                view->Relayout();
        else if (view && immediate)
                view->Layout(false);
}


void*
BLayoutItem::LayoutData() const
{
        return fLayoutData;
}


void
BLayoutItem::SetLayoutData(void* data)
{
        fLayoutData = data;
}


void
BLayoutItem::AlignInFrame(BRect frame)
{
        BSize maxSize = MaxSize();
        BAlignment alignment = Alignment();

        if (HasHeightForWidth()) {
                // The item has height for width, so we do the horizontal alignment
                // ourselves and restrict the height max constraint respectively.
                if (maxSize.width < frame.Width()
                        && alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) {
                        frame.left += (int)((frame.Width() - maxSize.width)
                                * alignment.horizontal);
                        frame.right = frame.left + maxSize.width;
                }
                alignment.horizontal = B_ALIGN_USE_FULL_WIDTH;

                float minHeight;
                GetHeightForWidth(frame.Width(), &minHeight, NULL, NULL);

                frame.bottom = frame.top + max_c(frame.Height(), minHeight);
                maxSize.height = minHeight;
        }

        SetFrame(BLayoutUtils::AlignInFrame(frame, maxSize, alignment));
}


status_t
BLayoutItem::Archive(BMessage* into, bool deep) const
{
        BArchiver archiver(into);
        status_t err = BArchivable::Archive(into, deep);

        if (err == B_OK)
                err = archiver.Finish();

        return err;
}


status_t
BLayoutItem::AllArchived(BMessage* into) const
{
        BArchiver archiver(into);
        return BArchivable::AllArchived(into);
}


status_t
BLayoutItem::AllUnarchived(const BMessage* from)
{
        return BArchivable::AllUnarchived(from);
}


void
BLayoutItem::SetLayout(BLayout* layout)
{
        if (layout == fLayout)
                return;

        BLayout* oldLayout = fLayout;
        fLayout = layout;

        if (oldLayout)
                DetachedFromLayout(oldLayout);

        if (BView* view = View()) {
                if (oldLayout && !fLayout) {
                        BView::Private(view).DeregisterLayoutItem(this);
                } else if (fLayout && !oldLayout) {
                        BView::Private(view).RegisterLayoutItem(this);
                }
        }

        if (fLayout)
                AttachedToLayout();
}


status_t
BLayoutItem::Perform(perform_code code, void* _data)
{
        return BArchivable::Perform(code, _data);
}


void
BLayoutItem::LayoutInvalidated(bool children)
{
        // hook method
}


void
BLayoutItem::AttachedToLayout()
{
        // hook method
}


void
BLayoutItem::DetachedFromLayout(BLayout* oldLayout)
{
        // hook method
}


void
BLayoutItem::AncestorVisibilityChanged(bool shown)
{
        // hook method
}


// Binary compatibility stuff


void BLayoutItem::_ReservedLayoutItem1() {}
void BLayoutItem::_ReservedLayoutItem2() {}
void BLayoutItem::_ReservedLayoutItem3() {}
void BLayoutItem::_ReservedLayoutItem4() {}
void BLayoutItem::_ReservedLayoutItem5() {}
void BLayoutItem::_ReservedLayoutItem6() {}
void BLayoutItem::_ReservedLayoutItem7() {}
void BLayoutItem::_ReservedLayoutItem8() {}
void BLayoutItem::_ReservedLayoutItem9() {}
void BLayoutItem::_ReservedLayoutItem10() {}