xref: /haiku/src/kits/interface/Slider.cpp (revision d29f332ad4210e2e2b5ef42231531dd937ebc52e)
1 /*
2  * Copyright 2001-2005, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stephan Aßmus <superstippi@gmx.de>
8  *		Axel Dörfler, axeld@pinc-software.de
9  */
10 
11 
12 #include <stdio.h>
13 
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <Bitmap.h>
18 #include <Errors.h>
19 #include <Message.h>
20 #include <Region.h>
21 #include <Window.h>
22 
23 #include <Slider.h>
24 
25 
26 rgb_color
27 _long_to_color_(int32 color)
28 {
29 	return *((rgb_color*)&color);
30 }
31 
32 int32
33 _color_to_long_(rgb_color color)
34 {
35 	return *((int32*)&color);
36 }
37 
38 
39 BSlider::BSlider(BRect frame, const char *name, const char *label, BMessage *message,
40 				 int32 minValue, int32 maxValue, thumb_style thumbType,
41 				 uint32 resizingMode, uint32 flags)
42 	: BControl(frame, name, label, message, resizingMode, flags)
43 {
44 	fModificationMessage = NULL;
45 	fSnoozeAmount = 20000;
46 	fOrientation = B_HORIZONTAL;
47 	fBarThickness = 6.0f;
48 	fMinLimitStr = NULL;
49 	fMaxLimitStr = NULL;
50 	fMinValue = minValue;
51 	fMaxValue = maxValue;
52 
53 	SetValue(0);
54 
55 	fKeyIncrementValue = 1;
56 	fHashMarkCount = 0;
57 	fHashMarks = B_HASH_MARKS_NONE;
58 	fStyle = thumbType;
59 
60 	if (Style() == B_BLOCK_THUMB)
61 		SetBarColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
62 			B_DARKEN_4_TINT));
63 	else
64 		SetBarColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
65 			B_DARKEN_4_TINT));
66 
67 	UseFillColor(false, NULL);
68 
69 	_InitObject();
70 }
71 
72 
73 BSlider::BSlider(BRect frame, const char *name, const char *label, BMessage *message,
74 				 int32 minValue, int32 maxValue, orientation posture,
75 				 thumb_style thumbType, uint32 resizingMode, uint32 flags)
76 	: BControl(frame, name, label, message, resizingMode, flags)
77 {
78 	fModificationMessage = NULL;
79 	fSnoozeAmount = 20000;
80 	fOrientation = posture;
81 	fBarThickness = 6.0f;
82 	fMinLimitStr = NULL;
83 	fMaxLimitStr = NULL;
84 	fMinValue = minValue;
85 	fMaxValue = maxValue;
86 
87 	SetValue(0);
88 
89 	fKeyIncrementValue = 1;
90 	fHashMarkCount = 0;
91 	fHashMarks = B_HASH_MARKS_NONE;
92 	fStyle = thumbType;
93 
94 	if (Style() == B_BLOCK_THUMB)
95 		SetBarColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
96 			B_DARKEN_4_TINT));
97 	else
98 		SetBarColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
99 			B_DARKEN_4_TINT));
100 
101 	UseFillColor(false, NULL);
102 
103 	_InitObject();
104 }
105 
106 
107 BSlider::~BSlider()
108 {
109 #if USE_OFF_SCREEN_VIEW
110 	if (fOffScreenBits)
111 		delete fOffScreenBits;
112 #endif
113 
114 	delete fModificationMessage;
115 	free(fMinLimitStr);
116 	free(fMaxLimitStr);
117 }
118 
119 
120 BSlider::BSlider(BMessage *archive)
121 	:	BControl (archive)
122 {
123 	fModificationMessage = NULL;
124 
125 	if (archive->HasMessage("_mod_msg")) {
126 		BMessage *message = new BMessage;
127 
128 		archive->FindMessage("_mod_msg", message);
129 
130 		SetModificationMessage(message);
131 	}
132 
133 	if (archive->FindInt32("_sdelay", &fSnoozeAmount) != B_OK)
134 		SetSnoozeAmount(20000);
135 
136 	int32 color;
137 
138 	if (archive->FindInt32("_fcolor", &color) == B_OK) {
139 		rgb_color fillColor = _long_to_color_(color);
140 		UseFillColor(true, &fillColor);
141 	} else
142 		UseFillColor(false);
143 
144 	int32 orient;
145 
146 	if (archive->FindInt32("_orient", &orient) == B_OK)
147 		fOrientation = (orientation)orient;
148 	else
149 		fOrientation = B_HORIZONTAL;
150 
151 	fMinLimitStr = NULL;
152 	fMaxLimitStr = NULL;
153 
154 	const char *minlbl = NULL, *maxlbl = NULL;
155 
156 	archive->FindString("_minlbl", &minlbl);
157 	archive->FindString("_maxlbl", &maxlbl);
158 
159 	SetLimitLabels(minlbl, maxlbl);
160 
161 	if (archive->FindInt32("_min", &fMinValue) != B_OK)
162 		fMinValue = 0;
163 
164 	if (archive->FindInt32("_max", &fMaxValue) != B_OK)
165 		fMaxValue = 100;
166 
167 	if (archive->FindInt32("_incrementvalue", &fKeyIncrementValue) != B_OK)
168 		fKeyIncrementValue = 1;
169 
170 	if (archive->FindInt32("_hashcount", &fHashMarkCount) != B_OK)
171 		fHashMarkCount = 11;
172 
173 	int16 hashloc;
174 
175 	if (archive->FindInt16("_hashloc", &hashloc) == B_OK)
176 		fHashMarks = (hash_mark_location)hashloc;
177 	else
178 		fHashMarks = B_HASH_MARKS_NONE;
179 
180 	int16 sstyle;
181 
182 	if (archive->FindInt16("_sstyle", &sstyle) == B_OK)
183 		fStyle = (thumb_style)sstyle;
184 	else
185 		fStyle = B_BLOCK_THUMB;
186 
187 	if (archive->FindInt32("_bcolor", &color) == B_OK)
188 		SetBarColor(_long_to_color_(color));
189 	else {
190 		if (Style() == B_BLOCK_THUMB)
191 			SetBarColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
192 				B_DARKEN_4_TINT));
193 		else
194 			SetBarColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
195 				B_DARKEN_4_TINT));
196 	}
197 
198 	float bthickness;
199 
200 	if (archive->FindFloat("_bthickness", &bthickness) == B_OK)
201 		fBarThickness = bthickness;
202 	else
203 		fBarThickness = 6.0f;
204 
205 	_InitObject();
206 }
207 
208 
209 void
210 BSlider::_InitObject()
211 {
212 	fLocation.x = 0;
213 	fLocation.y = 0;
214 	fInitialLocation.x = 0;
215 	fInitialLocation.y = 0;
216 
217 #if USE_OFF_SCREEN_VIEW
218 	fOffScreenBits = NULL;
219 	fOffScreenView = NULL;
220 #endif
221 }
222 
223 
224 BArchivable*
225 BSlider::Instantiate(BMessage *archive)
226 {
227 	if (validate_instantiation(archive, "BSlider"))
228 		return new BSlider(archive);
229 
230 	return NULL;
231 }
232 
233 
234 status_t
235 BSlider::Archive(BMessage *archive, bool deep) const
236 {
237 	BControl::Archive(archive, deep);
238 
239 	if (ModificationMessage())
240 		archive->AddMessage("_mod_msg", ModificationMessage());
241 
242 	archive->AddInt32("_sdelay", fSnoozeAmount);
243 
244 	archive->AddInt32("_bcolor", _color_to_long_(fBarColor));
245 
246 	if (FillColor(NULL))
247 		archive->AddInt32("_fcolor", _color_to_long_(fFillColor));
248 
249 	if (fMinLimitStr)
250 		archive->AddString("_minlbl", fMinLimitStr);
251 
252 	if (fMaxLimitStr)
253 		archive->AddString("_maxlbl", fMaxLimitStr);
254 
255 	archive->AddInt32("_min", fMinValue);
256 	archive->AddInt32("_max", fMaxValue);
257 
258 	archive->AddInt32("_incrementvalue", fKeyIncrementValue);
259 
260 	archive->AddInt32("_hashcount", fHashMarkCount);
261 
262 	archive->AddInt16("_hashloc", fHashMarks);
263 
264 	archive->AddInt16("_sstyle", fStyle);
265 
266 	archive->AddInt32("_orient", fOrientation);
267 
268 	archive->AddFloat("_bthickness", fBarThickness);
269 
270 	return B_OK;
271 }
272 
273 
274 status_t
275 BSlider::Perform(perform_code d, void *arg)
276 {
277 	return BControl::Perform(d, arg);
278 }
279 
280 
281 void
282 BSlider::WindowActivated(bool state)
283 {
284 	BControl::WindowActivated(state);
285 }
286 
287 
288 void
289 BSlider::AttachedToWindow()
290 {
291 	ResizeToPreferred();
292 
293 	fLocation.Set(9.0f, 0.0f);
294 
295 #if USE_OFF_SCREEN_VIEW
296 	BRect bounds(Bounds());
297 
298 	if (!fOffScreenView) {
299 		fOffScreenView = new BView(bounds, "", B_FOLLOW_ALL, B_WILL_DRAW);
300 
301 		BFont font;
302 		GetFont(&font);
303 		fOffScreenView->SetFont(&font);
304 	}
305 
306 	if (!fOffScreenBits) {
307 		fOffScreenBits = new BBitmap(bounds, B_CMAP8, true, false);
308 
309 		if (fOffScreenBits && fOffScreenView)
310 			fOffScreenBits->AddChild(fOffScreenView);
311 
312 	} else if (fOffScreenView)
313 		fOffScreenBits->AddChild(fOffScreenView);
314 #endif // USE_OFF_SCREEN_VIEW
315 
316 	SetValue(Value());
317 
318 	BView* view = OffscreenView();
319 
320 	BControl::AttachedToWindow();
321 
322 	if (view && Parent()) {
323 		rgb_color color = Parent()->ViewColor();
324 
325 /*		fOffScreenBits->Lock();
326 		fOffScreenView->SetViewColor(color);
327 		fOffScreenView->SetLowColor(color);
328 		fOffScreenBits->Unlock();*/
329 
330 		view->LockLooper();
331 		view->SetViewColor(B_TRANSPARENT_COLOR);
332 		view->SetLowColor(color);
333 		view->UnlockLooper();
334 	}
335 }
336 
337 
338 void
339 BSlider::AllAttached()
340 {
341 	BControl::AllAttached();
342 }
343 
344 
345 void
346 BSlider::AllDetached()
347 {
348 	BControl::AllDetached();
349 }
350 
351 
352 void
353 BSlider::DetachedFromWindow()
354 {
355 	BControl::DetachedFromWindow();
356 
357 #if USE_OFF_SCREEN_VIEW
358 	if (fOffScreenBits) {
359 		delete fOffScreenBits;
360 		fOffScreenBits = NULL;
361 		fOffScreenView = NULL;
362 	}
363 #endif
364 }
365 
366 
367 void
368 BSlider::MessageReceived(BMessage *msg)
369 {
370 	BControl::MessageReceived(msg);
371 }
372 
373 
374 void
375 BSlider::FrameMoved(BPoint new_position)
376 {
377 	BControl::FrameMoved(new_position);
378 }
379 
380 
381 void
382 BSlider::FrameResized(float w,float h)
383 {
384 	BControl::FrameResized(w, h);
385 
386 	BRect bounds(Bounds());
387 
388 	if (bounds.right <= 0.0f || bounds.bottom <= 0.0f)
389 		return;
390 
391 #if USE_OFF_SCREEN_VIEW
392 	if (fOffScreenBits) {
393 		fOffScreenBits->RemoveChild(fOffScreenView);
394 		delete fOffScreenBits;
395 
396 		fOffScreenView->ResizeTo(bounds.Width(), bounds.Height());
397 
398 		fOffScreenBits = new BBitmap(Bounds(), B_CMAP8, true, false);
399 		fOffScreenBits->AddChild(fOffScreenView);
400 	}
401 #endif
402 
403 	SetValue(Value());
404 	// virtual
405 }
406 
407 
408 void
409 BSlider::KeyDown(const char *bytes, int32 numBytes)
410 {
411 	if (!IsEnabled() || IsHidden())
412 		return;
413 
414 	switch (bytes[0]) {
415 		case B_LEFT_ARROW:
416 		case B_DOWN_ARROW: {
417 			SetValue(Value() - KeyIncrementValue());
418 			Invoke();
419 			break;
420 		}
421 		case B_RIGHT_ARROW:
422 		case B_UP_ARROW: {
423 			SetValue(Value() + KeyIncrementValue());
424 			Invoke();
425 			break;
426 		}
427 		default:
428 			BControl::KeyDown(bytes, numBytes);
429 	}
430 }
431 
432 
433 bool
434 BSlider::_ConstrainPoint(BPoint point, BPoint comparePoint) const
435 {
436 	if (fOrientation == B_HORIZONTAL) {
437 		if (point.x != comparePoint.x) {
438 			if (point.x < _MinPosition())
439 				point.x = _MinPosition();
440 			else if (point.x > _MaxPosition())
441 				point.x = _MaxPosition();
442 
443 			return true;
444 		}
445 	} else {
446 		if (point.y != comparePoint.y) {
447 			if (point.y > _MinPosition())
448 				point.y = _MinPosition();
449 			else if (point.y < _MaxPosition())
450 				point.y = _MaxPosition();
451 
452 			return true;
453 		}
454 	}
455 
456 	return false;
457 }
458 
459 
460 void
461 BSlider::MouseDown(BPoint point)
462 {
463 	if (!IsEnabled())
464 		return;
465 
466 	if (BarFrame().Contains(point) || ThumbFrame().Contains(point))
467 		fInitialLocation = _Location();
468 
469 	uint32 buttons;
470 	GetMouse(&point, &buttons, true);
471 
472 	_ConstrainPoint(point, fInitialLocation);
473 	SetValue(ValueForPoint(point));
474 
475 	InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
476 
477 	if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
478 		SetTracking(true);
479 		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
480 	} else {
481 		// synchronous mouse tracking
482 		BPoint prevPoint;
483 
484 		while (buttons) {
485 			prevPoint = point;
486 
487 			snooze(SnoozeAmount());
488 			GetMouse(&point, &buttons, true);
489 
490 			if (_ConstrainPoint(point, prevPoint)) {
491 				SetValue(ValueForPoint(point));
492 				InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
493 			}
494 		}
495 	}
496 
497 	if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) == 0) {
498 		if (_Location() != fInitialLocation)
499 			Invoke();
500 	}
501 }
502 
503 
504 void
505 BSlider::MouseUp(BPoint point)
506 {
507 	if (IsTracking()) {
508 		if (_Location() != fInitialLocation)
509 			Invoke();
510 
511 		SetTracking(false);
512 	} else
513 		BControl::MouseUp(point);
514 }
515 
516 
517 void
518 BSlider::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
519 {
520 	if (IsTracking()) {
521 		if (_ConstrainPoint(point, _Location())) {
522 			SetValue(ValueForPoint(point));
523 			InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
524 		}
525 	} else
526 		BControl::MouseMoved(point, transit, message);
527 }
528 
529 
530 void
531 BSlider::Pulse()
532 {
533 	BControl::Pulse();
534 }
535 
536 
537 void
538 BSlider::SetLabel(const char *label)
539 {
540 	BControl::SetLabel(label);
541 }
542 
543 
544 void
545 BSlider::SetLimitLabels(const char *minLabel, const char *maxLabel)
546 {
547 	if (minLabel) {
548 		if (fMinLimitStr)
549 			free(fMinLimitStr);
550 		fMinLimitStr = strdup(minLabel);
551 	}
552 
553 	if (maxLabel) {
554 		if (fMaxLimitStr)
555 			free(fMaxLimitStr);
556 		fMaxLimitStr = strdup(maxLabel);
557 	}
558 
559 	// TODO: Auto resizing?!? I would not want this as an app programmer!
560 	ResizeToPreferred();
561 	Invalidate();
562 }
563 
564 
565 const char*
566 BSlider::MinLimitLabel() const
567 {
568 	return fMinLimitStr;
569 }
570 
571 
572 const char*
573 BSlider::MaxLimitLabel() const
574 {
575 	return fMaxLimitStr;
576 }
577 
578 
579 void
580 BSlider::SetValue(int32 value)
581 {
582 	if (value < fMinValue)
583 		value = fMinValue;
584 	if (value > fMaxValue)
585 		value = fMaxValue;
586 
587 	if (value != Value()) {
588 		BPoint loc;
589 		float pos = (float)(value - fMinValue) / (float)(fMaxValue - fMinValue) *
590 			_MaxPosition() - _MinPosition();
591 
592 		if (fOrientation == B_HORIZONTAL) {
593 			loc.x = ceil(_MinPosition() + pos);
594 			loc.y = 0;
595 		} else {
596 			loc.x = 0;
597 			loc.y = floor(_MaxPosition() - pos);
598 		}
599 
600 		BRect oldThumbFrame = ThumbFrame();
601 
602 		if (IsFocus() && Style() == B_TRIANGLE_THUMB) {
603 			// we need to update the region with the focus mark as well
604 			// (a method BSlider::FocusMarkFrame() would be nice as well)
605 			if (fOrientation == B_HORIZONTAL)
606 				oldThumbFrame.bottom += 2;
607 			else
608 				oldThumbFrame.left -= 2;
609 		}
610 
611 		// While it would be enough to do this dependent on fUseFillColor,
612 		// that doesn't work out if DrawBar() has been overridden by a sub class
613 		if (fOrientation == B_HORIZONTAL)
614 			oldThumbFrame.top = BarFrame().top;
615 		else
616 			oldThumbFrame.right = BarFrame().right;
617 
618 		_SetLocation(loc);
619 
620 		BControl::SetValue(value);
621 
622 		Invalidate(oldThumbFrame | ThumbFrame());
623 	}
624 }
625 
626 
627 int32
628 BSlider::ValueForPoint(BPoint location) const
629 {
630 	return (int32)(((fOrientation == B_HORIZONTAL ? location.x : location.y)
631 			- _MinPosition())
632 		* (fMaxValue - fMinValue) / (_MaxPosition() - _MinPosition())) + fMinValue;
633 }
634 
635 
636 void
637 BSlider::SetPosition(float position)
638 {
639 	if (position <= 0.0f)
640 		BControl::SetValue(fMinValue);
641 	else if (position >= 1.0f)
642 		BControl::SetValue(fMaxValue);
643 	else
644 		BControl::SetValue((int32)(position * (fMaxValue - fMinValue) + fMinValue));
645 }
646 
647 
648 float
649 BSlider::Position() const
650 {
651 	return ((float)(Value() - fMinValue) / (float)(fMaxValue - fMinValue));
652 }
653 
654 
655 void
656 BSlider::SetEnabled(bool on)
657 {
658 	BControl::SetEnabled(on);
659 }
660 
661 
662 void
663 BSlider::GetLimits(int32 *minimum, int32 *maximum)
664 {
665 	*minimum = fMinValue;
666 	*maximum = fMaxValue;
667 }
668 
669 
670 void
671 BSlider::Draw(BRect updateRect)
672 {
673 	// clear out background
674 	BRegion background(updateRect);
675 	background.Exclude(BarFrame());
676 
677 	// ToDo: the triangle thumb doesn't delete its background, so we still have to do it
678 	// Note, this also creates a different behaviour for subclasses, depending on the
679 	// thumb style - if possible this should be avoided.
680 	if (Style() == B_BLOCK_THUMB)
681 		background.Exclude(ThumbFrame());
682 
683 
684 #if USE_OFF_SCREEN_VIEW
685 	if (!fOffScreenBits)
686 		return;
687 
688 	if (fOffScreenBits->Lock()) {
689 #endif
690 
691 		if (background.Frame().IsValid())
692 			OffscreenView()->FillRegion(&background, B_SOLID_LOW);
693 
694 #if USE_OFF_SCREEN_VIEW
695 		fOffScreenView->Sync();
696 		fOffScreenBits->Unlock();
697 	}
698 #endif
699 
700 	DrawSlider();
701 }
702 
703 
704 void
705 BSlider::DrawSlider()
706 {
707 #if USE_OFF_SCREEN_VIEW
708 	if (!fOffScreenBits)
709 		return;
710 	if (fOffScreenBits->Lock()) {
711 #endif
712 		DrawBar();
713 		DrawHashMarks();
714 		DrawThumb();
715 		DrawFocusMark();
716 		DrawText();
717 
718 #if USE_OFF_SCREEN_VIEW
719 		fOffScreenView->Sync();
720 		fOffScreenBits->Unlock();
721 
722 		DrawBitmap(fOffScreenBits, B_ORIGIN);
723 	}
724 #endif
725 }
726 
727 
728 void
729 BSlider::DrawBar()
730 {
731 	BRect frame = BarFrame();
732 	BView *view = OffscreenView();
733 
734 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
735 	rgb_color lightenmax;
736 	rgb_color darken1;
737 	rgb_color darken2;
738 	rgb_color darkenmax;
739 
740 	rgb_color barColor;
741 	rgb_color fillColor;
742 
743 	if (IsEnabled()) {
744 		lightenmax	= tint_color(no_tint, B_LIGHTEN_MAX_TINT);
745 		darken1		= tint_color(no_tint, B_DARKEN_1_TINT);
746 		darken2		= tint_color(no_tint, B_DARKEN_2_TINT);
747 		darkenmax	= tint_color(no_tint, B_DARKEN_MAX_TINT);
748 		barColor	= fBarColor;
749 		fillColor	= fFillColor;
750 	} else {
751 		lightenmax	= tint_color(no_tint, B_LIGHTEN_MAX_TINT);
752 		darken1		= no_tint;
753 		darken2		= tint_color(no_tint, B_DARKEN_1_TINT);
754 		darkenmax	= tint_color(no_tint, B_DARKEN_3_TINT);
755 
756 		barColor.red	= (fBarColor.red + no_tint.red) / 2;
757 		barColor.green	= (fBarColor.green + no_tint.green) / 2;
758 		barColor.blue	= (fBarColor.blue + no_tint.blue) / 2;
759 
760 		fillColor.red	= (fFillColor.red + no_tint.red) / 2;
761 		fillColor.green	= (fFillColor.green + no_tint.green) / 2;
762 		fillColor.blue	= (fFillColor.blue + no_tint.blue) / 2;
763 	}
764 
765 	// exclude the block thumb from the bar filling
766 
767 	BRect lowerFrame = frame.InsetByCopy(1, 1);
768 	lowerFrame.top++;
769 	lowerFrame.left++;
770 	BRect upperFrame = lowerFrame;
771 	BRect thumbFrame;
772 
773 	if (Style() == B_BLOCK_THUMB) {
774 		thumbFrame = ThumbFrame();
775 
776 		if (fOrientation == B_HORIZONTAL) {
777 			lowerFrame.right = thumbFrame.left;
778 			upperFrame.left = thumbFrame.right;
779 		} else {
780 			lowerFrame.top = thumbFrame.bottom;
781 			upperFrame.bottom = thumbFrame.top;
782 		}
783 	} else if (fUseFillColor) {
784 		if (fOrientation == B_HORIZONTAL) {
785 			lowerFrame.right = floor(lowerFrame.left - 1 + Position()
786 				* (lowerFrame.Width() + 1));
787 			upperFrame.left = lowerFrame.right;
788 		} else {
789 			lowerFrame.top = floor(lowerFrame.bottom + 1 - Position()
790 				* (lowerFrame.Height() + 1));
791 			upperFrame.bottom = lowerFrame.top;
792 		}
793 	}
794 
795 	view->SetHighColor(barColor);
796 	view->FillRect(upperFrame);
797 
798 	if (Style() == B_BLOCK_THUMB || fUseFillColor) {
799 		if (fUseFillColor)
800 			view->SetHighColor(fillColor);
801 		view->FillRect(lowerFrame);
802 	}
803 
804 	if (Style() == B_BLOCK_THUMB) {
805 		// We don't want to stroke the lines over the thumb
806 
807 		PushState();
808 
809 		BRegion region;
810 		GetClippingRegion(&region);
811 		region.Exclude(thumbFrame);
812 		ConstrainClippingRegion(&region);
813 	}
814 
815 	view->SetHighColor(darken1);
816 	view->StrokeLine(BPoint(frame.left, frame.top),
817 					 BPoint(frame.left + 1.0f, frame.top));
818 	view->StrokeLine(BPoint(frame.left, frame.bottom),
819 					 BPoint(frame.left + 1.0f, frame.bottom));
820 	view->StrokeLine(BPoint(frame.right - 1.0f, frame.top),
821 					 BPoint(frame.right, frame.top));
822 
823 	view->SetHighColor(darken2);
824 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
825 					 BPoint(frame.right - 1.0f, frame.top));
826 	view->StrokeLine(BPoint(frame.left, frame.bottom - 1.0f),
827 					 BPoint(frame.left, frame.top + 1.0f));
828 
829 	view->SetHighColor(lightenmax);
830 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.bottom),
831 					 BPoint(frame.right, frame.bottom));
832 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
833 					 BPoint(frame.right, frame.top + 1.0f));
834 
835 	frame.InsetBy(1.0f, 1.0f);
836 
837 	view->SetHighColor(darkenmax);
838 	view->StrokeLine(BPoint(frame.left, frame.bottom),
839 					 BPoint(frame.left, frame.top));
840 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
841 					 BPoint(frame.right, frame.top));
842 
843 	if (Style() == B_BLOCK_THUMB)
844 		PopState();
845 }
846 
847 
848 void
849 BSlider::DrawHashMarks()
850 {
851 	BRect frame = HashMarksFrame();
852 	BView *view = OffscreenView();
853 
854 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
855 	rgb_color lightenmax;
856 	rgb_color darken2;
857 
858 	if (IsEnabled()) {
859 		lightenmax	= tint_color(no_tint, B_LIGHTEN_MAX_TINT);
860 		darken2		= tint_color(no_tint, B_DARKEN_2_TINT);
861 	} else {
862 		lightenmax	= tint_color(no_tint, B_LIGHTEN_2_TINT);
863 		darken2		= tint_color(no_tint, B_DARKEN_1_TINT);
864 	}
865 
866 	float pos = _MinPosition();
867 	float factor = (_MaxPosition() - pos) / (fHashMarkCount - 1);
868 
869 	if (fHashMarks & B_HASH_MARKS_TOP) {
870 
871 		view->BeginLineArray(fHashMarkCount * 2);
872 
873 		if (fOrientation == B_HORIZONTAL) {
874 			for (int32 i = 0; i < fHashMarkCount; i++) {
875 				view->AddLine(BPoint(pos, frame.top),
876 							  BPoint(pos, frame.top + 5), darken2);
877 				view->AddLine(BPoint(pos + 1, frame.top),
878 							  BPoint(pos + 1, frame.top + 5), lightenmax);
879 
880 				pos += factor;
881 			}
882 		} else {
883 			for (int32 i = 0; i < fHashMarkCount; i++) {
884 				view->AddLine(BPoint(frame.left, pos),
885 							  BPoint(frame.left + 5, pos), darken2);
886 				view->AddLine(BPoint(frame.left, pos + 1),
887 							  BPoint(frame.left + 5, pos + 1), lightenmax);
888 
889 				pos += factor;
890 			}
891 		}
892 
893 		view->EndLineArray();
894 	}
895 
896 	pos = _MinPosition();
897 
898 	if (fHashMarks & B_HASH_MARKS_BOTTOM) {
899 		view->BeginLineArray(fHashMarkCount * 2);
900 
901 		if (fOrientation == B_HORIZONTAL) {
902 			for (int32 i = 0; i < fHashMarkCount; i++) {
903 				view->AddLine(BPoint(pos, frame.bottom - 5),
904 							  BPoint(pos, frame.bottom), darken2);
905 				view->AddLine(BPoint(pos + 1, frame.bottom - 5),
906 							  BPoint(pos + 1, frame.bottom), lightenmax);
907 
908 				pos += factor;
909 			}
910 		} else {
911 			for (int32 i = 0; i < fHashMarkCount; i++) {
912 				view->AddLine(BPoint(frame.right - 5, pos),
913 							  BPoint(frame.right, pos), darken2);
914 				view->AddLine(BPoint(frame.right - 5, pos + 1),
915 							  BPoint(frame.right, pos + 1), lightenmax);
916 
917 				pos += factor;
918 			}
919 		}
920 
921 		view->EndLineArray();
922 	}
923 }
924 
925 
926 void
927 BSlider::DrawThumb()
928 {
929 	if (Style() == B_BLOCK_THUMB)
930 		_DrawBlockThumb();
931 	else
932 		_DrawTriangleThumb();
933 }
934 
935 
936 void
937 BSlider::DrawFocusMark()
938 {
939 	if (!IsFocus())
940 		return;
941 
942 	OffscreenView()->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
943 
944 	BRect frame = ThumbFrame();
945 
946 	if (fStyle == B_BLOCK_THUMB) {
947 		frame.left += 2.0f;
948 		frame.top += 2.0f;
949 		frame.right -= 3.0f;
950 		frame.bottom -= 3.0f;
951 		OffscreenView()->StrokeRect(frame);
952 	} else {
953 		if (fOrientation == B_HORIZONTAL) {
954 			OffscreenView()->StrokeLine(BPoint(frame.left, frame.bottom + 2.0f),
955 				BPoint(frame.right, frame.bottom + 2.0f));
956 		} else {
957 			OffscreenView()->StrokeLine(BPoint(frame.left - 2.0f, frame.top),
958 				BPoint(frame.left - 2.0f, frame.bottom));
959 		}
960 	}
961 }
962 
963 
964 void
965 BSlider::DrawText()
966 {
967 	BRect bounds(Bounds());
968 	BView *view = OffscreenView();
969 
970 	if (IsEnabled()) {
971 		view->SetHighColor(0, 0, 0);
972 	} else {
973 		view->SetHighColor(tint_color(LowColor(), B_DISABLED_LABEL_TINT));
974 	}
975 
976 	font_height fheight;
977 
978 	GetFontHeight(&fheight);
979 
980 	if (Orientation() == B_HORIZONTAL) {
981 		if (Label())
982 			view->DrawString(Label(), BPoint(2.0f, (float)ceil(fheight.ascent)));
983 
984 		if (fMinLimitStr)
985 			view->DrawString(fMinLimitStr, BPoint(2.0f, bounds.bottom - 4.0f));
986 
987 		if (fMaxLimitStr)
988 			view->DrawString(fMaxLimitStr, BPoint(bounds.right -
989 												  StringWidth(fMaxLimitStr) - 2.0f,
990 												  bounds.bottom - 4.0f));
991 	} else {
992 		float ascent = (float)ceil(fheight.ascent);
993 
994 		if (Label())
995 			view->DrawString(Label(), BPoint(bounds.Width() / 2.0f -
996 											 StringWidth(Label()) / 2.0f,
997 											 ascent));
998 
999 		if (fMaxLimitStr)
1000 			view->DrawString(fMaxLimitStr, BPoint(bounds.Width() / 2.0f -
1001 												  StringWidth(fMaxLimitStr) / 2.0f,
1002 												  ascent +
1003 												  (Label() ? (float)ceil(ascent + fheight.descent + 2.0f)
1004 												  		   : 0.0f)));
1005 
1006 		if (fMinLimitStr)
1007 			view->DrawString(fMinLimitStr, BPoint(bounds.Width() / 2.0f -
1008 												  StringWidth(fMinLimitStr) / 2.0f,
1009 												  bounds.bottom - 2.0f));
1010 	}
1011 }
1012 
1013 
1014 char*
1015 BSlider::UpdateText() const
1016 {
1017 	return NULL;
1018 }
1019 
1020 
1021 BRect
1022 BSlider::BarFrame() const
1023 {
1024 	BRect frame(Bounds());
1025 
1026 	font_height fontHeight;
1027 	GetFontHeight(&fontHeight);
1028 
1029 	float textHeight = (float)ceil(fontHeight.ascent + fontHeight.descent);
1030 
1031 	if (fStyle == B_BLOCK_THUMB) {
1032 		if (Orientation() == B_HORIZONTAL) {
1033 			frame.left = 8.0f;
1034 			frame.top = 6.0f + (Label() ? textHeight + 4.0f : 0.0f);
1035 			frame.right -= 8.0f;
1036 			frame.bottom = frame.top + fBarThickness;
1037 		} else {
1038 			frame.left = floor((frame.Width() - fBarThickness) / 2.0f);
1039 			frame.top = 12.0f + (Label() ? textHeight : 0.0f) +
1040 				(fMaxLimitStr ? textHeight : 0.0f);
1041 			frame.right = frame.left + fBarThickness;
1042 			frame.bottom = frame.bottom - 8.0f -
1043 				(fMinLimitStr ? textHeight + 4 : 0.0f);
1044 		}
1045 	} else {
1046 		if (Orientation() == B_HORIZONTAL) {
1047 			frame.left = 7.0f;
1048 			frame.top = 6.0f + (Label() ? textHeight + 4.0f : 0.0f);
1049 			frame.right -= 7.0f;
1050 			frame.bottom = frame.top + fBarThickness;
1051 		} else {
1052 			frame.left = floor((frame.Width() - fBarThickness) / 2.0f);
1053 			frame.top = 11.0f + (Label() ? textHeight : 0.0f) +
1054 				(fMaxLimitStr ? textHeight : 0.0f);
1055 			frame.right = frame.left + fBarThickness;
1056 			frame.bottom = frame.bottom - 7.0f -
1057 				(fMinLimitStr ? textHeight + 4 : 0.0f);
1058 		}
1059 	}
1060 
1061 	return frame;
1062 }
1063 
1064 
1065 BRect
1066 BSlider::HashMarksFrame() const
1067 {
1068 	BRect frame(BarFrame());
1069 
1070 	if (fOrientation == B_HORIZONTAL) {
1071 		frame.top -= 6.0f;
1072 		frame.bottom += 6.0f;
1073 	} else {
1074 		frame.left -= 6.0f;
1075 		frame.right += 6.0f;
1076 	}
1077 
1078 	return frame;
1079 }
1080 
1081 
1082 BRect
1083 BSlider::ThumbFrame() const
1084 {
1085 	// TODO: The slider looks really ugly and broken when it is too little.
1086 	// I would suggest using BarFrame() here to get the top and bottom coords
1087 	// and spread them further apart for the thumb
1088 
1089 	BRect frame = Bounds();
1090 	font_height fheight;
1091 
1092 	GetFontHeight(&fheight);
1093 
1094 	float textHeight = (float)ceil(fheight.ascent + fheight.descent);
1095 
1096 	if (fStyle == B_BLOCK_THUMB) {
1097 		if (Orientation() == B_HORIZONTAL) {
1098 			frame.left = (float)floor(Position() * (_MaxPosition() - _MinPosition()) +
1099 				_MinPosition()) - 8.0f;
1100 			frame.top = 2.0f + (Label() ? textHeight + 4.0f : 0.0f);
1101 			frame.right = frame.left + 17.0f;
1102 			frame.bottom = frame.top + fBarThickness + 7.0f;
1103 		} else {
1104 			frame.left = floor((frame.Width() - fBarThickness) / 2.0f) - 4;
1105 			frame.top = (float)floor(Position() * (_MaxPosition() - _MinPosition()) +
1106 				_MinPosition()) - 8.0f;
1107 			frame.right = frame.left + fBarThickness + 7.0f;
1108 			frame.bottom = frame.top + 17;
1109 		}
1110 	} else {
1111 		if (Orientation() == B_HORIZONTAL) {
1112 			frame.left = (float)floor(Position() * (_MaxPosition() - _MinPosition()) +
1113 				_MinPosition()) - 6;
1114 			frame.right = frame.left + 12.0f;
1115 			frame.bottom = frame.bottom - 2.0f -
1116 				(MinLimitLabel() || MaxLimitLabel() ? textHeight + 4.0f : 0.0f);
1117 			frame.top = frame.bottom - 8.0f;
1118 		} else {
1119 			frame.left = floor((frame.Width() - fBarThickness) / 2.0f) - 3;
1120 			frame.top = (float)floor(Position() * (_MaxPosition() - _MinPosition())) +
1121 				_MinPosition() - 6.0f;
1122 			frame.right = frame.left + 7;
1123 			frame.bottom = frame.top + 12;
1124 		}
1125 	}
1126 
1127 	return frame;
1128 }
1129 
1130 
1131 void
1132 BSlider::SetFlags(uint32 flags)
1133 {
1134 	BControl::SetFlags(flags);
1135 }
1136 
1137 
1138 void
1139 BSlider::SetResizingMode(uint32 mode)
1140 {
1141 	BControl::SetResizingMode(mode);
1142 }
1143 
1144 
1145 void
1146 BSlider::GetPreferredSize(float* _width, float* _height)
1147 {
1148 	font_height fontHeight;
1149 	GetFontHeight(&fontHeight);
1150 
1151 	int32 rows = 0;
1152 
1153 	if (Orientation() == B_HORIZONTAL) {
1154 		*_width = Frame().Width();
1155 		*_height = 12.0f + fBarThickness;
1156 
1157 		float labelWidth = 0;
1158 		if (Label()) {
1159 			labelWidth = StringWidth(Label());
1160 			rows++;
1161 		}
1162 
1163 		float minWidth = 0;
1164 		if (MinLimitLabel())
1165 			minWidth = StringWidth(MinLimitLabel());
1166 		if (MaxLimitLabel()) {
1167 			// some space between the labels
1168 			if (MinLimitLabel())
1169 				minWidth += 8.0f;
1170 
1171 			minWidth += StringWidth(MaxLimitLabel());
1172 		}
1173 
1174 		if (minWidth > *_width)
1175 			*_width = minWidth;
1176 		if (labelWidth > *_width)
1177 			*_width = labelWidth;
1178 		if (*_width < 32.0f)
1179 			*_width = 32.0f;
1180 
1181 		if (MinLimitLabel() || MaxLimitLabel())
1182 			rows++;
1183 
1184 		*_height += rows * ((float)ceil(fontHeight.ascent + fontHeight.descent) + 4.0f);
1185 	} else {
1186 		// B_VERTICAL
1187 		*_width = 12.0f + fBarThickness;
1188 		*_height = Frame().Height();
1189 
1190 		// find largest label
1191 
1192 		float minWidth = 0;
1193 		if (Label()) {
1194 			minWidth = StringWidth(Label());
1195 			rows++;
1196 		}
1197 		if (MinLimitLabel()) {
1198 			float width = StringWidth(MinLimitLabel());
1199 			if (width > minWidth)
1200 				minWidth = width;
1201 			rows++;
1202 		}
1203 		if (MaxLimitLabel()) {
1204 			float width = StringWidth(MaxLimitLabel());
1205 			if (width > minWidth)
1206 				minWidth = width;
1207 			rows++;
1208 		}
1209 
1210 		if (minWidth > *_width)
1211 			*_width = minWidth;
1212 
1213 		float minHeight = 32.0f + rows
1214 			* ((float)ceil(fontHeight.ascent + fontHeight.descent) + 4.0f);
1215 
1216 		if (Label() && MaxLimitLabel())
1217 			minHeight -= 4.0f;
1218 
1219 		if (minHeight > *_height)
1220 			*_height = minHeight;
1221 	}
1222 }
1223 
1224 
1225 void
1226 BSlider::ResizeToPreferred()
1227 {
1228 	BControl::ResizeToPreferred();
1229 }
1230 
1231 
1232 status_t
1233 BSlider::Invoke(BMessage *msg)
1234 {
1235 	return BControl::Invoke(msg);
1236 }
1237 
1238 
1239 BHandler*
1240 BSlider::ResolveSpecifier(BMessage *message, int32 index,
1241 						  BMessage *specifier, int32 command,
1242 						  const char *property)
1243 {
1244 	return BControl::ResolveSpecifier(message, index, specifier,
1245 									  command, property);
1246 }
1247 
1248 
1249 status_t
1250 BSlider::GetSupportedSuites(BMessage *message)
1251 {
1252 	return BControl::GetSupportedSuites(message);
1253 }
1254 
1255 
1256 void
1257 BSlider::SetModificationMessage(BMessage *message)
1258 {
1259 	if (fModificationMessage)
1260 		delete fModificationMessage;
1261 
1262 	fModificationMessage = message;
1263 }
1264 
1265 
1266 BMessage*
1267 BSlider::ModificationMessage() const
1268 {
1269 	return fModificationMessage;
1270 }
1271 
1272 
1273 void
1274 BSlider::SetSnoozeAmount(int32 snooze_time)
1275 {
1276 	if (snooze_time < 5000)
1277 		snooze_time = 5000;
1278 	if (snooze_time > 1000000)
1279 		snooze_time = 1000000;
1280 
1281 	fSnoozeAmount = snooze_time;
1282 }
1283 
1284 
1285 int32
1286 BSlider::SnoozeAmount() const
1287 {
1288 	return fSnoozeAmount;
1289 }
1290 
1291 
1292 void
1293 BSlider::SetKeyIncrementValue(int32 increment_value)
1294 {
1295 	fKeyIncrementValue = increment_value;
1296 }
1297 
1298 
1299 int32
1300 BSlider::KeyIncrementValue() const
1301 {
1302 	return fKeyIncrementValue;
1303 }
1304 
1305 
1306 void
1307 BSlider::SetHashMarkCount(int32 hash_mark_count)
1308 {
1309 	fHashMarkCount = hash_mark_count;
1310 	Invalidate();
1311 }
1312 
1313 
1314 int32
1315 BSlider::HashMarkCount() const
1316 {
1317 	return fHashMarkCount;
1318 }
1319 
1320 
1321 void
1322 BSlider::SetHashMarks(hash_mark_location where)
1323 {
1324 	fHashMarks = where;
1325 	Invalidate();
1326 }
1327 
1328 
1329 hash_mark_location
1330 BSlider::HashMarks() const
1331 {
1332 	return fHashMarks;
1333 }
1334 
1335 
1336 void
1337 BSlider::SetStyle(thumb_style style)
1338 {
1339 	fStyle = style;
1340 	Invalidate();
1341 }
1342 
1343 
1344 thumb_style
1345 BSlider::Style() const
1346 {
1347 	return fStyle;
1348 }
1349 
1350 
1351 void
1352 BSlider::SetBarColor(rgb_color bar_color)
1353 {
1354 	fBarColor = bar_color;
1355 	Invalidate();
1356 }
1357 
1358 
1359 rgb_color
1360 BSlider::BarColor() const
1361 {
1362 	return fBarColor;
1363 }
1364 
1365 
1366 void
1367 BSlider::UseFillColor(bool use_fill, const rgb_color *bar_color)
1368 {
1369 	fUseFillColor = use_fill;
1370 
1371 	if (use_fill && bar_color)
1372 		fFillColor = *bar_color;
1373 
1374 	Invalidate();
1375 }
1376 
1377 
1378 bool
1379 BSlider::FillColor(rgb_color *bar_color) const
1380 {
1381 	if (bar_color && fUseFillColor)
1382 		*bar_color = fFillColor;
1383 
1384 	return fUseFillColor;
1385 }
1386 
1387 
1388 BView*
1389 BSlider::OffscreenView() const
1390 {
1391 #if USE_OFF_SCREEN_VIEW
1392 	return fOffScreenView;
1393 #else
1394 	return (BView*)this;
1395 #endif
1396 }
1397 
1398 
1399 orientation
1400 BSlider::Orientation() const
1401 {
1402 	return fOrientation;
1403 }
1404 
1405 
1406 void
1407 BSlider::SetOrientation(orientation posture)
1408 {
1409 	fOrientation = posture;
1410 	Invalidate();
1411 }
1412 
1413 
1414 float
1415 BSlider::BarThickness() const
1416 {
1417 	return fBarThickness;
1418 }
1419 
1420 
1421 void
1422 BSlider::SetBarThickness(float thickness)
1423 {
1424 	if (thickness >= 1.0f)
1425 		fBarThickness = thickness;
1426 }
1427 
1428 
1429 void
1430 BSlider::SetFont(const BFont *font, uint32 properties)
1431 {
1432 	BControl::SetFont(font, properties);
1433 
1434 #if USE_OFF_SCREEN_VIEW
1435 	if (fOffScreenView && fOffScreenBits) {
1436 		if (fOffScreenBits->Lock()) {
1437 			fOffScreenView->SetFont(font, properties);
1438 			fOffScreenBits->Unlock();
1439 		}
1440 	}
1441 #endif
1442 }
1443 
1444 
1445 #ifdef __HAIKU__
1446 void
1447 BSlider::SetLimits(int32 minimum, int32 maximum)
1448 {
1449 	if (minimum <= maximum) {
1450 		fMinValue = minimum;
1451 		fMaxValue = maximum;
1452 
1453 		int32 value = Value();
1454 		value = max_c(minimum, value);
1455 		value = min_c(maximum, value);
1456 
1457 		if (value != Value()) {
1458 			SetValue(value);
1459 		}
1460 	}
1461 }
1462 #endif
1463 
1464 
1465 void
1466 BSlider::_DrawBlockThumb()
1467 {
1468 	BRect frame = ThumbFrame();
1469 	BView *view = OffscreenView();
1470 
1471 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
1472 	rgb_color lighten2;
1473 	rgb_color lighten1;
1474 	rgb_color darken2;
1475 	rgb_color darken3;
1476 	rgb_color darkenmax;
1477 
1478 	if (IsEnabled()) {
1479 		lighten2	= tint_color(no_tint, B_LIGHTEN_2_TINT);
1480 		lighten1	= no_tint;
1481 		darken2		= tint_color(no_tint, B_DARKEN_2_TINT);
1482 		darken3		= tint_color(no_tint, B_DARKEN_3_TINT);
1483 		darkenmax	= tint_color(no_tint, B_DARKEN_MAX_TINT);
1484 	} else {
1485 		lighten2	= tint_color(no_tint, B_LIGHTEN_2_TINT);
1486 		lighten1	= tint_color(no_tint, B_LIGHTEN_1_TINT);
1487 		darken2		= tint_color(no_tint, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
1488 		darken3		= tint_color(no_tint, B_DARKEN_1_TINT);
1489 		darkenmax	= tint_color(no_tint, B_DARKEN_3_TINT);
1490 	}
1491 
1492 	// blank background for shadow
1493 	// ToDo: this also draws over the hash marks (though it's not *that* noticeable)
1494 	view->SetHighColor(no_tint);
1495 	view->StrokeLine(BPoint(frame.left, frame.top),
1496 					 BPoint(frame.left, frame.top));
1497 
1498 	BRect barFrame = BarFrame();
1499 	if (barFrame.right >= frame.right) {
1500 		// leave out barFrame from shadow background clearing
1501 		view->StrokeLine(BPoint(frame.right, frame.top),
1502 						 BPoint(frame.right, barFrame.top - 1.0f));
1503 		view->StrokeLine(BPoint(frame.right, barFrame.bottom + 1.0f),
1504 						 BPoint(frame.right, frame.bottom));
1505 	} else {
1506 		view->StrokeLine(BPoint(frame.right, frame.top),
1507 						 BPoint(frame.right, frame.bottom));
1508 	}
1509 
1510 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1511 					 BPoint(frame.right - 1.0f, frame.bottom));
1512 	view->StrokeLine(BPoint(frame.left, frame.bottom - 1.0f),
1513 					 BPoint(frame.left, frame.bottom - 1.0f));
1514 	view->StrokeLine(BPoint(frame.right - 1.0f, frame.top),
1515 					 BPoint(frame.right - 1.0f, frame.top));
1516 
1517 	// Outline (top, left)
1518 	view->SetHighColor(darken3);
1519 	view->StrokeLine(BPoint(frame.left, frame.bottom - 2.0f),
1520 					 BPoint(frame.left, frame.top + 1.0f));
1521 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
1522 					 BPoint(frame.right - 2.0f, frame.top));
1523 
1524 	// Shadow
1525 	view->SetHighColor(0, 0, 0, IsEnabled() ? 100 : 50);
1526 	view->SetDrawingMode(B_OP_ALPHA);
1527 	view->StrokeLine(BPoint(frame.right, frame.top + 2.0f),
1528 					 BPoint(frame.right, frame.bottom - 1.0f));
1529 	view->StrokeLine(BPoint(frame.left + 2.0f, frame.bottom),
1530 					 BPoint(frame.right - 1.0f, frame.bottom));
1531 
1532 	view->SetDrawingMode(B_OP_COPY);
1533 	view->SetHighColor(darken3);
1534 	view->StrokeLine(BPoint(frame.right - 1.0f, frame.bottom - 1.0f),
1535 					 BPoint(frame.right - 1.0f, frame.bottom - 1.0f));
1536 
1537 
1538 	// First bevel
1539 	frame.InsetBy(1.0f, 1.0f);
1540 
1541 	view->SetHighColor(darkenmax);
1542 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1543 					 BPoint(frame.right - 1.0f, frame.bottom));
1544 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
1545 					 BPoint(frame.right, frame.top));
1546 
1547 	view->SetHighColor(lighten2);
1548 	view->StrokeLine(BPoint(frame.left, frame.top),
1549 					 BPoint(frame.left, frame.bottom - 1.0f));
1550 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
1551 					 BPoint(frame.right - 1.0f, frame.top));
1552 
1553 	frame.InsetBy(1.0f, 1.0f);
1554 
1555 	view->FillRect(BRect(frame.left, frame.top, frame.right - 1.0f, frame.bottom - 1.0f));
1556 
1557 	// Second bevel and center dots
1558 	view->SetHighColor(darken2);
1559 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1560 					 BPoint(frame.right, frame.bottom));
1561 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
1562 					 BPoint(frame.right, frame.top));
1563 
1564 	if (Orientation() == B_HORIZONTAL) {
1565 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 2.0f),
1566 						 BPoint(frame.left + 6.0f, frame.top + 2.0f));
1567 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 4.0f),
1568 						 BPoint(frame.left + 6.0f, frame.top + 4.0f));
1569 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 6.0f),
1570 						 BPoint(frame.left + 6.0f, frame.top + 6.0f));
1571 	} else {
1572 		view->StrokeLine(BPoint(frame.left + 2.0f, frame.top + 6.0f),
1573 						 BPoint(frame.left + 2.0f, frame.top + 6.0f));
1574 		view->StrokeLine(BPoint(frame.left + 4.0f, frame.top + 6.0f),
1575 						 BPoint(frame.left + 4.0f, frame.top + 6.0f));
1576 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 6.0f),
1577 						 BPoint(frame.left + 6.0f, frame.top + 6.0f));
1578 	}
1579 
1580 	frame.InsetBy(1.0f, 1.0f);
1581 
1582 	// Third bevel
1583 	view->SetHighColor(lighten1);
1584 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1585 					 BPoint(frame.right, frame.bottom));
1586 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
1587 					 BPoint(frame.right, frame.top));
1588 }
1589 
1590 
1591 void
1592 BSlider::_DrawTriangleThumb()
1593 {
1594 	BRect frame = ThumbFrame();
1595 	BView *view = OffscreenView();
1596 
1597 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
1598 	rgb_color lightenmax;
1599 	rgb_color lighten1;
1600 	rgb_color darken2;
1601 	rgb_color darken3;
1602 	rgb_color darkenmax;
1603 
1604 	if (IsEnabled()) {
1605 		lightenmax	= tint_color(no_tint, B_LIGHTEN_MAX_TINT);
1606 		lighten1	= no_tint;
1607 		darken2		= tint_color(no_tint, B_DARKEN_2_TINT);
1608 		darken3		= tint_color(no_tint, B_DARKEN_3_TINT);
1609 		darkenmax	= tint_color(no_tint, B_DARKEN_MAX_TINT);
1610 	} else {
1611 		lightenmax	= tint_color(no_tint, B_LIGHTEN_2_TINT);
1612 		lighten1	= tint_color(no_tint, B_LIGHTEN_1_TINT);
1613 		darken2		= tint_color(no_tint, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
1614 		darken3		= tint_color(no_tint, B_DARKEN_1_TINT);
1615 		darkenmax	= tint_color(no_tint, B_DARKEN_3_TINT);
1616 	}
1617 
1618 	view->SetDrawingMode(B_OP_OVER);
1619 
1620 	if (Orientation() == B_HORIZONTAL) {
1621 		view->SetHighColor(lighten1);
1622 		view->FillTriangle(BPoint(frame.left + 1.0, frame.bottom - 2.0),
1623 						   BPoint(frame.left + 6.0, frame.top + 1.0),
1624 						   BPoint(frame.right - 1.0, frame.bottom - 2.0));
1625 
1626 		view->SetHighColor(no_tint);
1627 		view->StrokeLine(BPoint(frame.right - 2.0, frame.bottom - 2.0),
1628 						 BPoint(frame.left + 3.0, frame.bottom - 2.0));
1629 
1630 		view->SetHighColor(darkenmax);
1631 		view->StrokeLine(BPoint(frame.left, frame.bottom),
1632 						 BPoint(frame.right, frame.bottom));
1633 		view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0),
1634 						 BPoint(frame.left + 6.0, frame.top + 1.0));
1635 
1636 		view->SetHighColor(darken2);
1637 		view->StrokeLine(BPoint(frame.right - 1.0, frame.bottom - 1.0),
1638 						 BPoint(frame.left + 1.0, frame.bottom - 1.0));
1639 		view->SetHighColor(darken3);
1640 		view->StrokeLine(BPoint(frame.left, frame.bottom - 1.0),
1641 						 BPoint(frame.left + 5.0, frame.top + 2.0));
1642 
1643 		view->SetHighColor(lightenmax);
1644 		view->StrokeLine(BPoint(frame.left + 2.0, frame.bottom - 2.0),
1645 						 BPoint(frame.left + 6.0, frame.top + 2.0));
1646 	} else {
1647 		view->SetHighColor(lighten1);
1648 		view->FillTriangle(BPoint(frame.left + 1.0f, frame.top),
1649 			BPoint(frame.left + 7.0f, frame.top + 6.0f),
1650 			BPoint(frame.left + 1.0f, frame.bottom));
1651 
1652 		view->SetHighColor(darkenmax);
1653 		view->StrokeLine(BPoint(frame.left, frame.top + 1),
1654 			BPoint(frame.left, frame.bottom));
1655 		view->StrokeLine(BPoint(frame.left + 1.0f, frame.bottom),
1656 			BPoint(frame.left + 7.0f, frame.top + 6.0f));
1657 
1658 		view->SetHighColor(darken2);
1659 		view->StrokeLine(BPoint(frame.left, frame.top),
1660 			BPoint(frame.left, frame.bottom - 1));
1661 		view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
1662 			BPoint(frame.left + 6.0f, frame.top + 5.0f));
1663 
1664 		view->SetHighColor(no_tint);
1665 		view->StrokeLine(BPoint(frame.left + 1.0f, frame.top + 2.0f),
1666 			BPoint(frame.left + 1.0f, frame.bottom - 1.0f));
1667 		view->StrokeLine(BPoint(frame.left + 2.0f, frame.bottom - 2.0f),
1668 			BPoint(frame.left + 6.0f, frame.top + 6.0f));
1669 	}
1670 
1671 	view->SetDrawingMode(B_OP_COPY);
1672 }
1673 
1674 
1675 BPoint
1676 BSlider::_Location() const
1677 {
1678 	return fLocation;
1679 }
1680 
1681 
1682 void
1683 BSlider::_SetLocation(BPoint p)
1684 {
1685 	fLocation = p;
1686 }
1687 
1688 
1689 float
1690 BSlider::_MinPosition() const
1691 {
1692 	if (fOrientation == B_HORIZONTAL)
1693 		return BarFrame().left + 1.0f;
1694 	else
1695 		return BarFrame().bottom - 1.0f;
1696 }
1697 
1698 
1699 float
1700 BSlider::_MaxPosition() const
1701 {
1702 	if (fOrientation == B_HORIZONTAL)
1703 		return BarFrame().right - 1.0f;
1704 	else
1705 		return BarFrame().top + 1.0f;
1706 }
1707 
1708 
1709 extern "C"
1710 void _ReservedSlider4__7BSlider(BSlider *slider, int32 minimum, int32 maximum)
1711 {
1712 #ifdef __HAIKU__
1713 	slider->SetLimits(minimum, maximum);
1714 #endif
1715 }
1716 
1717 
1718 void BSlider::_ReservedSlider5() {}
1719 void BSlider::_ReservedSlider6() {}
1720 void BSlider::_ReservedSlider7() {}
1721 void BSlider::_ReservedSlider8() {}
1722 void BSlider::_ReservedSlider9() {}
1723 void BSlider::_ReservedSlider10() {}
1724 void BSlider::_ReservedSlider11() {}
1725 void BSlider::_ReservedSlider12() {}
1726 
1727 
1728 BSlider &
1729 BSlider::operator=(const BSlider &)
1730 {
1731 	return *this;
1732 }
1733 
1734