xref: /haiku/src/preferences/appearance/FakeScrollBar.cpp (revision 11c9f9a1d649c006f9066ae9436372ab75728c4b)
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 
22 typedef enum {
23 	ARROW_LEFT = 0,
24 	ARROW_RIGHT,
25 	ARROW_UP,
26 	ARROW_DOWN,
27 	ARROW_NONE
28 } arrow_direction;
29 
30 
31 FakeScrollBar::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 
43 FakeScrollBar::~FakeScrollBar(void)
44 {
45 }
46 
47 
48 void
49 FakeScrollBar::Draw(BRect updateRect)
50 {
51 	BRect bounds = Bounds();
52 
53 	rgb_color normal = ui_color(B_PANEL_BACKGROUND_COLOR);
54 
55 	if (IsFocus()) {
56 		// draw the focus indicator
57 		SetHighColor(ui_color(B_NAVIGATION_BASE_COLOR));
58 		StrokeRect(bounds);
59 		bounds.InsetBy(1.0, 1.0);
60 
61 		// Draw the selected border (1px)
62 		if (Value() == B_CONTROL_ON)
63 			SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
64 		else
65 			SetHighColor(normal);
66 
67 		StrokeRect(bounds);
68 		bounds.InsetBy(1.0, 1.0);
69 	} else {
70 		// Draw the selected border (2px)
71 		if (Value() == B_CONTROL_ON)
72 			SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
73 		else
74 			SetHighColor(normal);
75 
76 		StrokeRect(bounds);
77 		bounds.InsetBy(1.0, 1.0);
78 		StrokeRect(bounds);
79 		bounds.InsetBy(1.0, 1.0);
80 	}
81 
82 	// draw a gap (1px)
83 	SetHighColor(normal);
84 	StrokeRect(bounds);
85 	bounds.InsetBy(1.0, 1.0);
86 
87 	// draw a border around control (1px)
88 	SetHighColor(tint_color(normal, B_DARKEN_1_TINT));
89 	StrokeRect(bounds);
90 	bounds.InsetBy(1.0, 1.0);
91 
92 	BRect thumbBG = bounds;
93 	BRect bgRect = bounds;
94 
95 	if (fDrawArrows) {
96 		// draw arrows
97 		SetDrawingMode(B_OP_OVER);
98 
99 		BRect buttonFrame(bounds.left, bounds.top,
100 			bounds.left + bounds.Height(), bounds.bottom);
101 
102 		_DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame, updateRect);
103 
104 		if (fDoubleArrows) {
105 			buttonFrame.OffsetBy(bounds.Height() + 1, 0.0);
106 			_DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame,
107 				updateRect);
108 
109 			buttonFrame.OffsetTo(bounds.right - ((bounds.Height() * 2) + 1),
110 				bounds.top);
111 			_DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame,
112 				updateRect);
113 
114 			thumbBG.left += bounds.Height() * 2 + 2;
115 			thumbBG.right -= bounds.Height() * 2 + 2;
116 		} else {
117 			thumbBG.left += bounds.Height() + 1;
118 			thumbBG.right -= bounds.Height() + 1;
119 		}
120 
121 		buttonFrame.OffsetTo(bounds.right - bounds.Height(), bounds.top);
122 		_DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame, updateRect);
123 
124 		SetDrawingMode(B_OP_COPY);
125 
126 		bgRect = bounds.InsetByCopy(48, 0);
127 	} else
128 		bgRect = bounds.InsetByCopy(16, 0);
129 
130 	// fill background besides the thumb
131 	BRect leftOfThumb(thumbBG.left, thumbBG.top, bgRect.left - 1,
132 		thumbBG.bottom);
133 	BRect rightOfThumb(bgRect.right + 1, thumbBG.top, thumbBG.right,
134 		thumbBG.bottom);
135 
136 	be_control_look->DrawScrollBarBackground(this, leftOfThumb,
137 		rightOfThumb, updateRect, normal, 0, B_HORIZONTAL);
138 
139 	// Draw scroll thumb
140 
141 	// fill the clickable surface of the thumb
142 	be_control_look->DrawButtonBackground(this, bgRect, updateRect,
143 		normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
144 }
145 
146 
147 void
148 FakeScrollBar::MouseDown(BPoint point)
149 {
150 	BControl::MouseDown(point);
151 }
152 
153 
154 void
155 FakeScrollBar::MouseMoved(BPoint point, uint32 transit,
156 	const BMessage* message)
157 {
158 	BControl::MouseMoved(point, transit, message);
159 }
160 
161 
162 void
163 FakeScrollBar::MouseUp(BPoint point)
164 {
165 	SetValue(B_CONTROL_ON);
166 	Invoke();
167 
168 	Invalidate();
169 
170 	BControl::MouseUp(point);
171 }
172 
173 
174 void
175 FakeScrollBar::SetValue(int32 value)
176 {
177 	if (value != Value()) {
178 		BControl::SetValueNoUpdate(value);
179 		Invalidate();
180 	}
181 
182 	if (!value)
183 		return;
184 
185 	BView* parent = Parent();
186 	BView* child = NULL;
187 
188 	if (parent != NULL) {
189 		// If the parent is a BBox, the group parent is the parent of the BBox
190 		BBox* box = dynamic_cast<BBox*>(parent);
191 
192 		if (box && box->LabelView() == this)
193 			parent = box->Parent();
194 
195 		if (parent != NULL) {
196 			BBox* box = dynamic_cast<BBox*>(parent);
197 
198 			// If the parent is a BBox, skip the label if there is one
199 			if (box && box->LabelView())
200 				child = parent->ChildAt(1);
201 			else
202 				child = parent->ChildAt(0);
203 		} else
204 			child = Window()->ChildAt(0);
205 	} else if (Window())
206 		child = Window()->ChildAt(0);
207 
208 	while (child) {
209 		FakeScrollBar* scrollbar = dynamic_cast<FakeScrollBar*>(child);
210 
211 		if (scrollbar != NULL && (scrollbar != this))
212 			scrollbar->SetValue(B_CONTROL_OFF);
213 		else {
214 			// If the child is a BBox, check if the label is a scrollbarbutton
215 			BBox* box = dynamic_cast<BBox*>(child);
216 
217 			if (box && box->LabelView()) {
218 				scrollbar = dynamic_cast<FakeScrollBar*>(box->LabelView());
219 
220 				if (scrollbar != NULL && (scrollbar != this))
221 					scrollbar->SetValue(B_CONTROL_OFF);
222 			}
223 		}
224 
225 		child = child->NextSibling();
226 	}
227 
228 	//ASSERT(Value() == B_CONTROL_ON);
229 }
230 
231 
232 //	#pragma mark -
233 
234 
235 void
236 FakeScrollBar::SetDoubleArrows(bool doubleArrows)
237 {
238 	fDoubleArrows = doubleArrows;
239 	Invalidate();
240 }
241 
242 
243 void
244 FakeScrollBar::SetKnobStyle(uint32 knobStyle)
245 {
246 	fKnobStyle = knobStyle;
247 	Invalidate();
248 }
249 
250 
251 void
252 FakeScrollBar::SetFromScrollBarInfo(const scroll_bar_info &info)
253 {
254 	fDoubleArrows = info.double_arrows;
255 	fKnobStyle = info.knob;
256 	Invalidate();
257 }
258 
259 
260 //	#pragma mark -
261 
262 
263 void
264 FakeScrollBar::_DrawArrowButton(int32 direction, bool doubleArrows, BRect r,
265 	const BRect& updateRect)
266 {
267 	if (!updateRect.Intersects(r))
268 		return;
269 
270 	rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR);
271 	rgb_color light = tint_color(c, B_LIGHTEN_MAX_TINT);
272 	rgb_color dark = tint_color(c, B_DARKEN_1_TINT);
273 	rgb_color darker = tint_color(c, B_DARKEN_2_TINT);
274 	rgb_color normal = c;
275 	rgb_color arrow = tint_color(c,
276 		(B_DARKEN_MAX_TINT + B_DARKEN_4_TINT) / 2.0);
277 
278 	BPoint tri1, tri2, tri3;
279 	float hInset = r.Width() / 3;
280 	float vInset = r.Height() / 3;
281 	r.InsetBy(hInset, vInset);
282 
283 	switch (direction) {
284 		case ARROW_LEFT:
285 			tri1.Set(r.right, r.top);
286 			tri2.Set(r.right - r.Width() / 1.33, (r.top + r.bottom + 1) / 2);
287 			tri3.Set(r.right, r.bottom + 1);
288 			break;
289 
290 		case ARROW_RIGHT:
291 			tri1.Set(r.left, r.bottom + 1);
292 			tri2.Set(r.left + r.Width() / 1.33, (r.top + r.bottom + 1) / 2);
293 			tri3.Set(r.left, r.top);
294 			break;
295 
296 		case ARROW_UP:
297 			tri1.Set(r.left, r.bottom);
298 			tri2.Set((r.left + r.right + 1) / 2, r.bottom - r.Height() / 1.33);
299 			tri3.Set(r.right + 1, r.bottom);
300 			break;
301 
302 		default:
303 			tri1.Set(r.left, r.top);
304 			tri2.Set((r.left + r.right + 1) / 2, r.top + r.Height() / 1.33);
305 			tri3.Set(r.right + 1, r.top);
306 			break;
307 	}
308 
309 	r.InsetBy(-(hInset - 1), -(vInset - 1));
310 	BRect temp(r.InsetByCopy(-1, -1));
311 	be_control_look->DrawButtonBackground(this, temp, updateRect,
312 		normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
313 
314 	BShape arrowShape;
315 	arrowShape.MoveTo(tri1);
316 	arrowShape.LineTo(tri2);
317 	arrowShape.LineTo(tri3);
318 
319 	SetHighColor(arrow);
320 	SetPenSize(ceilf(hInset / 2.0));
321 	StrokeShape(&arrowShape);
322 	SetPenSize(1.0);
323 }
324