1/*
2 *  Copyright 2010-2012 Haiku, Inc. All rights reserved.
3 *  Distributed under the terms of the MIT license.
4 *
5 *	Authors:
6 *		DarkWyrm <bpmagic@columbus.rr.com>
7 *		John Scipione <jscipione@gmail.com>
8 */
9
10
11#include "FakeScrollBar.h"
12
13#include <Box.h>
14#include <ControlLook.h>
15#include <Message.h>
16#include <ScrollBar.h>
17#include <Shape.h>
18#include <Size.h>
19#include <Window.h>
20
21
22typedef enum {
23	ARROW_LEFT = 0,
24	ARROW_RIGHT,
25	ARROW_UP,
26	ARROW_DOWN,
27	ARROW_NONE
28} arrow_direction;
29
30
31FakeScrollBar::FakeScrollBar(bool drawArrows, bool doubleArrows,
32	BMessage* message)
33	:
34	BControl("FakeScrollBar", NULL, message, B_WILL_DRAW | B_NAVIGABLE),
35	fDrawArrows(drawArrows),
36	fDoubleArrows(doubleArrows)
37{
38	SetExplicitMinSize(BSize(160, 20));
39	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 20));
40}
41
42
43FakeScrollBar::~FakeScrollBar(void)
44{
45}
46
47
48void
49FakeScrollBar::Draw(BRect updateRect)
50{
51	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
52
53	uint32 flags = BControlLook::B_PARTIALLY_ACTIVATED;
54
55	if (Value() == B_CONTROL_ON)
56		SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
57	else
58		SetHighColor(base);
59
60	BRect rect(Bounds());
61
62	// draw the selected border (2px)
63	StrokeRect(rect);
64	rect.InsetBy(1, 1);
65	StrokeRect(rect);
66	rect.InsetBy(1, 1);
67
68	// draw a 1px gap
69	SetHighColor(base);
70	StrokeRect(rect);
71	rect.InsetBy(1, 1);
72
73	// draw a 1px border around the entire scroll bar
74	be_control_look->DrawScrollBarBorder(this, rect, updateRect, base, flags,
75		B_HORIZONTAL);
76
77	// inset past border
78	rect.InsetBy(1, 1);
79
80	// draw arrow buttons
81	if (fDrawArrows) {
82		BRect buttonFrame(rect.left, rect.top, rect.left + rect.Height(),
83			rect.bottom);
84		be_control_look->DrawScrollBarButton(this, buttonFrame, updateRect,
85			base, flags, BControlLook::B_LEFT_ARROW, B_HORIZONTAL);
86		if (fDoubleArrows) {
87			buttonFrame.OffsetBy(rect.Height() + 1, 0.0f);
88			be_control_look->DrawScrollBarButton(this, buttonFrame,
89				updateRect, base, flags, BControlLook::B_RIGHT_ARROW,
90				B_HORIZONTAL);
91			buttonFrame.OffsetTo(rect.right - ((rect.Height() * 2) + 1),
92				rect.top);
93			be_control_look->DrawScrollBarButton(this, buttonFrame,
94				updateRect, base, flags, BControlLook::B_LEFT_ARROW,
95				B_HORIZONTAL);
96		}
97		buttonFrame.OffsetTo(rect.right - rect.Height(), rect.top);
98		be_control_look->DrawScrollBarButton(this, buttonFrame, updateRect,
99			base, flags, BControlLook::B_RIGHT_ARROW, B_HORIZONTAL);
100	}
101
102	// inset rect to make room for arrows
103	if (fDrawArrows) {
104		if (fDoubleArrows)
105			rect.InsetBy((rect.Height() + 1) * 2, 0.0f);
106		else
107			rect.InsetBy(rect.Height() + 1, 0.0f);
108	}
109
110	// draw background and thumb
111	float less = floorf(rect.Width() / 3);
112	BRect thumbRect(rect.left + less, rect.top, rect.right - less,
113		rect.bottom);
114	BRect leftOfThumb(rect.left, thumbRect.top, thumbRect.left - 1,
115		thumbRect.bottom);
116	BRect rightOfThumb(thumbRect.right + 1, thumbRect.top, rect.right,
117		thumbRect.bottom);
118
119	be_control_look->DrawScrollBarBackground(this, leftOfThumb,
120		rightOfThumb, updateRect, base, flags, B_HORIZONTAL);
121	be_control_look->DrawScrollBarThumb(this, thumbRect, updateRect,
122		ui_color(B_SCROLL_BAR_THUMB_COLOR), flags, B_HORIZONTAL, fKnobStyle);
123}
124
125
126void
127FakeScrollBar::MouseDown(BPoint point)
128{
129	BControl::MouseDown(point);
130}
131
132
133void
134FakeScrollBar::MouseMoved(BPoint point, uint32 transit,
135	const BMessage* message)
136{
137	BControl::MouseMoved(point, transit, message);
138}
139
140
141void
142FakeScrollBar::MouseUp(BPoint point)
143{
144	SetValue(B_CONTROL_ON);
145	Invoke();
146
147	Invalidate();
148
149	BControl::MouseUp(point);
150}
151
152
153void
154FakeScrollBar::SetValue(int32 value)
155{
156	if (value != Value()) {
157		BControl::SetValueNoUpdate(value);
158		Invalidate();
159	}
160
161	if (!value)
162		return;
163
164	BView* parent = Parent();
165	BView* child = NULL;
166
167	if (parent != NULL) {
168		// If the parent is a BBox, the group parent is the parent of the BBox
169		BBox* box = dynamic_cast<BBox*>(parent);
170
171		if (box && box->LabelView() == this)
172			parent = box->Parent();
173
174		if (parent != NULL) {
175			BBox* box = dynamic_cast<BBox*>(parent);
176
177			// If the parent is a BBox, skip the label if there is one
178			if (box && box->LabelView())
179				child = parent->ChildAt(1);
180			else
181				child = parent->ChildAt(0);
182		} else
183			child = Window()->ChildAt(0);
184	} else if (Window())
185		child = Window()->ChildAt(0);
186
187	while (child) {
188		FakeScrollBar* scrollbar = dynamic_cast<FakeScrollBar*>(child);
189
190		if (scrollbar != NULL && (scrollbar != this))
191			scrollbar->SetValue(B_CONTROL_OFF);
192		else {
193			// If the child is a BBox, check if the label is a scrollbarbutton
194			BBox* box = dynamic_cast<BBox*>(child);
195
196			if (box && box->LabelView()) {
197				scrollbar = dynamic_cast<FakeScrollBar*>(box->LabelView());
198
199				if (scrollbar != NULL && (scrollbar != this))
200					scrollbar->SetValue(B_CONTROL_OFF);
201			}
202		}
203
204		child = child->NextSibling();
205	}
206
207	//ASSERT(Value() == B_CONTROL_ON);
208}
209
210
211//	#pragma mark -
212
213
214void
215FakeScrollBar::SetDoubleArrows(bool doubleArrows)
216{
217	fDoubleArrows = doubleArrows;
218	Invalidate();
219}
220
221
222void
223FakeScrollBar::SetKnobStyle(uint32 knobStyle)
224{
225	fKnobStyle = knobStyle;
226	Invalidate();
227}
228
229
230void
231FakeScrollBar::SetFromScrollBarInfo(const scroll_bar_info &info)
232{
233	fDoubleArrows = info.double_arrows;
234	fKnobStyle = info.knob;
235	Invalidate();
236}
237
238
239//	#pragma mark -
240
241
242void
243FakeScrollBar::_DrawArrowButton(int32 direction, BRect rect,
244	const BRect& updateRect)
245{
246	if (!updateRect.Intersects(rect))
247		return;
248
249	uint32 flags = 0;
250
251	rgb_color baseColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
252		B_LIGHTEN_1_TINT);
253
254	be_control_look->DrawButtonBackground(this, rect, updateRect, baseColor,
255		flags, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
256
257	rect.InsetBy(-1, -1);
258	be_control_look->DrawArrowShape(this, rect, updateRect,
259		baseColor, direction, flags, B_DARKEN_MAX_TINT);
260}
261