xref: /haiku/src/apps/soundrecorder/TrackSlider.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2005, Jérôme Duval. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Inspired by SoundCapture from Be newsletter (Media Kit Basics: Consumers
6  * and Producers)
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <Screen.h>
12 
13 #include "TrackSlider.h"
14 #include "icon_button.h"
15 
16 TrackSlider::TrackSlider(BRect rect, const char *title, BMessage *msg,
17 	uint32 resizeFlags)
18 	:
19 	BControl(rect, "slider", NULL, msg, resizeFlags, B_WILL_DRAW
20 		| B_FRAME_EVENTS),
21 	fLeftTime(0),
22 	fRightTime(1000000),
23 	fMainTime(0),
24 	fTotalTime(1000000),
25 	fLeftTracking(false),
26 	fRightTracking(false),
27 	fMainTracking(false),
28 	fBitmap(NULL),
29 	fBitmapView(NULL)
30 {
31 	fFont.SetSize(8.0);
32 	fFont.SetFlags(B_DISABLE_ANTIALIASING);
33 
34 	int32 numFamilies = count_font_families();
35 	for (int32 i = 0; i < numFamilies; i++ ) {
36 		font_family family;
37 		uint32 flags;
38 		if ((get_font_family(i, &family, &flags) == B_OK)
39 			&& (strcmp(family, "Baskerville") == 0)) {
40 			fFont.SetFamilyAndFace(family, B_REGULAR_FACE);
41 			break;
42 		}
43 	}
44 
45 }
46 
47 
48 TrackSlider::~TrackSlider()
49 {
50 	delete fBitmap;
51 }
52 
53 
54 void
55 TrackSlider::AttachedToWindow()
56 {
57 	BControl::AttachedToWindow();
58 	SetViewColor(B_TRANSPARENT_COLOR);
59 	_InitBitmap();
60 	_RenderBitmap();
61 }
62 
63 
64 void
65 TrackSlider::_InitBitmap()
66 {
67 	if (fBitmap != NULL) {
68 		if (fBitmapView != NULL) {
69 			fBitmap->RemoveChild(fBitmapView);
70 			delete fBitmapView;
71 		}
72 		delete fBitmap;
73 	}
74 
75 	BRect rect = Bounds();
76 
77 	fBitmap = new BBitmap(rect, BScreen().ColorSpace(), true);
78 
79 	fBitmapView = new SliderOffscreenView(rect.OffsetToSelf(B_ORIGIN), "bitmapView");
80 	fBitmap->AddChild(fBitmapView);
81 
82 	fBitmapView->fRight = Bounds().right - kLeftRightTrackSliderWidth;
83 	if (fTotalTime == 0) {
84 		fBitmapView->fLeftX = 14;
85 		fBitmapView->fRightX = fBitmapView->fRight;
86 		fBitmapView->fPositionX = 15;
87 	} else {
88 		fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
89 			* ((double)fLeftTime / fTotalTime);
90 		fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
91 			* ((double)fRightTime / fTotalTime);
92 		fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
93 			* ((double)fMainTime / fTotalTime);
94 	}
95 }
96 
97 #define SLIDER_BASE 10
98 
99 void
100 TrackSlider::_RenderBitmap()
101 {
102 	/* rendering */
103 	if (fBitmap->Lock()) {
104 		fBitmapView->DrawX();
105 		fBitmap->Unlock();
106 	}
107 }
108 
109 
110 void
111 TrackSlider::Draw(BRect updateRect)
112 {
113 	DrawBitmapAsync(fBitmap, BPoint(0,0));
114 
115 	_DrawCounter(fMainTime, fBitmapView->fPositionX, fMainTracking);
116 	if (fLeftTracking)
117 		_DrawCounter(fLeftTime, fBitmapView->fLeftX, fLeftTracking);
118 	else if (fRightTracking)
119 		_DrawCounter(fRightTime, fBitmapView->fRightX, fRightTracking);
120 
121 	_DrawMarker(fBitmapView->fPositionX);
122 
123 	Sync();
124 }
125 
126 
127 void
128 TrackSlider::_DrawCounter(bigtime_t timestamp, float position, bool isTracking)
129 {
130 	// timecounter
131 
132 	rgb_color gray = {128,128,128};
133 	rgb_color blue = {0,0,140};
134 	rgb_color blue2 = {146,146,214};
135 	rgb_color white = {255,255,255};
136 
137 	char string[12];
138 	_TimeToString(timestamp, string);
139 	int32 halfwidth = ((int32)fFont.StringWidth(string)) / 2;
140 
141 	float counterX = position;
142 	if (counterX < 39)
143 		counterX = 39;
144 	if (counterX > fBitmapView->fRight - 23)
145 		counterX = fBitmapView->fRight - 23;
146 
147 	BeginLineArray(4);
148 	if (!isTracking) {
149 		AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE+1),
150 			BPoint(counterX+halfwidth+3,SLIDER_BASE+1), gray);
151 		AddLine(BPoint(counterX+halfwidth+4,SLIDER_BASE+1),
152 			BPoint(counterX+halfwidth+4,SLIDER_BASE-8), gray);
153 		AddLine(BPoint(counterX-halfwidth-4,SLIDER_BASE+1),
154 			BPoint(counterX-halfwidth-4,SLIDER_BASE-9), white);
155 		AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE-9),
156 			BPoint(counterX+halfwidth+4,SLIDER_BASE-9), white);
157 		SetHighColor(216,216,216);
158 	} else {
159 		AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE+1),
160 			BPoint(counterX+halfwidth+3,SLIDER_BASE+1), blue);
161 		AddLine(BPoint(counterX+halfwidth+4,SLIDER_BASE+1),
162 			BPoint(counterX+halfwidth+4,SLIDER_BASE-9), blue2);
163 		AddLine(BPoint(counterX-halfwidth-4,SLIDER_BASE+1),
164 			BPoint(counterX-halfwidth-4,SLIDER_BASE-9), blue2);
165 		AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE-9),
166 			BPoint(counterX+halfwidth+3,SLIDER_BASE-9), blue2);
167 		SetHighColor(48,48,241);
168 	}
169 	EndLineArray();
170 	FillRect(BRect(counterX-halfwidth-3,SLIDER_BASE-8,counterX+halfwidth+3,
171 		SLIDER_BASE));
172 
173 #ifdef __HAIKU__
174 	SetDrawingMode(B_OP_OVER);
175 #else
176 	SetDrawingMode(B_OP_COPY);
177 #endif
178 	if (isTracking)
179 		SetHighColor(255,255,255);
180 	else
181 		SetHighColor(0,0,0);
182 	SetLowColor(ViewColor());
183 
184 	SetFont(&fFont);
185 	DrawString(string, BPoint(counterX-halfwidth, SLIDER_BASE-1));
186 
187 }
188 
189 
190 void
191 TrackSlider::_DrawMarker(float position)
192 {
193 	rgb_color black = {0,0,0};
194 	rgb_color rose = {255,152,152};
195 	rgb_color red = {255,0,0};
196 	rgb_color bordeau = {178,0,0};
197 	rgb_color white = {255,255,255};
198 
199 	BeginLineArray(30);
200 	AddLine(BPoint(position,SLIDER_BASE+7), BPoint(position-4,SLIDER_BASE+3),
201 		black);
202 	AddLine(BPoint(position-4,SLIDER_BASE+3), BPoint(position-4,SLIDER_BASE+1),
203 		black);
204 	AddLine(BPoint(position-4,SLIDER_BASE+1), BPoint(position+4,SLIDER_BASE+1),
205 		black);
206 	AddLine(BPoint(position+4,SLIDER_BASE+1), BPoint(position+4,SLIDER_BASE+3),
207 		black);
208 	AddLine(BPoint(position+4,SLIDER_BASE+3), BPoint(position,SLIDER_BASE+7),
209 		black);
210 
211 
212 	AddLine(BPoint(position-3,SLIDER_BASE+2), BPoint(position+3,SLIDER_BASE+2),
213 		rose);
214 	AddLine(BPoint(position-3,SLIDER_BASE+3), BPoint(position-1,SLIDER_BASE+5),
215 		rose);
216 
217 	AddLine(BPoint(position-2,SLIDER_BASE+3), BPoint(position+2,SLIDER_BASE+3),
218 		red);
219 	AddLine(BPoint(position-1,SLIDER_BASE+4), BPoint(position+1,SLIDER_BASE+4),
220 		red);
221 	AddLine(BPoint(position,SLIDER_BASE+5), BPoint(position,SLIDER_BASE+5),
222 		red);
223 
224 	AddLine(BPoint(position,SLIDER_BASE+6), BPoint(position+3,SLIDER_BASE+3),
225 		bordeau);
226 
227 	AddLine(BPoint(position,SLIDER_BASE+12), BPoint(position-4,SLIDER_BASE+16),
228 		black);
229 	AddLine(BPoint(position-4,SLIDER_BASE+16), BPoint(position-4,
230 		SLIDER_BASE+17), black);
231 	AddLine(BPoint(position-4,SLIDER_BASE+17), BPoint(position+4,
232 		SLIDER_BASE+17), black);
233 	AddLine(BPoint(position+4,SLIDER_BASE+17), BPoint(position+4,
234 		SLIDER_BASE+16), black);
235 	AddLine(BPoint(position+4,SLIDER_BASE+16), BPoint(position,SLIDER_BASE+12),
236 		black);
237 	AddLine(BPoint(position-4,SLIDER_BASE+18), BPoint(position+4,
238 		SLIDER_BASE+18), white);
239 
240 	AddLine(BPoint(position-3,SLIDER_BASE+16), BPoint(position,SLIDER_BASE+13),
241 		rose);
242 
243 	AddLine(BPoint(position-2,SLIDER_BASE+16), BPoint(position+2,
244 		SLIDER_BASE+16), red);
245 	AddLine(BPoint(position-1,SLIDER_BASE+15), BPoint(position+1,
246 		SLIDER_BASE+15), red);
247 	AddLine(BPoint(position,SLIDER_BASE+14), BPoint(position,
248 		SLIDER_BASE+14), red);
249 
250 	AddLine(BPoint(position+1,SLIDER_BASE+14), BPoint(position+3,
251 		SLIDER_BASE+16), bordeau);
252 
253 	EndLineArray();
254 }
255 
256 
257 void
258 TrackSlider::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
259 {
260 	if (!IsTracking())
261 		return;
262 
263 	uint32 mouseButtons;
264 	BPoint where;
265 	GetMouse(&where, &mouseButtons, true);
266 
267 	// button not pressed, exit
268 	if (! (mouseButtons & B_PRIMARY_MOUSE_BUTTON)) {
269 		Invoke();
270 		SetTracking(false);
271 	}
272 
273 	_UpdatePosition(point);
274 }
275 
276 
277 void
278 TrackSlider::MouseDown(BPoint point)
279 {
280 	if (!Bounds().InsetBySelf(2,2).Contains(point))
281 		return;
282 
283 	_UpdatePosition(point);
284 	SetTracking(true);
285 	SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY
286 		| B_LOCK_WINDOW_FOCUS);
287 }
288 
289 
290 void
291 TrackSlider::MouseUp(BPoint point)
292 {
293 	if (!IsTracking())
294 		return;
295 	if (Bounds().InsetBySelf(2,2).Contains(point)) {
296 		_UpdatePosition(point);
297 	}
298 
299 	fLeftTracking = fRightTracking = fMainTracking = false;
300 
301 	Invoke();
302 	SetTracking(false);
303 	Draw(Bounds());
304 	Flush();
305 }
306 
307 
308 void
309 TrackSlider::_UpdatePosition(BPoint point)
310 {
311 	BRect leftRect(fBitmapView->fLeftX-9, SLIDER_BASE+3, fBitmapView->fLeftX,
312 		SLIDER_BASE+16);
313 	BRect rightRect(fBitmapView->fRightX, SLIDER_BASE+3,
314 		fBitmapView->fRightX+9, SLIDER_BASE+16);
315 
316 	if (!(fRightTracking || fMainTracking) && (fLeftTracking
317 		|| ((point.x < fBitmapView->fPositionX-4) && leftRect.Contains(point)))) {
318 		if (!IsTracking())
319 			fBitmapView->fLastX = point.x - fBitmapView->fLeftX;
320 		fBitmapView->fLeftX = MIN(MAX(point.x - fBitmapView->fLastX, 15),
321 			fBitmapView->fRight);
322 		fLeftTime = (bigtime_t)(MAX(MIN((fBitmapView->fLeftX - 15)
323 			/ (fBitmapView->fRight - 14),1), 0) * fTotalTime);
324 		fLeftTracking = true;
325 
326 		BMessage msg = *Message();
327 		msg.AddInt64("left", fLeftTime);
328 
329 		if (fBitmapView->fPositionX < fBitmapView->fLeftX) {
330 			fBitmapView->fPositionX = fBitmapView->fLeftX + 1;
331 			fMainTime = fLeftTime;
332 			msg.AddInt64("main", fMainTime);
333 			if (fBitmapView->fRightX < fBitmapView->fPositionX) {
334 				fBitmapView->fRightX = fBitmapView->fPositionX;
335 				fRightTime = fMainTime;
336 				msg.AddInt64("right", fRightTime);
337 			}
338 		}
339 
340 		Invoke(&msg);
341 		_RenderBitmap();
342 
343 		//printf("fLeftPos : %lld\n", fLeftTime);
344 	} else if (!fMainTracking && (fRightTracking
345 		|| ((point.x > fBitmapView->fPositionX+4)
346 		&& rightRect.Contains(point)))) {
347 		if (!IsTracking())
348 			fBitmapView->fLastX = point.x - fBitmapView->fRightX;
349 		fBitmapView->fRightX = MIN(MAX(point.x - fBitmapView->fLastX, 15),
350 			fBitmapView->fRight);
351 		fRightTime = (bigtime_t)(MAX(MIN((fBitmapView->fRightX - 15)
352 			/ (fBitmapView->fRight - 14),1), 0) * fTotalTime);
353 		fRightTracking = true;
354 
355 		BMessage msg = *Message();
356 		msg.AddInt64("right", fRightTime);
357 
358 		if (fBitmapView->fPositionX > fBitmapView->fRightX) {
359 			fBitmapView->fPositionX = fBitmapView->fRightX;
360 			fMainTime = fRightTime;
361 			msg.AddInt64("main", fMainTime);
362 			if (fBitmapView->fLeftX > fBitmapView->fPositionX) {
363 				fBitmapView->fLeftX = fBitmapView->fPositionX - 1;
364 				fLeftTime = fMainTime;
365 				msg.AddInt64("left", fLeftTime);
366 			}
367 		}
368 
369 		Invoke(&msg);
370 		_RenderBitmap();
371 
372 		//printf("fRightPos : %lld\n", fRightTime);
373 	} else {
374 		fBitmapView->fPositionX = MIN(MAX(point.x, 15), fBitmapView->fRight);
375 		fMainTime = (bigtime_t)(MAX(MIN((fBitmapView->fPositionX - 15)
376 			/ (fBitmapView->fRight - 14),1), 0) * fTotalTime);
377 		fMainTracking = true;
378 
379 		BMessage msg = *Message();
380 		msg.AddInt64("main", fMainTime);
381 
382 		if (fBitmapView->fRightX < fBitmapView->fPositionX) {
383 			fBitmapView->fRightX = fBitmapView->fPositionX;
384 			fRightTime = fMainTime;
385 			msg.AddInt64("right", fRightTime);
386 			_RenderBitmap();
387 		} else if (fBitmapView->fLeftX > fBitmapView->fPositionX) {
388 			fBitmapView->fLeftX = fBitmapView->fPositionX - 1;
389 			fLeftTime = fMainTime;
390 			msg.AddInt64("left", fLeftTime);
391 			_RenderBitmap();
392 		}
393 
394 		Invoke(&msg);
395 		//printf("fPosition : %lld\n", fMainTime);
396 	}
397 	Draw(Bounds());
398 	Flush();
399 }
400 
401 
402 void
403 TrackSlider::_TimeToString(bigtime_t timestamp, char *string)
404 {
405 	uint32 hours = timestamp / 3600000000LL;
406 	timestamp -= hours * 3600000000LL;
407 	uint32 minutes = timestamp / 60000000LL;
408 	timestamp -= minutes * 60000000LL;
409 	uint32 seconds = timestamp / 1000000LL;
410 	timestamp -= seconds * 1000000LL;
411 	uint32 centiseconds = timestamp / 10000LL;
412 	sprintf(string, "%02" B_PRId32 ":%02" B_PRId32 ":%02" B_PRId32 ":%02"
413 		B_PRId32, hours, minutes, seconds, centiseconds);
414 }
415 
416 
417 void
418 TrackSlider::SetMainTime(bigtime_t timestamp, bool reset)
419 {
420 	fMainTime = timestamp;
421 	fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
422 		* ((double)fMainTime / fTotalTime);
423 	if (reset) {
424 		fRightTime = fTotalTime;
425 		fLeftTime = 0;
426 		fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
427 			* ((double)fLeftTime / fTotalTime);
428 		fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
429 			* ((double)fRightTime / fTotalTime);
430 		_RenderBitmap();
431 	}
432 	Invalidate();
433 }
434 
435 void
436 TrackSlider::SetTotalTime(bigtime_t timestamp, bool reset)
437 {
438 	fTotalTime = timestamp;
439 	if (reset) {
440 		fMainTime = 0;
441 		fRightTime = fTotalTime;
442 		fLeftTime = 0;
443 	}
444 	fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
445 		* ((double)fMainTime / fTotalTime);
446 	fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
447 		* ((double)fLeftTime / fTotalTime);
448 	fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
449 		* ((double)fRightTime / fTotalTime);
450 	_RenderBitmap();
451 	Invalidate();
452 }
453 
454 
455 void
456 TrackSlider::ResetMainTime()
457 {
458 	fMainTime = fLeftTime;
459 	fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
460 		* ((double)fMainTime / fTotalTime);
461 	Invalidate();
462 }
463 
464 
465 void
466 TrackSlider::FrameResized(float width, float height)
467 {
468 	fBitmapView->fRight = Bounds().right - kLeftRightTrackSliderWidth;
469 	fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
470 		* ((double)fMainTime / fTotalTime);
471 	_InitBitmap();
472 	fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
473 		* ((double)fLeftTime / fTotalTime);
474 	fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
475 		* ((double)fRightTime / fTotalTime);
476 	_RenderBitmap();
477 	Invalidate();
478 }
479 
480 
481 SliderOffscreenView::SliderOffscreenView(BRect frame, const char *name)
482 	: BView(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW),
483 	leftBitmap(BRect(BPoint(0,0), kLeftRightTrackSliderSize), B_CMAP8),
484 	rightBitmap(BRect(BPoint(0,0), kLeftRightTrackSliderSize), B_CMAP8),
485 	leftThumbBitmap(BRect(0, 0, kLeftRightThumbWidth - 1,
486 		kLeftRightThumbHeight - 1), B_CMAP8),
487 	rightThumbBitmap(BRect(0, 0, kLeftRightThumbWidth - 1,
488 		kLeftRightThumbHeight - 1), B_CMAP8)
489 {
490 	leftBitmap.SetBits(kLeftTrackSliderBits,
491 		kLeftRightTrackSliderWidth * kLeftRightTrackSliderHeight, 0, B_CMAP8);
492 	rightBitmap.SetBits(kRightTrackSliderBits,
493 		kLeftRightTrackSliderWidth * kLeftRightTrackSliderHeight, 0, B_CMAP8);
494 	leftThumbBitmap.SetBits(kLeftThumbBits,
495 		kLeftRightThumbWidth * kLeftRightThumbHeight, 0, B_CMAP8);
496 	rightThumbBitmap.SetBits(kRightThumbBits,
497 		kLeftRightThumbWidth * kLeftRightThumbHeight, 0, B_CMAP8);
498 }
499 
500 
501 SliderOffscreenView::~SliderOffscreenView()
502 {
503 
504 }
505 
506 
507 void
508 SliderOffscreenView::DrawX()
509 {
510 	SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
511 	FillRect(Bounds());
512 
513 	SetHighColor(189, 186, 189);
514 	StrokeLine(BPoint(11, SLIDER_BASE + 1), BPoint(fRight, SLIDER_BASE + 1));
515 	SetHighColor(0, 0, 0);
516 	StrokeLine(BPoint(11, SLIDER_BASE + 2), BPoint(fRight, SLIDER_BASE + 2));
517 	SetHighColor(255, 255, 255);
518 	StrokeLine(BPoint(11, SLIDER_BASE + 17), BPoint(fRight, SLIDER_BASE + 17));
519 	SetHighColor(231, 227, 231);
520 	StrokeLine(BPoint(11, SLIDER_BASE + 18), BPoint(fRight, SLIDER_BASE + 18));
521 
522 	SetDrawingMode(B_OP_OVER);
523 	SetLowColor(HighColor());
524 
525 	BPoint leftPoint(5, SLIDER_BASE + 1);
526 	DrawBitmapAsync(&leftBitmap, BRect(BPoint(0, 0),
527 		kLeftRightTrackSliderSize - BPoint(5, 0)),
528 		BRect(leftPoint, leftPoint + kLeftRightTrackSliderSize - BPoint(5, 0)));
529 	BPoint rightPoint(fRight + 1, SLIDER_BASE + 1);
530 	DrawBitmapAsync(&rightBitmap, BRect(BPoint(5, 0), kLeftRightTrackSliderSize),
531 		BRect(rightPoint, rightPoint + kLeftRightTrackSliderSize-BPoint(5, 0)));
532 
533 	SetHighColor(153, 153, 153);
534 	FillRect(BRect(11, SLIDER_BASE + 3, fLeftX - 9, SLIDER_BASE + 16));
535 	FillRect(BRect(fRightX + 9, SLIDER_BASE + 3, fRight, SLIDER_BASE + 16));
536 	if (fLeftX > 19) {
537 		StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 3), BPoint(fLeftX - 6,
538 			SLIDER_BASE + 3));
539 		StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 4), BPoint(fLeftX - 7,
540 			SLIDER_BASE + 4));
541 		StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 5), BPoint(fLeftX - 8,
542 			SLIDER_BASE + 5));
543 		StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 16), BPoint(fLeftX - 6,
544 			SLIDER_BASE + 16));
545 		StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 15), BPoint(fLeftX - 7,
546 			SLIDER_BASE + 15));
547 		StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 14), BPoint(fLeftX - 8,
548 			SLIDER_BASE + 14));
549 	}
550 	if (fRightX < fRight - 5) {
551 		StrokeLine(BPoint(fRightX + 5, SLIDER_BASE + 3), BPoint(fRightX + 8,
552 			SLIDER_BASE + 3));
553 		StrokeLine(BPoint(fRightX + 7, SLIDER_BASE + 4), BPoint(fRightX + 8,
554 			SLIDER_BASE + 4));
555 		StrokeLine(BPoint(fRightX + 8, SLIDER_BASE + 5), BPoint(fRightX + 8,
556 			SLIDER_BASE + 6));
557 		StrokeLine(BPoint(fRightX + 8, SLIDER_BASE + 13), BPoint(fRightX + 8,
558 			SLIDER_BASE + 14));
559 		StrokeLine(BPoint(fRightX + 5, SLIDER_BASE + 16), BPoint(fRightX + 8,
560 			SLIDER_BASE + 16));
561 		StrokeLine(BPoint(fRightX + 7, SLIDER_BASE + 15), BPoint(fRightX + 8,
562 			SLIDER_BASE + 15));
563 	}
564 	SetHighColor(144, 186, 136);
565 	FillRect(BRect(fLeftX + 1, SLIDER_BASE + 3, fRightX, SLIDER_BASE + 4));
566 	FillRect(BRect(fLeftX + 1, SLIDER_BASE + 5, fLeftX + 2, SLIDER_BASE + 16));
567 	SetHighColor(171, 221, 161);
568 	FillRect(BRect(fLeftX + 3, SLIDER_BASE + 5, fRightX, SLIDER_BASE + 16));
569 
570 	int i = 17;
571 	int j = 18;
572 	SetHighColor(128, 128, 128);
573 	for (; i < fLeftX - 9; i += 6) {
574 		StrokeLine(BPoint(i, SLIDER_BASE + 7), BPoint(i, SLIDER_BASE + 13));
575 	}
576 	SetHighColor(179, 179, 179);
577 	for (; j < fLeftX - 9; j += 6) {
578 		StrokeLine(BPoint(j, SLIDER_BASE + 7), BPoint(j, SLIDER_BASE + 13));
579 	}
580 
581 	while (i <= fLeftX)
582 		i += 6;
583 	while (j <= fLeftX)
584 		j += 6;
585 
586 	SetHighColor(144, 186, 136);
587 	for (; i <= fRightX; i += 6) {
588 		StrokeLine(BPoint(i, SLIDER_BASE + 7), BPoint(i, SLIDER_BASE + 13));
589 	}
590 	SetHighColor(189, 244, 178);
591 	for (; j <= fRightX; j += 6) {
592 		StrokeLine(BPoint(j, SLIDER_BASE + 7), BPoint(j, SLIDER_BASE + 13));
593 	}
594 
595 	while (i <= fRightX + 9)
596 		i += 6;
597 	while (j <= fRightX + 9)
598 		j += 6;
599 
600 	SetHighColor(128, 128, 128);
601 	for (; i <= fRight + 1; i += 6) {
602 		StrokeLine(BPoint(i, SLIDER_BASE + 7), BPoint(i, SLIDER_BASE + 13));
603 	}
604 	SetHighColor(179, 179, 179);
605 	for (; j <= fRight + 1; j += 6) {
606 		StrokeLine(BPoint(j, SLIDER_BASE + 7), BPoint(j, SLIDER_BASE + 13));
607 	}
608 
609 	SetLowColor(HighColor());
610 
611 	BPoint leftThumbPoint(fLeftX - 8, SLIDER_BASE + 3);
612 	DrawBitmapAsync(&leftThumbBitmap, BRect(BPoint(0, 0),
613 		kLeftRightThumbSize - BPoint(7, 0)),
614 		BRect(leftThumbPoint, leftThumbPoint
615 			+ kLeftRightThumbSize - BPoint(7, 0)));
616 
617 	BPoint rightThumbPoint(fRightX, SLIDER_BASE + 3);
618 	DrawBitmapAsync(&rightThumbBitmap, BRect(BPoint(6, 0),
619 		kLeftRightThumbSize),
620 		BRect(rightThumbPoint, rightThumbPoint
621 			+ kLeftRightThumbSize-BPoint(6, 0)));
622 
623 	Sync();
624 }
625