/*
 * Copyright (C) 2010 Rene Gollent <rene@gollent.com>
 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
 *
 * All rights reserved. Distributed under the terms of the MIT License.
 */
 
#include "TabView.h"
 
#include <stdio.h>
 
#include <Application.h>
#include <Bitmap.h>
#include <Button.h>
#include <CardLayout.h>
#include <ControlLook.h>
#include <GroupView.h>
#include <SpaceLayoutItem.h>
#include <Window.h>
 
#include "TabContainerView.h"
 
 
// #pragma mark - TabView
 
 
TabView::TabView()
	:
	fContainerView(NULL),
	fLayoutItem(new TabLayoutItem(this)),
	fLabel()
{
}
 
 
TabView::~TabView()
{
	// The layout item is deleted for us by the layout which contains it.
	if (!fContainerView)
		delete fLayoutItem;
}
 
 
BSize
TabView::MinSize()
{
	BSize size(MaxSize());
	size.width = 60.0f;
	return size;
}
 
 
BSize
TabView::PreferredSize()
{
	return MaxSize();
}
 
 
BSize
TabView::MaxSize()
{
	float extra = be_control_look->DefaultLabelSpacing();
	float labelWidth = 300.0f;
	return BSize(labelWidth, _LabelHeight() + extra);
}
 
 
void
TabView::Draw(BRect updateRect)
{
	BRect frame(fLayoutItem->Frame());
	if (fIsFront) {
		// Extend the front tab outward left/right in order to merge
		// the frames of adjacent tabs.
		if (!fIsFirst)
			frame.left--;
		if (!fIsLast)
			frame.right++;
	}
	frame.bottom++;
 
	DrawBackground(fContainerView, frame, updateRect, fIsFirst, fIsLast,
		fIsFront);
 
	if (fIsFront) {
		frame.top += 3.0f;
		if (!fIsFirst)
			frame.left++;
		if (!fIsLast)
			frame.right--;
	} else
		frame.top += 6.0f;
 
	float spacing = be_control_look->DefaultLabelSpacing();
	frame.InsetBy(spacing, spacing / 2);
	DrawContents(fContainerView, frame, updateRect, fIsFirst, fIsLast,
		fIsFront);
}
 
 
void
TabView::DrawBackground(BView* owner, BRect frame, const BRect& updateRect,
	bool isFirst, bool isLast, bool isFront)
{
	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
	uint32 borders = BControlLook::B_TOP_BORDER
		| BControlLook::B_BOTTOM_BORDER;
 
	if (isFirst)
		borders |= BControlLook::B_LEFT_BORDER;
	if (isLast)
		borders |= BControlLook::B_RIGHT_BORDER;
	if (isFront) {
		be_control_look->DrawActiveTab(owner, frame, updateRect, base,
			0, borders);
	} else {
		be_control_look->DrawInactiveTab(owner, frame, updateRect, base,
			0, borders);
	}
}
 
 
void
TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect,
	bool isFirst, bool isLast, bool isFront)
{
	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
	be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect,
		base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE));
}
 
 
void
TabView::MouseDown(BPoint where, uint32 buttons)
{
	fContainerView->SelectTab(this);
}
 
 
void
TabView::MouseUp(BPoint where)
{
}
 
 
void
TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
{
}
 
 
void
TabView::SetIsFront(bool isFront)
{
	Update(fIsFirst, fIsLast, isFront);
}
 
 
bool
TabView::IsFront() const
{
	return fIsFront;
}
 
 
void
TabView::SetIsLast(bool isLast)
{
	Update(fIsFirst, isLast, fIsFront);
}
 
 
void
TabView::Update(bool isFirst, bool isLast, bool isFront)
{
	if (fIsFirst == isFirst && fIsLast == isLast && fIsFront == isFront)
		return;
	fIsFirst = isFirst;
	fIsLast = isLast;
	fIsFront = isFront;
 
	fLayoutItem->InvalidateContainer();
}
 
 
void
TabView::SetContainerView(TabContainerView* containerView)
{
	fContainerView = containerView;
}
 
 
TabContainerView*
TabView::ContainerView() const
{
	return fContainerView;
}
 
 
BLayoutItem*
TabView::LayoutItem() const
{
	return fLayoutItem;
}
 
 
void
TabView::SetLabel(const char* label)
{
	if (fLabel == label)
		return;
	fLabel = label;
	fLayoutItem->InvalidateLayout();
}
 
 
const BString&
TabView::Label() const
{
	return fLabel;
}
 
 
BRect
TabView::Frame() const
{
	return fLayoutItem->Frame();
}
 
 
float
TabView::_LabelHeight() const
{
	font_height fontHeight;
	fContainerView->GetFontHeight(&fontHeight);
	return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
}
 
 
// #pragma mark - TabLayoutItem
 
 
TabLayoutItem::TabLayoutItem(TabView* parent)
	:
	fParent(parent),
	fVisible(true)
{
}
 
 
bool
TabLayoutItem::IsVisible()
{
	return fVisible;
}
 
 
void
TabLayoutItem::SetVisible(bool visible)
{
	if (fVisible == visible)
		return;
 
	fVisible = visible;
 
	InvalidateContainer();
	fParent->ContainerView()->InvalidateLayout();
}
 
 
BRect
TabLayoutItem::Frame()
{
	return fFrame;
}
 
 
void
TabLayoutItem::SetFrame(BRect frame)
{
	BRect dirty = fFrame;
	fFrame = frame;
	dirty = dirty | fFrame;
	InvalidateContainer(dirty);
}
 
 
BView*
TabLayoutItem::View()
{
	return NULL;
}
 
 
BSize
TabLayoutItem::BaseMinSize()
{
	return fParent->MinSize();
}
 
 
BSize
TabLayoutItem::BaseMaxSize()
{
	return fParent->MaxSize();
}
 
 
BSize
TabLayoutItem::BasePreferredSize()
{
	return fParent->PreferredSize();
}
 
 
BAlignment
TabLayoutItem::BaseAlignment()
{
	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
}
 
 
TabView*
TabLayoutItem::Parent() const
{
	return fParent;
}
 
 
void
TabLayoutItem::InvalidateContainer()
{
	InvalidateContainer(Frame());
}
 
 
void
TabLayoutItem::InvalidateContainer(BRect frame)
{
	// Invalidate more than necessary, to help the TabContainerView
	// redraw the parts outside any tabs...
	frame.bottom++;
	frame.right++;
	fParent->ContainerView()->Invalidate(frame);
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fIsFirst, fIsLast, fIsFront.