/*
 * Copyright 2006-2010, Haiku Inc.
 * Distributed under the terms of the MIT License.
 */
#ifndef	_SPLIT_LAYOUT_H
#define	_SPLIT_LAYOUT_H


#include <AbstractLayout.h>
#include <Point.h>


namespace BPrivate {
namespace Layout {
	class Layouter;
	class LayoutInfo;
}
}

using BPrivate::Layout::Layouter;
using BPrivate::Layout::LayoutInfo;


class BSplitLayout : public BAbstractLayout {
public:
								BSplitLayout(orientation orientation,
									float spacing = 0.0f);
								BSplitLayout(BMessage* from);
	virtual						~BSplitLayout();

			void				SetInsets(float left, float top, float right,
									float bottom);
			void				GetInsets(float* left, float* top, float* right,
									float* bottom) const;

			float				Spacing() const;
			void				SetSpacing(float spacing);

			orientation			Orientation() const;
			void				SetOrientation(orientation orientation);

			float				SplitterSize() const;
			void				SetSplitterSize(float size);

	virtual	BLayoutItem*		AddView(BView* child);
	virtual	BLayoutItem*		AddView(int32 index, BView* child);
	virtual	BLayoutItem*		AddView(BView* child, float weight);
	virtual	BLayoutItem*		AddView(int32 index, BView* child,
									float weight);

	virtual	bool				AddItem(BLayoutItem* item);
	virtual	bool				AddItem(int32 index, BLayoutItem* item);
	virtual	bool				AddItem(BLayoutItem* item, float weight);
	virtual	bool				AddItem(int32 index, BLayoutItem* item,
									float weight);


			float				ItemWeight(int32 index) const;
			float				ItemWeight(BLayoutItem* item) const;
			void				SetItemWeight(int32 index, float weight,
									bool invalidateLayout);
			void				SetItemWeight(BLayoutItem* item, float weight);

			bool				IsCollapsible(int32 index) const;
			void				SetCollapsible(bool collapsible);
			void				SetCollapsible(int32 index, bool collapsible);
			void				SetCollapsible(int32 first, int32 last,
									bool collapsible);

			bool				IsItemCollapsed(int32 index) const;
			void				SetItemCollapsed(int32 index, bool visible);

	virtual	BSize				BaseMinSize();
	virtual	BSize				BaseMaxSize();
	virtual	BSize				BasePreferredSize();
	virtual	BAlignment			BaseAlignment();

	virtual	bool				HasHeightForWidth();
	virtual	void				GetHeightForWidth(float width, float* min,
									float* max, float* preferred);

	virtual	void				LayoutInvalidated(bool children);
	virtual	void				DoLayout();

	// interface for BSplitView
			BRect				SplitterItemFrame(int32 index) const;
			bool				IsAboveSplitter(const BPoint& point) const;

			bool				StartDraggingSplitter(BPoint point);
			bool				DragSplitter(BPoint point);
			bool				StopDraggingSplitter();
			int32				DraggedSplitter() const;

	// archiving methods
	virtual status_t			Archive(BMessage* into, bool deep = true) const;
	static	BArchivable*		Instantiate(BMessage* from);

	virtual status_t			ItemArchived(BMessage* into, BLayoutItem* item,
									int32 index) const;
	virtual	status_t			ItemUnarchived(const BMessage* from,
									BLayoutItem* item, int32 index);

protected:
	virtual	bool				ItemAdded(BLayoutItem* item, int32 atIndex);
	virtual	void				ItemRemoved(BLayoutItem* item, int32 fromIndex);

private:
			class ItemLayoutInfo;
			class ValueRange;
			class SplitterItem;

			void				_InvalidateLayout(bool invalidateView,
									bool children = false);
			void				_InvalidateCachedHeightForWidth();

			SplitterItem*		_SplitterItemAt(const BPoint& point,
									int32* index = NULL) const;
			SplitterItem*		_SplitterItemAt(int32 index) const;

			void				_GetSplitterValueRange(int32 index,
									ValueRange& range);
			int32				_SplitterValue(int32 index) const;

			void				_LayoutItem(BLayoutItem* item, BRect frame,
									bool visible);
			void				_LayoutItem(BLayoutItem* item,
									ItemLayoutInfo* info);

			bool				_SetSplitterValue(int32 index, int32 value);

			ItemLayoutInfo*		_ItemLayoutInfo(BLayoutItem* item) const;


			void				_UpdateSplitterWeights();

			void				_ValidateMinMax();

			void				_InternalGetHeightForWidth(float width,
									bool realLayout, float* minHeight,
									float* maxHeight, float* preferredHeight);

			float				_SplitterSpace() const;

			BSize				_AddInsets(BSize size);
			void				_AddInsets(float* minHeight, float* maxHeight,
									float* preferredHeight);
			BSize				_SubtractInsets(BSize size);

private:
			orientation			fOrientation;
			float				fLeftInset;
			float				fRightInset;
			float				fTopInset;
			float				fBottomInset;
			float				fSplitterSize;
			float				fSpacing;

			BList				fSplitterItems;
			BList				fVisibleItems;

			BSize				fMin;
			BSize				fMax;
			BSize				fPreferred;

			Layouter*			fHorizontalLayouter;
			Layouter*			fVerticalLayouter;

			LayoutInfo*			fHorizontalLayoutInfo;
			LayoutInfo*			fVerticalLayoutInfo;

			BList				fHeightForWidthItems;
			// Incorporates the children's height for width constraints for a
			// concrete width. Cloned lazily from fVerticalLayout when needed.
			Layouter*			fHeightForWidthVerticalLayouter;
			LayoutInfo*			fHeightForWidthHorizontalLayoutInfo;
				// for computing height for width info

			bool				fLayoutValid;

			float				fCachedHeightForWidthWidth;
			float				fHeightForWidthVerticalLayouterWidth;
			float				fCachedMinHeightForWidth;
			float				fCachedMaxHeightForWidth;
			float				fCachedPreferredHeightForWidth;

			BPoint				fDraggingStartPoint;
			int32				fDraggingStartValue;
			int32				fDraggingCurrentValue;
			int32				fDraggingSplitterIndex;
};

#endif	// _SPLIT_LAYOUT_H
