/*
 *  Copyright 2010-2012 Haiku, Inc. All rights reserved.
 *  Distributed under the terms of the MIT license.
 *
 *	Authors:
 *		DarkWyrm <bpmagic@columbus.rr.com>
 *		John Scipione <jscipione@gmail.com>
 */
 
 
#include "FakeScrollBar.h"
 
#include <Box.h>
#include <ControlLook.h>
#include <Message.h>
#include <ScrollBar.h>
#include <Shape.h>
#include <Size.h>
#include <Window.h>
 
 
typedef enum {
	ARROW_LEFT = 0,
	ARROW_RIGHT,
	ARROW_UP,
	ARROW_DOWN,
	ARROW_NONE
} arrow_direction;
 
 
FakeScrollBar::FakeScrollBar(bool drawArrows, bool doubleArrows,
	BMessage* message)
	:
	BControl("FakeScrollBar", NULL, message, B_WILL_DRAW | B_NAVIGABLE),
	fDrawArrows(drawArrows),
	fDoubleArrows(doubleArrows)
{
	SetExplicitMinSize(BSize(160, 20));
	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 20));
}
 
 
FakeScrollBar::~FakeScrollBar(void)
{
}
 
 
void
FakeScrollBar::Draw(BRect updateRect)
{
	BRect bounds = Bounds();
 
	rgb_color normal = ui_color(B_PANEL_BACKGROUND_COLOR);
 
	if (IsFocus()) {
		// draw the focus indicator
		SetHighColor(ui_color(B_NAVIGATION_BASE_COLOR));
		StrokeRect(bounds);
		bounds.InsetBy(1.0, 1.0);
 
		// Draw the selected border (1px)
		if (Value() == B_CONTROL_ON)
			SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
		else
			SetHighColor(normal);
 
		StrokeRect(bounds);
		bounds.InsetBy(1.0, 1.0);
	} else {
		// Draw the selected border (2px)
		if (Value() == B_CONTROL_ON)
			SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
		else
			SetHighColor(normal);
 
		StrokeRect(bounds);
		bounds.InsetBy(1.0, 1.0);
		StrokeRect(bounds);
		bounds.InsetBy(1.0, 1.0);
	}
 
	// draw a gap (1px)
	SetHighColor(normal);
	StrokeRect(bounds);
	bounds.InsetBy(1.0, 1.0);
 
	// draw a border around control (1px)
	SetHighColor(tint_color(normal, B_DARKEN_1_TINT));
	StrokeRect(bounds);
	bounds.InsetBy(1.0, 1.0);
 
	BRect thumbBG = bounds;
	BRect bgRect = bounds;
 
	if (fDrawArrows) {
		// draw arrows
		SetDrawingMode(B_OP_OVER);
 
		BRect buttonFrame(bounds.left, bounds.top,
			bounds.left + bounds.Height(), bounds.bottom);
 
		_DrawArrowButton(ARROW_LEFT, buttonFrame, updateRect);
 
		if (fDoubleArrows) {
			buttonFrame.OffsetBy(bounds.Height() + 1, 0.0);
			_DrawArrowButton(ARROW_RIGHT, buttonFrame,
				updateRect);
 
			buttonFrame.OffsetTo(bounds.right - ((bounds.Height() * 2) + 1),
				bounds.top);
			_DrawArrowButton(ARROW_LEFT, buttonFrame,
				updateRect);
 
			thumbBG.left += bounds.Height() * 2 + 2;
			thumbBG.right -= bounds.Height() * 2 + 2;
		} else {
			thumbBG.left += bounds.Height() + 1;
			thumbBG.right -= bounds.Height() + 1;
		}
 
		buttonFrame.OffsetTo(bounds.right - bounds.Height(), bounds.top);
		_DrawArrowButton(ARROW_RIGHT, buttonFrame, updateRect);
 
		SetDrawingMode(B_OP_COPY);
 
		bgRect = bounds.InsetByCopy(48, 0);
	} else
		bgRect = bounds.InsetByCopy(16, 0);
 
	// fill background besides the thumb
	BRect leftOfThumb(thumbBG.left, thumbBG.top, bgRect.left - 1,
		thumbBG.bottom);
	BRect rightOfThumb(bgRect.right + 1, thumbBG.top, thumbBG.right,
		thumbBG.bottom);
 
	be_control_look->DrawScrollBarBackground(this, leftOfThumb,
		rightOfThumb, updateRect, normal, 0, B_HORIZONTAL);
 
	// Draw scroll thumb
 
	// fill the clickable surface of the thumb
	be_control_look->DrawButtonBackground(this, bgRect, updateRect,
		normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
}
 
 
void
FakeScrollBar::MouseDown(BPoint point)
{
	BControl::MouseDown(point);
}
 
 
void
FakeScrollBar::MouseMoved(BPoint point, uint32 transit,
	const BMessage* message)
{
	BControl::MouseMoved(point, transit, message);
}
 
 
void
FakeScrollBar::MouseUp(BPoint point)
{
	SetValue(B_CONTROL_ON);
	Invoke();
 
	Invalidate();
 
	BControl::MouseUp(point);
}
 
 
void
FakeScrollBar::SetValue(int32 value)
{
	if (value != Value()) {
		BControl::SetValueNoUpdate(value);
		Invalidate();
	}
 
	if (!value)
		return;
 
	BView* parent = Parent();
	BView* child = NULL;
 
	if (parent != NULL) {
		// If the parent is a BBox, the group parent is the parent of the BBox
		BBox* box = dynamic_cast<BBox*>(parent);
 
		if (box && box->LabelView() == this)
			parent = box->Parent();
 
		if (parent != NULL) {
			BBox* box = dynamic_cast<BBox*>(parent);
 
			// If the parent is a BBox, skip the label if there is one
			if (box && box->LabelView())
				child = parent->ChildAt(1);
			else
				child = parent->ChildAt(0);
		} else
			child = Window()->ChildAt(0);
	} else if (Window())
		child = Window()->ChildAt(0);
 
	while (child) {
		FakeScrollBar* scrollbar = dynamic_cast<FakeScrollBar*>(child);
 
		if (scrollbar != NULL && (scrollbar != this))
			scrollbar->SetValue(B_CONTROL_OFF);
		else {
			// If the child is a BBox, check if the label is a scrollbarbutton
			BBox* box = dynamic_cast<BBox*>(child);
 
			if (box && box->LabelView()) {
				scrollbar = dynamic_cast<FakeScrollBar*>(box->LabelView());
 
				if (scrollbar != NULL && (scrollbar != this))
					scrollbar->SetValue(B_CONTROL_OFF);
			}
		}
 
		child = child->NextSibling();
	}
 
	//ASSERT(Value() == B_CONTROL_ON);
}
 
 
//	#pragma mark -
 
 
void
FakeScrollBar::SetDoubleArrows(bool doubleArrows)
{
	fDoubleArrows = doubleArrows;
	Invalidate();
}
 
 
void
FakeScrollBar::SetKnobStyle(uint32 knobStyle)
{
	fKnobStyle = knobStyle;
	Invalidate();
}
 
 
void
FakeScrollBar::SetFromScrollBarInfo(const scroll_bar_info &info)
{
	fDoubleArrows = info.double_arrows;
	fKnobStyle = info.knob;
	Invalidate();
}
 
 
//	#pragma mark -
 
 
void
FakeScrollBar::_DrawArrowButton(int32 direction, BRect rect,
	const BRect& updateRect)
{
	if (!updateRect.Intersects(rect))
		return;
 
	uint32 flags = 0;
 
	rgb_color baseColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
		B_LIGHTEN_1_TINT);
 
	be_control_look->DrawButtonBackground(this, rect, updateRect, baseColor,
		flags, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
 
	rect.InsetBy(-1, -1);
	be_control_look->DrawArrowShape(this, rect, updateRect,
		baseColor, direction, flags, B_DARKEN_MAX_TINT);
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fKnobStyle.