root/src/kits/interface/AbstractLayout.cpp
/*
 * Copyright 2010, Haiku, Inc.
 * All rights reserved. Distributed under the terms of the MIT License.
 */


#include <AbstractLayout.h>
#include <LayoutUtils.h>
#include <Message.h>
#include <View.h>
#include <ViewPrivate.h>


namespace {
        const char* const kSizesField = "BAbstractLayout:sizes";
                // kSizesField == {min, max, preferred}
        const char* const kAlignmentField = "BAbstractLayout:alignment";
        const char* const kFrameField = "BAbstractLayout:frame";
        const char* const kVisibleField = "BAbstractLayout:visible";

        enum proxy_type { VIEW_PROXY_TYPE, DATA_PROXY_TYPE }; 
}


struct BAbstractLayout::Proxy {

        Proxy(proxy_type type)
                :
                type(type)
        {
        }

        virtual ~Proxy()
        {
        }

        virtual BSize           MinSize() const = 0;
        virtual void            SetMinSize(const BSize&) = 0;

        virtual BSize           MaxSize() const = 0;
        virtual void            SetMaxSize(const BSize&) = 0;

        virtual BSize           PreferredSize() const = 0;
        virtual void            SetPreferredSize(const BSize&) = 0;

        virtual BAlignment      Alignment() const = 0;
        virtual void            SetAlignment(const BAlignment&) = 0;

        virtual BRect           Frame() const = 0;
        virtual void            SetFrame(const BRect& frame) = 0;

        virtual bool            IsVisible(bool ancestorHidden) const = 0;
        virtual void            SetVisible(bool visible) = 0;

        virtual status_t        AddDataToArchive(BMessage* archive,
                                                        bool ancestorHidden) = 0;
        virtual status_t        RestoreDataFromArchive(const BMessage* archive) = 0;

                        proxy_type      type;
};


struct BAbstractLayout::DataProxy : Proxy {

        DataProxy()
                :
                Proxy(DATA_PROXY_TYPE),
                minSize(),
                maxSize(),
                preferredSize(),
                alignment(),
                frame(-1, -1, 0, 0),
                visible(true)
        {
        }

        BSize MinSize() const
        {
                return minSize;
        }

        void SetMinSize(const BSize& min)
        {
                minSize = min;
        }

        BSize MaxSize() const
        {
                return maxSize;
        }

        void SetMaxSize(const BSize& max)
        {
                maxSize = max;
        }

        BSize PreferredSize() const
        {
                return preferredSize;
        }

        void SetPreferredSize(const BSize& preferred)
        {
                preferredSize = preferred;
        }

        BAlignment Alignment() const
        {
                return this->alignment;
        }

        void SetAlignment(const BAlignment& align)
        {
                this->alignment = align;
        }

        BRect Frame() const
        {
                return frame;
        }

        void SetFrame(const BRect& frame)
        {
                if (frame == this->frame)
                        return;
                this->frame = frame;
        }

        bool IsVisible(bool) const
        {
                return visible;
        }

        void SetVisible(bool visible)
        {
                this->visible = visible;
        }

        status_t AddDataToArchive(BMessage* archive, bool ancestorHidden)
        {
                status_t err = archive->AddSize(kSizesField, minSize);
                if (err == B_OK)
                        err = archive->AddSize(kSizesField, maxSize);
                if (err == B_OK)
                        err = archive->AddSize(kSizesField, preferredSize);
                if (err == B_OK)
                        err = archive->AddAlignment(kAlignmentField, alignment);
                if (err == B_OK)
                        err = archive->AddRect(kFrameField, frame);
                if (err == B_OK)
                        err = archive->AddBool(kVisibleField, visible);

                return err;
        }

        status_t RestoreDataFromArchive(const BMessage* archive)
        {
                status_t err = archive->FindSize(kSizesField, 0, &minSize);
                if (err == B_OK)
                        err = archive->FindSize(kSizesField, 1, &maxSize);
                if (err == B_OK)
                        err = archive->FindSize(kSizesField, 2, &preferredSize);
                if (err == B_OK)
                        err = archive->FindAlignment(kAlignmentField, &alignment);
                if (err == B_OK)
                        err = archive->FindRect(kFrameField, &frame);
                if (err == B_OK)
                        err = archive->FindBool(kVisibleField, &visible);

                return err;
        }

        BSize           minSize;
        BSize           maxSize;
        BSize           preferredSize;
        BAlignment      alignment;
        BRect           frame;
        bool            visible;
};


struct BAbstractLayout::ViewProxy : Proxy {
        ViewProxy(BView* target)
                :
                Proxy(VIEW_PROXY_TYPE),
                view(target)
        {
        }

        BSize MinSize() const
        {
                return view->ExplicitMinSize();
        }

        void SetMinSize(const BSize& min)
        {
                view->SetExplicitMinSize(min);
        }

        BSize MaxSize() const
        {
                return view->ExplicitMaxSize();
        }

        void SetMaxSize(const BSize& min)
        {
                view->SetExplicitMaxSize(min);
        }

        BSize PreferredSize() const
        {
                return view->ExplicitPreferredSize();
        }

        void SetPreferredSize(const BSize& preferred)
        {
                view->SetExplicitPreferredSize(preferred);
        }

        BAlignment Alignment() const
        {
                return view->ExplicitAlignment();
        }

        void SetAlignment(const BAlignment& alignment)
        {
                view->SetExplicitAlignment(alignment);
        }

        BRect Frame() const
        {
                return view->Frame();
        }

        void SetFrame(const BRect& frame)
        {
                view->MoveTo(frame.LeftTop());
                view->ResizeTo(frame.Width(), frame.Height());
        }

        bool IsVisible(bool ancestorsVisible) const
        {
                int16 showLevel = BView::Private(view).ShowLevel();
                return (showLevel - (ancestorsVisible ? 0 : 1)) <= 0;
        }

        void SetVisible(bool visible)
        {
                // No need to check that we are not re-hiding, that is done
                // for us.
                if (visible)
                        view->Show();
                else
                        view->Hide();
        }

        status_t AddDataToArchive(BMessage* archive, bool ancestorHidden)
        {
                return B_OK;
        }

        status_t RestoreDataFromArchive(const BMessage* archive)
        {
                return B_OK;
        }

        BView*  view;
};


BAbstractLayout::BAbstractLayout()
        :
        fExplicitData(new BAbstractLayout::DataProxy())
{
}


BAbstractLayout::BAbstractLayout(BMessage* from)
        :
        BLayout(BUnarchiver::PrepareArchive(from)),
        fExplicitData(new DataProxy())
{
        BUnarchiver(from).Finish();
}


BAbstractLayout::~BAbstractLayout()
{
        delete fExplicitData;
}


BSize
BAbstractLayout::MinSize()
{
        return BLayoutUtils::ComposeSize(fExplicitData->MinSize(), BaseMinSize());
}


BSize
BAbstractLayout::MaxSize()
{
        return BLayoutUtils::ComposeSize(fExplicitData->MaxSize(), BaseMaxSize());
}


BSize
BAbstractLayout::PreferredSize()
{
        return BLayoutUtils::ComposeSize(fExplicitData->PreferredSize(),
                BasePreferredSize());
}


BAlignment
BAbstractLayout::Alignment()
{
        return BLayoutUtils::ComposeAlignment(fExplicitData->Alignment(),
                BaseAlignment());
}


void
BAbstractLayout::SetExplicitMinSize(BSize size)
{
        fExplicitData->SetMinSize(size);
}


void
BAbstractLayout::SetExplicitMaxSize(BSize size)
{
        fExplicitData->SetMaxSize(size);
}


void
BAbstractLayout::SetExplicitPreferredSize(BSize size)
{
        fExplicitData->SetPreferredSize(size);
}


void
BAbstractLayout::SetExplicitAlignment(BAlignment alignment)
{
        fExplicitData->SetAlignment(alignment);
}


BSize
BAbstractLayout::BaseMinSize()
{
        return BSize(0, 0);
}


BSize
BAbstractLayout::BaseMaxSize()
{
        return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
}


BSize
BAbstractLayout::BasePreferredSize()
{
        return BSize(0, 0);
}


BAlignment
BAbstractLayout::BaseAlignment()
{
        return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
}


BRect
BAbstractLayout::Frame()
{
        return fExplicitData->Frame();
}


void
BAbstractLayout::SetFrame(BRect frame)
{
        if (frame != fExplicitData->Frame()) {
                fExplicitData->SetFrame(frame);
                if (!Owner())
                        Relayout();
        }
}


bool
BAbstractLayout::IsVisible()
{
        return fExplicitData->IsVisible(AncestorsVisible());
}


void
BAbstractLayout::SetVisible(bool visible)
{
        if (visible != fExplicitData->IsVisible(AncestorsVisible())) {
                fExplicitData->SetVisible(visible);
                if (Layout())
                        Layout()->InvalidateLayout(false);
                VisibilityChanged(visible);
        }
}


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

        return archiver.Finish(err);
}


status_t
BAbstractLayout::AllArchived(BMessage* archive) const
{
        return BLayout::AllArchived(archive);
}


status_t
BAbstractLayout::AllUnarchived(const BMessage* from)
{
        status_t err = fExplicitData->RestoreDataFromArchive(from);
        if (err != B_OK)
                return err;
                
        return BLayout::AllUnarchived(from);
}


status_t
BAbstractLayout::ItemArchived(BMessage* into, BLayoutItem* item,
        int32 index) const
{
        return BLayout::ItemArchived(into, item, index);
}


status_t
BAbstractLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item,
        int32 index)
{
        return BLayout::ItemUnarchived(from, item, index);
}


bool
BAbstractLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
{
        return BLayout::ItemAdded(item, atIndex);
}


void
BAbstractLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
{
        BLayout::ItemRemoved(item, fromIndex);
}


void
BAbstractLayout::LayoutInvalidated(bool children)
{
        BLayout::LayoutInvalidated(children);
}


void
BAbstractLayout::OwnerChanged(BView* was)
{
        if (was) {
                static_cast<ViewProxy*>(fExplicitData)->view = Owner();
                return;
        }

        delete fExplicitData;
        fExplicitData = new ViewProxy(Owner());
}


void
BAbstractLayout::AttachedToLayout()
{
        BLayout::AttachedToLayout();
}


void
BAbstractLayout::DetachedFromLayout(BLayout* layout)
{
        BLayout::DetachedFromLayout(layout);
}


void
BAbstractLayout::AncestorVisibilityChanged(bool shown)
{
        if (AncestorsVisible() == shown)
                return;

        if (BView* owner = Owner()) {
                if (shown)
                        owner->Show();
                else
                        owner->Hide();
        }
        BLayout::AncestorVisibilityChanged(shown);
}


// Binary compatibility stuff


status_t
BAbstractLayout::Perform(perform_code code, void* _data)
{
        return BLayout::Perform(code, _data);
}


void BAbstractLayout::_ReservedAbstractLayout1() {}
void BAbstractLayout::_ReservedAbstractLayout2() {}
void BAbstractLayout::_ReservedAbstractLayout3() {}
void BAbstractLayout::_ReservedAbstractLayout4() {}
void BAbstractLayout::_ReservedAbstractLayout5() {}
void BAbstractLayout::_ReservedAbstractLayout6() {}
void BAbstractLayout::_ReservedAbstractLayout7() {}
void BAbstractLayout::_ReservedAbstractLayout8() {}
void BAbstractLayout::_ReservedAbstractLayout9() {}
void BAbstractLayout::_ReservedAbstractLayout10() {}