xref: /haiku/src/kits/interface/Slider.cpp (revision c9ad965c81b08802fed0827fd1dd16f45297928a)
1 /*
2  * Copyright 2001-2009, 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 <Slider.h>
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include <Bitmap.h>
19 #include <ControlLook.h>
20 #include <Errors.h>
21 #include <LayoutUtils.h>
22 #include <Message.h>
23 #include <Region.h>
24 #include <String.h>
25 #include <Window.h>
26 
27 #include <binary_compatibility/Interface.h>
28 
29 
30 #define USE_OFF_SCREEN_VIEW 1
31 
32 
33 BSlider::BSlider(BRect frame, const char* name, const char* label,
34 			BMessage* message, int32 minValue, int32 maxValue,
35 			thumb_style thumbType, uint32 resizingMode, uint32 flags)
36 	: BControl(frame, name, label, message, resizingMode, flags),
37 	fModificationMessage(NULL),
38 	fSnoozeAmount(20000),
39 
40 	fMinLimitLabel(NULL),
41 	fMaxLimitLabel(NULL),
42 
43 	fMinValue(minValue),
44 	fMaxValue(maxValue),
45 	fKeyIncrementValue(1),
46 
47 	fHashMarkCount(0),
48 	fHashMarks(B_HASH_MARKS_NONE),
49 
50 	fStyle(thumbType),
51 
52 	fOrientation(B_HORIZONTAL),
53 	fBarThickness(6.0)
54 {
55 	_InitBarColor();
56 
57 	_InitObject();
58 	SetValue(0);
59 }
60 
61 
62 BSlider::BSlider(BRect frame, const char *name, const char *label,
63 			BMessage *message, int32 minValue, int32 maxValue,
64 			orientation posture, thumb_style thumbType, uint32 resizingMode,
65 			uint32 flags)
66 	: BControl(frame, name, label, message, resizingMode, flags),
67 	fModificationMessage(NULL),
68 	fSnoozeAmount(20000),
69 
70 	fMinLimitLabel(NULL),
71 	fMaxLimitLabel(NULL),
72 
73 	fMinValue(minValue),
74 	fMaxValue(maxValue),
75 	fKeyIncrementValue(1),
76 
77 	fHashMarkCount(0),
78 	fHashMarks(B_HASH_MARKS_NONE),
79 
80 	fStyle(thumbType),
81 
82 	fOrientation(posture),
83 	fBarThickness(6.0)
84 {
85 	_InitBarColor();
86 
87 	_InitObject();
88 	SetValue(0);
89 }
90 
91 
92 BSlider::BSlider(const char *name, const char *label, BMessage *message,
93 			int32 minValue, int32 maxValue, orientation posture,
94 			thumb_style thumbType, uint32 flags)
95 	: BControl(name, label, message, flags),
96 	fModificationMessage(NULL),
97 	fSnoozeAmount(20000),
98 
99 	fMinLimitLabel(NULL),
100 	fMaxLimitLabel(NULL),
101 
102 	fMinValue(minValue),
103 	fMaxValue(maxValue),
104 	fKeyIncrementValue(1),
105 
106 	fHashMarkCount(0),
107 	fHashMarks(B_HASH_MARKS_NONE),
108 
109 	fStyle(thumbType),
110 
111 	fOrientation(posture),
112 	fBarThickness(6.0)
113 {
114 	_InitBarColor();
115 
116 	_InitObject();
117 	SetValue(0);
118 }
119 
120 
121 BSlider::BSlider(BMessage *archive)
122 	: BControl(archive)
123 {
124 	fModificationMessage = NULL;
125 
126 	if (archive->HasMessage("_mod_msg")) {
127 		BMessage* message = new BMessage;
128 
129 		archive->FindMessage("_mod_msg", message);
130 
131 		SetModificationMessage(message);
132 	}
133 
134 	if (archive->FindInt32("_sdelay", &fSnoozeAmount) != B_OK)
135 		SetSnoozeAmount(20000);
136 
137 	rgb_color color;
138 	if (archive->FindInt32("_fcolor", (int32 *)&color) == B_OK)
139 		UseFillColor(true, &color);
140 	else
141 		UseFillColor(false);
142 
143 	int32 orient;
144 	if (archive->FindInt32("_orient", &orient) == B_OK)
145 		fOrientation = (orientation)orient;
146 	else
147 		fOrientation = B_HORIZONTAL;
148 
149 	fMinLimitLabel = NULL;
150 	fMaxLimitLabel = NULL;
151 
152 	const char* minlbl = NULL;
153 	const char* maxlbl = NULL;
154 
155 	archive->FindString("_minlbl", &minlbl);
156 	archive->FindString("_maxlbl", &maxlbl);
157 
158 	SetLimitLabels(minlbl, maxlbl);
159 
160 	if (archive->FindInt32("_min", &fMinValue) != B_OK)
161 		fMinValue = 0;
162 
163 	if (archive->FindInt32("_max", &fMaxValue) != B_OK)
164 		fMaxValue = 100;
165 
166 	if (archive->FindInt32("_incrementvalue", &fKeyIncrementValue) != B_OK)
167 		fKeyIncrementValue = 1;
168 
169 	if (archive->FindInt32("_hashcount", &fHashMarkCount) != B_OK)
170 		fHashMarkCount = 11;
171 
172 	int16 hashloc;
173 	if (archive->FindInt16("_hashloc", &hashloc) == B_OK)
174 		fHashMarks = (hash_mark_location)hashloc;
175 	else
176 		fHashMarks = B_HASH_MARKS_NONE;
177 
178 	int16 sstyle;
179 	if (archive->FindInt16("_sstyle", &sstyle) == B_OK)
180 		fStyle = (thumb_style)sstyle;
181 	else
182 		fStyle = B_BLOCK_THUMB;
183 
184 	if (archive->FindInt32("_bcolor", (int32 *)&color) != B_OK)
185 		color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_4_TINT);
186 	SetBarColor(color);
187 
188 	float bthickness;
189 	if (archive->FindFloat("_bthickness", &bthickness) == B_OK)
190 		fBarThickness = bthickness;
191 	else
192 		fBarThickness = 6.0f;
193 
194 	_InitObject();
195 }
196 
197 
198 BSlider::~BSlider()
199 {
200 #if USE_OFF_SCREEN_VIEW
201 	delete fOffScreenBits;
202 #endif
203 
204 	delete fModificationMessage;
205 	free(fMinLimitLabel);
206 	free(fMaxLimitLabel);
207 }
208 
209 
210 void
211 BSlider::_InitBarColor()
212 {
213 	if (be_control_look != NULL) {
214 		SetBarColor(be_control_look->SliderBarColor(
215 			ui_color(B_PANEL_BACKGROUND_COLOR)));
216 	} else {
217 		SetBarColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
218 			B_DARKEN_4_TINT));
219 	}
220 
221 	UseFillColor(false, NULL);
222 }
223 
224 
225 void
226 BSlider::_InitObject()
227 {
228 	fLocation.x = 0;
229 	fLocation.y = 0;
230 	fInitialLocation.x = 0;
231 	fInitialLocation.y = 0;
232 
233 #if USE_OFF_SCREEN_VIEW
234 	fOffScreenBits = NULL;
235 	fOffScreenView = NULL;
236 #endif
237 
238 	fUpdateText = NULL;
239 	fMinSize.Set(-1, -1);
240 	fMaxUpdateTextWidth = -1.0;
241 }
242 
243 
244 BArchivable*
245 BSlider::Instantiate(BMessage *archive)
246 {
247 	if (validate_instantiation(archive, "BSlider"))
248 		return new BSlider(archive);
249 
250 	return NULL;
251 }
252 
253 
254 status_t
255 BSlider::Archive(BMessage *archive, bool deep) const
256 {
257 	status_t ret = BControl::Archive(archive, deep);
258 
259 	if (ModificationMessage() && ret == B_OK)
260 		ret = archive->AddMessage("_mod_msg", ModificationMessage());
261 
262 	if (ret == B_OK)
263 		ret = archive->AddInt32("_sdelay", fSnoozeAmount);
264 	if (ret == B_OK)
265 		ret = archive->AddInt32("_bcolor", (const uint32 &)fBarColor);
266 
267 	if (FillColor(NULL) && ret == B_OK)
268 		ret = archive->AddInt32("_fcolor", (const uint32 &)fFillColor);
269 
270 	if (ret == B_OK && fMinLimitLabel)
271 		ret = archive->AddString("_minlbl", fMinLimitLabel);
272 
273 	if (ret == B_OK && fMaxLimitLabel)
274 		ret = archive->AddString("_maxlbl", fMaxLimitLabel);
275 
276 	if (ret == B_OK)
277 		ret = archive->AddInt32("_min", fMinValue);
278 	if (ret == B_OK)
279 		ret = archive->AddInt32("_max", fMaxValue);
280 
281 	if (ret == B_OK)
282 		ret = archive->AddInt32("_incrementvalue", fKeyIncrementValue);
283 	if (ret == B_OK)
284 		ret = archive->AddInt32("_hashcount", fHashMarkCount);
285 	if (ret == B_OK)
286 		ret = archive->AddInt16("_hashloc", fHashMarks);
287 	if (ret == B_OK)
288 		ret = archive->AddInt16("_sstyle", fStyle);
289 	if (ret == B_OK)
290 		ret = archive->AddInt32("_orient", fOrientation);
291 	if (ret == B_OK)
292 		ret = archive->AddFloat("_bthickness", fBarThickness);
293 
294 	return ret;
295 }
296 
297 
298 status_t
299 BSlider::Perform(perform_code code, void* _data)
300 {
301 	switch (code) {
302 		case PERFORM_CODE_MIN_SIZE:
303 			((perform_data_min_size*)_data)->return_value
304 				= BSlider::MinSize();
305 			return B_OK;
306 		case PERFORM_CODE_MAX_SIZE:
307 			((perform_data_max_size*)_data)->return_value
308 				= BSlider::MaxSize();
309 			return B_OK;
310 		case PERFORM_CODE_PREFERRED_SIZE:
311 			((perform_data_preferred_size*)_data)->return_value
312 				= BSlider::PreferredSize();
313 			return B_OK;
314 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
315 			((perform_data_layout_alignment*)_data)->return_value
316 				= BSlider::LayoutAlignment();
317 			return B_OK;
318 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
319 			((perform_data_has_height_for_width*)_data)->return_value
320 				= BSlider::HasHeightForWidth();
321 			return B_OK;
322 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
323 		{
324 			perform_data_get_height_for_width* data
325 				= (perform_data_get_height_for_width*)_data;
326 			BSlider::GetHeightForWidth(data->width, &data->min, &data->max,
327 				&data->preferred);
328 			return B_OK;
329 		}
330 		case PERFORM_CODE_SET_LAYOUT:
331 		{
332 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
333 			BSlider::SetLayout(data->layout);
334 			return B_OK;
335 		}
336 		case PERFORM_CODE_INVALIDATE_LAYOUT:
337 		{
338 			perform_data_invalidate_layout* data
339 				= (perform_data_invalidate_layout*)_data;
340 			BSlider::InvalidateLayout(data->descendants);
341 			return B_OK;
342 		}
343 		case PERFORM_CODE_DO_LAYOUT:
344 		{
345 			BSlider::DoLayout();
346 			return B_OK;
347 		}
348 	}
349 
350 	return BControl::Perform(code, _data);
351 }
352 
353 
354 void
355 BSlider::WindowActivated(bool state)
356 {
357 	BControl::WindowActivated(state);
358 }
359 
360 
361 void
362 BSlider::AttachedToWindow()
363 {
364 	ResizeToPreferred();
365 
366 	fLocation.Set(9.0f, 0.0f);
367 	fUpdateText = UpdateText();
368 
369 #if USE_OFF_SCREEN_VIEW
370 	BRect bounds(Bounds());
371 
372 	if (!fOffScreenView) {
373 		fOffScreenView = new BView(bounds, "", B_FOLLOW_ALL, B_WILL_DRAW);
374 
375 		BFont font;
376 		GetFont(&font);
377 		fOffScreenView->SetFont(&font);
378 	}
379 
380 	if (!fOffScreenBits) {
381 		fOffScreenBits = new BBitmap(bounds, B_RGBA32, true, false);
382 
383 		if (fOffScreenBits && fOffScreenView)
384 			fOffScreenBits->AddChild(fOffScreenView);
385 
386 	} else if (fOffScreenView)
387 		fOffScreenBits->AddChild(fOffScreenView);
388 #endif // USE_OFF_SCREEN_VIEW
389 
390 	BControl::AttachedToWindow();
391 
392 	BView* view = OffscreenView();
393 	if (view && view->LockLooper()) {
394 		view->SetViewColor(B_TRANSPARENT_COLOR);
395 		view->SetLowColor(ViewColor());
396 		view->UnlockLooper();
397 	}
398 
399 	SetValue(Value());
400 		// makes sure the value is within valid bounds
401 }
402 
403 
404 void
405 BSlider::AllAttached()
406 {
407 	BControl::AllAttached();
408 }
409 
410 
411 void
412 BSlider::AllDetached()
413 {
414 	BControl::AllDetached();
415 }
416 
417 
418 void
419 BSlider::DetachedFromWindow()
420 {
421 	BControl::DetachedFromWindow();
422 
423 #if USE_OFF_SCREEN_VIEW
424 	if (fOffScreenBits) {
425 		delete fOffScreenBits;
426 		fOffScreenBits = NULL;
427 		fOffScreenView = NULL;
428 	}
429 #endif
430 }
431 
432 
433 void
434 BSlider::MessageReceived(BMessage *msg)
435 {
436 	BControl::MessageReceived(msg);
437 }
438 
439 
440 void
441 BSlider::FrameMoved(BPoint new_position)
442 {
443 	BControl::FrameMoved(new_position);
444 }
445 
446 
447 void
448 BSlider::FrameResized(float w,float h)
449 {
450 	BControl::FrameResized(w, h);
451 
452 	BRect bounds(Bounds());
453 
454 	if (bounds.right <= 0.0f || bounds.bottom <= 0.0f)
455 		return;
456 
457 #if USE_OFF_SCREEN_VIEW
458 	if (fOffScreenBits) {
459 		fOffScreenBits->RemoveChild(fOffScreenView);
460 		delete fOffScreenBits;
461 
462 		fOffScreenView->ResizeTo(bounds.Width(), bounds.Height());
463 
464 		fOffScreenBits = new BBitmap(Bounds(), B_RGBA32, true, false);
465 		fOffScreenBits->AddChild(fOffScreenView);
466 	}
467 #endif
468 
469 	Invalidate();
470 }
471 
472 
473 void
474 BSlider::KeyDown(const char *bytes, int32 numBytes)
475 {
476 	if (!IsEnabled() || IsHidden())
477 		return;
478 
479 	int32 newValue = Value();
480 
481 	switch (bytes[0]) {
482 		case B_LEFT_ARROW:
483 		case B_DOWN_ARROW: {
484 			newValue -= KeyIncrementValue();
485 			break;
486 		}
487 		case B_RIGHT_ARROW:
488 		case B_UP_ARROW: {
489 			newValue += KeyIncrementValue();
490 			break;
491 		}
492 		case B_HOME:
493 			newValue = fMinValue;
494 			break;
495 		case B_END:
496 			newValue = fMaxValue;
497 			break;
498 		default:
499 			BControl::KeyDown(bytes, numBytes);
500 			return;
501 	}
502 
503 	if (newValue != Value()) {
504 		SetValue(newValue);
505 		InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
506 	}
507 }
508 
509 
510 /*!
511 	Makes sure the \a point is within valid bounds.
512 	Returns \c true if the relevant coordinate (depending on the orientation
513 	of the slider) differs from \a comparePoint.
514 */
515 bool
516 BSlider::_ConstrainPoint(BPoint& point, BPoint comparePoint) const
517 {
518 	if (fOrientation == B_HORIZONTAL) {
519 		if (point.x != comparePoint.x) {
520 			if (point.x < _MinPosition())
521 				point.x = _MinPosition();
522 			else if (point.x > _MaxPosition())
523 				point.x = _MaxPosition();
524 
525 			return true;
526 		}
527 	} else {
528 		if (point.y != comparePoint.y) {
529 			if (point.y > _MinPosition())
530 				point.y = _MinPosition();
531 			else if (point.y < _MaxPosition())
532 				point.y = _MaxPosition();
533 
534 			return true;
535 		}
536 	}
537 
538 	return false;
539 }
540 
541 
542 void
543 BSlider::MouseDown(BPoint point)
544 {
545 	if (!IsEnabled())
546 		return;
547 
548 	if (BarFrame().Contains(point) || ThumbFrame().Contains(point))
549 		fInitialLocation = _Location();
550 
551 	uint32 buttons;
552 	GetMouse(&point, &buttons, true);
553 
554 	_ConstrainPoint(point, fInitialLocation);
555 	SetValue(ValueForPoint(point));
556 
557 	if (_Location() != fInitialLocation)
558 		InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
559 
560 	if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
561 		SetTracking(true);
562 		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
563 	} else {
564 		// synchronous mouse tracking
565 		BPoint prevPoint;
566 
567 		while (buttons) {
568 			prevPoint = point;
569 
570 			snooze(SnoozeAmount());
571 			GetMouse(&point, &buttons, true);
572 
573 			if (_ConstrainPoint(point, prevPoint)) {
574 				int32 value = ValueForPoint(point);
575 				if (value != Value()) {
576 					SetValue(value);
577 					InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
578 				}
579 			}
580 		}
581 		if (_Location() != fInitialLocation)
582 			Invoke();
583 	}
584 }
585 
586 
587 void
588 BSlider::MouseUp(BPoint point)
589 {
590 	if (IsTracking()) {
591 		if (_Location() != fInitialLocation)
592 			Invoke();
593 
594 		SetTracking(false);
595 	} else
596 		BControl::MouseUp(point);
597 }
598 
599 
600 void
601 BSlider::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
602 {
603 	if (IsTracking()) {
604 		if (_ConstrainPoint(point, _Location())) {
605 			int32 value = ValueForPoint(point);
606 			if (value != Value()) {
607 				SetValue(value);
608 				InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
609 			}
610 		}
611 	} else
612 		BControl::MouseMoved(point, transit, message);
613 }
614 
615 
616 void
617 BSlider::Pulse()
618 {
619 	BControl::Pulse();
620 }
621 
622 
623 void
624 BSlider::SetLabel(const char *label)
625 {
626 	BControl::SetLabel(label);
627 }
628 
629 
630 void
631 BSlider::SetLimitLabels(const char *minLabel, const char *maxLabel)
632 {
633 	free(fMinLimitLabel);
634 	fMinLimitLabel = minLabel ? strdup(minLabel) : NULL;
635 
636 	free(fMaxLimitLabel);
637 	fMaxLimitLabel = maxLabel ? strdup(maxLabel) : NULL;
638 
639 	InvalidateLayout();
640 
641 	// TODO: This is for backwards compatibility and should
642 	// probably be removed when breaking binary compatiblity.
643 	// Applications like our own Mouse rely on this behavior.
644 	if ((Flags() & B_SUPPORTS_LAYOUT) == 0)
645 		ResizeToPreferred();
646 
647 	Invalidate();
648 }
649 
650 
651 const char*
652 BSlider::MinLimitLabel() const
653 {
654 	return fMinLimitLabel;
655 }
656 
657 
658 const char*
659 BSlider::MaxLimitLabel() const
660 {
661 	return fMaxLimitLabel;
662 }
663 
664 
665 void
666 BSlider::SetValue(int32 value)
667 {
668 	if (value < fMinValue)
669 		value = fMinValue;
670 	if (value > fMaxValue)
671 		value = fMaxValue;
672 
673 	if (value == Value())
674 		return;
675 
676 	BPoint loc;
677 	float range = (float)(fMaxValue - fMinValue);
678 	if (range == 0)
679 		range = 1;
680 
681 	float pos = (float)(value - fMinValue) / range *
682 		(_MaxPosition() - _MinPosition());
683 
684 	if (fOrientation == B_HORIZONTAL) {
685 		loc.x = ceil(_MinPosition() + pos);
686 		loc.y = 0;
687 	} else {
688 		loc.x = 0;
689 		loc.y = floor(_MaxPosition() - pos);
690 	}
691 
692 	BRect oldThumbFrame = ThumbFrame();
693 
694 	// While it would be enough to do this dependent on fUseFillColor,
695 	// that doesn't work out if DrawBar() has been overridden by a sub class
696 	if (fOrientation == B_HORIZONTAL)
697 		oldThumbFrame.top = BarFrame().top;
698 	else
699 		oldThumbFrame.right = BarFrame().right;
700 
701 	_SetLocation(loc);
702 
703 	BControl::SetValueNoUpdate(value);
704 	BRect invalid = oldThumbFrame | ThumbFrame();
705 
706 	if (Style() == B_TRIANGLE_THUMB) {
707 		// 1) we need to take care of pixels touched because of
708 		//    anti-aliasing
709 		// 2) we need to update the region with the focus mark as well
710 		//    (a method BSlider::FocusMarkFrame() would be nice as well)
711 		if (fOrientation == B_HORIZONTAL) {
712 			if (IsFocus())
713 				invalid.bottom += 2;
714 			invalid.InsetBy(-1, 0);
715 		} else {
716 			if (IsFocus())
717 				invalid.left -= 2;
718 			invalid.InsetBy(0, -1);
719 		}
720 	}
721 
722 	Invalidate(invalid);
723 
724 	UpdateTextChanged();
725 }
726 
727 
728 int32
729 BSlider::ValueForPoint(BPoint location) const
730 {
731 	float min;
732 	float max;
733 	float position;
734 	if (fOrientation == B_HORIZONTAL) {
735 		min = _MinPosition();
736 		max = _MaxPosition();
737 		position = location.x;
738 	} else {
739 		max = _MinPosition();
740 		min = _MaxPosition();
741 		position = min + (max - location.y);
742 	}
743 
744 	if (position < min)
745 		position = min;
746 	if (position > max)
747 		position = max;
748 
749 	return (int32)roundf(((position - min) * (fMaxValue - fMinValue) / (max - min)) + fMinValue);
750 }
751 
752 
753 void
754 BSlider::SetPosition(float position)
755 {
756 	if (position <= 0.0f)
757 		BControl::SetValue(fMinValue);
758 	else if (position >= 1.0f)
759 		BControl::SetValue(fMaxValue);
760 	else
761 		BControl::SetValue((int32)(position * (fMaxValue - fMinValue) + fMinValue));
762 }
763 
764 
765 float
766 BSlider::Position() const
767 {
768 	float range = (float)(fMaxValue - fMinValue);
769 	if (range == 0.0f)
770 		range = 1.0f;
771 
772 	return (float)(Value() - fMinValue) / range;
773 }
774 
775 
776 void
777 BSlider::SetEnabled(bool on)
778 {
779 	BControl::SetEnabled(on);
780 }
781 
782 
783 void
784 BSlider::GetLimits(int32 *minimum, int32 *maximum) const
785 {
786 	if (minimum != NULL)
787 		*minimum = fMinValue;
788 	if (maximum != NULL)
789 		*maximum = fMaxValue;
790 }
791 
792 
793 // #pragma mark - drawing
794 
795 
796 void
797 BSlider::Draw(BRect updateRect)
798 {
799 	// clear out background
800 	BRegion background(updateRect);
801 	background.Exclude(BarFrame());
802 
803 	// ToDo: the triangle thumb doesn't delete its background, so we still have
804 	// to do it Note, this also creates a different behaviour for subclasses,
805 	// depending on the thumb style - if possible this should be avoided.
806 	if (Style() == B_BLOCK_THUMB) {
807 		BRect thumbFrame = ThumbFrame();
808 		if (be_control_look != NULL) {
809 			// fill background where shadow will be...
810 			// TODO: Such drawint dependent behavior should be moved into
811 			// BControlLook of course.
812 			thumbFrame.right--;
813 			thumbFrame.bottom--;
814 		}
815 		background.Exclude(thumbFrame);
816 	}
817 
818 #if USE_OFF_SCREEN_VIEW
819 	if (!fOffScreenBits)
820 		return;
821 
822 	if (fOffScreenBits->Lock()) {
823 		fOffScreenView->SetViewColor(ViewColor());
824 		fOffScreenView->SetLowColor(ViewColor());
825 #endif
826 
827 		if (background.Frame().IsValid())
828 			OffscreenView()->FillRegion(&background, B_SOLID_LOW);
829 
830 #if USE_OFF_SCREEN_VIEW
831 		fOffScreenView->Sync();
832 		fOffScreenBits->Unlock();
833 	}
834 #endif
835 
836 	DrawSlider();
837 }
838 
839 
840 void
841 BSlider::DrawSlider()
842 {
843 	if (LockLooper()) {
844 #if USE_OFF_SCREEN_VIEW
845 		if (!fOffScreenBits)
846 			return;
847 		if (fOffScreenBits->Lock()) {
848 #endif
849 			DrawBar();
850 			DrawHashMarks();
851 			DrawThumb();
852 			DrawFocusMark();
853 			DrawText();
854 
855 #if USE_OFF_SCREEN_VIEW
856 			fOffScreenView->Sync();
857 			fOffScreenBits->Unlock();
858 
859 			DrawBitmap(fOffScreenBits, B_ORIGIN);
860 		}
861 #endif
862 		UnlockLooper();
863 	}
864 }
865 
866 
867 void
868 BSlider::DrawBar()
869 {
870 	BRect frame = BarFrame();
871 	BView *view = OffscreenView();
872 
873 	if (be_control_look != NULL) {
874 		uint32 flags = be_control_look->Flags(this);
875 		rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
876 		rgb_color rightFillColor = fBarColor;
877 		rgb_color leftFillColor = fUseFillColor ? fFillColor : fBarColor;
878 		be_control_look->DrawSliderBar(view, frame, frame, base, leftFillColor,
879 			rightFillColor, Position(), flags, fOrientation);
880 		return;
881 	}
882 
883 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
884 	rgb_color lightenmax;
885 	rgb_color darken1;
886 	rgb_color darken2;
887 	rgb_color darkenmax;
888 
889 	rgb_color barColor;
890 	rgb_color fillColor;
891 
892 	if (IsEnabled()) {
893 		lightenmax	= tint_color(no_tint, B_LIGHTEN_MAX_TINT);
894 		darken1		= tint_color(no_tint, B_DARKEN_1_TINT);
895 		darken2		= tint_color(no_tint, B_DARKEN_2_TINT);
896 		darkenmax	= tint_color(no_tint, B_DARKEN_MAX_TINT);
897 		barColor	= fBarColor;
898 		fillColor	= fFillColor;
899 	} else {
900 		lightenmax	= tint_color(no_tint, B_LIGHTEN_MAX_TINT);
901 		darken1		= no_tint;
902 		darken2		= tint_color(no_tint, B_DARKEN_1_TINT);
903 		darkenmax	= tint_color(no_tint, B_DARKEN_3_TINT);
904 
905 		barColor.red	= (fBarColor.red + no_tint.red) / 2;
906 		barColor.green	= (fBarColor.green + no_tint.green) / 2;
907 		barColor.blue	= (fBarColor.blue + no_tint.blue) / 2;
908 		barColor.alpha	= 255;
909 
910 		fillColor.red	= (fFillColor.red + no_tint.red) / 2;
911 		fillColor.green	= (fFillColor.green + no_tint.green) / 2;
912 		fillColor.blue	= (fFillColor.blue + no_tint.blue) / 2;
913 		fillColor.alpha	= 255;
914 	}
915 
916 	// exclude the block thumb from the bar filling
917 
918 	BRect lowerFrame = frame.InsetByCopy(1, 1);
919 	lowerFrame.top++;
920 	lowerFrame.left++;
921 	BRect upperFrame = lowerFrame;
922 	BRect thumbFrame;
923 
924 	if (Style() == B_BLOCK_THUMB) {
925 		thumbFrame = ThumbFrame();
926 
927 		if (fOrientation == B_HORIZONTAL) {
928 			lowerFrame.right = thumbFrame.left;
929 			upperFrame.left = thumbFrame.right;
930 		} else {
931 			lowerFrame.top = thumbFrame.bottom;
932 			upperFrame.bottom = thumbFrame.top;
933 		}
934 	} else if (fUseFillColor) {
935 		if (fOrientation == B_HORIZONTAL) {
936 			lowerFrame.right = floor(lowerFrame.left - 1 + Position()
937 				* (lowerFrame.Width() + 1));
938 			upperFrame.left = lowerFrame.right;
939 		} else {
940 			lowerFrame.top = floor(lowerFrame.bottom + 1 - Position()
941 				* (lowerFrame.Height() + 1));
942 			upperFrame.bottom = lowerFrame.top;
943 		}
944 	}
945 
946 	view->SetHighColor(barColor);
947 	view->FillRect(upperFrame);
948 
949 	if (Style() == B_BLOCK_THUMB || fUseFillColor) {
950 		if (fUseFillColor)
951 			view->SetHighColor(fillColor);
952 		view->FillRect(lowerFrame);
953 	}
954 
955 	if (Style() == B_BLOCK_THUMB) {
956 		// We don't want to stroke the lines over the thumb
957 
958 		PushState();
959 
960 		BRegion region;
961 		GetClippingRegion(&region);
962 		region.Exclude(thumbFrame);
963 		ConstrainClippingRegion(&region);
964 	}
965 
966 	view->SetHighColor(darken1);
967 	view->StrokeLine(BPoint(frame.left, frame.top),
968 					 BPoint(frame.left + 1.0f, frame.top));
969 	view->StrokeLine(BPoint(frame.left, frame.bottom),
970 					 BPoint(frame.left + 1.0f, frame.bottom));
971 	view->StrokeLine(BPoint(frame.right - 1.0f, frame.top),
972 					 BPoint(frame.right, frame.top));
973 
974 	view->SetHighColor(darken2);
975 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
976 					 BPoint(frame.right - 1.0f, frame.top));
977 	view->StrokeLine(BPoint(frame.left, frame.bottom - 1.0f),
978 					 BPoint(frame.left, frame.top + 1.0f));
979 
980 	view->SetHighColor(lightenmax);
981 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.bottom),
982 					 BPoint(frame.right, frame.bottom));
983 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
984 					 BPoint(frame.right, frame.top + 1.0f));
985 
986 	frame.InsetBy(1.0f, 1.0f);
987 
988 	view->SetHighColor(darkenmax);
989 	view->StrokeLine(BPoint(frame.left, frame.bottom),
990 					 BPoint(frame.left, frame.top));
991 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
992 					 BPoint(frame.right, frame.top));
993 
994 	if (Style() == B_BLOCK_THUMB)
995 		PopState();
996 }
997 
998 
999 void
1000 BSlider::DrawHashMarks()
1001 {
1002 	if (fHashMarks == B_HASH_MARKS_NONE)
1003 		return;
1004 
1005 	BRect frame = HashMarksFrame();
1006 	BView* view = OffscreenView();
1007 
1008 	if (be_control_look) {
1009 		rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
1010 		uint32 flags = be_control_look->Flags(this);
1011 		be_control_look->DrawSliderHashMarks(view, frame, frame, base,
1012 			fHashMarkCount, fHashMarks, flags, fOrientation);
1013 		return;
1014 	}
1015 
1016 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
1017 	rgb_color lightenmax;
1018 	rgb_color darken2;
1019 
1020 	if (IsEnabled()) {
1021 		lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT);
1022 		darken2 = tint_color(no_tint, B_DARKEN_2_TINT);
1023 	} else {
1024 		lightenmax = tint_color(no_tint, B_LIGHTEN_2_TINT);
1025 		darken2 = tint_color(no_tint, B_DARKEN_1_TINT);
1026 	}
1027 
1028 	float pos = _MinPosition();
1029 	int32 hashMarkCount = max_c(fHashMarkCount, 2);
1030 		// draw at least two hashmarks at min/max if
1031 		// fHashMarks != B_HASH_MARKS_NONE
1032 	float factor = (_MaxPosition() - pos) / (hashMarkCount - 1);
1033 
1034 	if (fHashMarks & B_HASH_MARKS_TOP) {
1035 
1036 		view->BeginLineArray(hashMarkCount * 2);
1037 
1038 		if (fOrientation == B_HORIZONTAL) {
1039 			for (int32 i = 0; i < hashMarkCount; i++) {
1040 				view->AddLine(BPoint(pos, frame.top),
1041 							  BPoint(pos, frame.top + 5), darken2);
1042 				view->AddLine(BPoint(pos + 1, frame.top),
1043 							  BPoint(pos + 1, frame.top + 5), lightenmax);
1044 
1045 				pos += factor;
1046 			}
1047 		} else {
1048 			for (int32 i = 0; i < hashMarkCount; i++) {
1049 				view->AddLine(BPoint(frame.left, pos),
1050 							  BPoint(frame.left + 5, pos), darken2);
1051 				view->AddLine(BPoint(frame.left, pos + 1),
1052 							  BPoint(frame.left + 5, pos + 1), lightenmax);
1053 
1054 				pos += factor;
1055 			}
1056 		}
1057 
1058 		view->EndLineArray();
1059 	}
1060 
1061 	pos = _MinPosition();
1062 
1063 	if (fHashMarks & B_HASH_MARKS_BOTTOM) {
1064 
1065 		view->BeginLineArray(hashMarkCount * 2);
1066 
1067 		if (fOrientation == B_HORIZONTAL) {
1068 			for (int32 i = 0; i < hashMarkCount; i++) {
1069 				view->AddLine(BPoint(pos, frame.bottom - 5),
1070 							  BPoint(pos, frame.bottom), darken2);
1071 				view->AddLine(BPoint(pos + 1, frame.bottom - 5),
1072 							  BPoint(pos + 1, frame.bottom), lightenmax);
1073 
1074 				pos += factor;
1075 			}
1076 		} else {
1077 			for (int32 i = 0; i < hashMarkCount; i++) {
1078 				view->AddLine(BPoint(frame.right - 5, pos),
1079 							  BPoint(frame.right, pos), darken2);
1080 				view->AddLine(BPoint(frame.right - 5, pos + 1),
1081 							  BPoint(frame.right, pos + 1), lightenmax);
1082 
1083 				pos += factor;
1084 			}
1085 		}
1086 
1087 		view->EndLineArray();
1088 	}
1089 }
1090 
1091 
1092 void
1093 BSlider::DrawThumb()
1094 {
1095 	if (Style() == B_BLOCK_THUMB)
1096 		_DrawBlockThumb();
1097 	else
1098 		_DrawTriangleThumb();
1099 }
1100 
1101 
1102 void
1103 BSlider::DrawFocusMark()
1104 {
1105 	if (!IsFocus())
1106 		return;
1107 
1108 	OffscreenView()->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
1109 
1110 	BRect frame = ThumbFrame();
1111 
1112 	if (fStyle == B_BLOCK_THUMB) {
1113 		frame.left += 2.0f;
1114 		frame.top += 2.0f;
1115 		frame.right -= 3.0f;
1116 		frame.bottom -= 3.0f;
1117 		OffscreenView()->StrokeRect(frame);
1118 	} else {
1119 		if (fOrientation == B_HORIZONTAL) {
1120 			OffscreenView()->StrokeLine(BPoint(frame.left, frame.bottom + 2.0f),
1121 				BPoint(frame.right, frame.bottom + 2.0f));
1122 		} else {
1123 			OffscreenView()->StrokeLine(BPoint(frame.left - 2.0f, frame.top),
1124 				BPoint(frame.left - 2.0f, frame.bottom));
1125 		}
1126 	}
1127 }
1128 
1129 
1130 void
1131 BSlider::DrawText()
1132 {
1133 	BRect bounds(Bounds());
1134 	BView *view = OffscreenView();
1135 
1136 	if (IsEnabled()) {
1137 		view->SetHighColor(0, 0, 0);
1138 	} else {
1139 		view->SetHighColor(tint_color(LowColor(), B_DISABLED_LABEL_TINT));
1140 	}
1141 
1142 	font_height fontHeight;
1143 	GetFontHeight(&fontHeight);
1144 	if (Orientation() == B_HORIZONTAL) {
1145 		if (Label())
1146 			view->DrawString(Label(), BPoint(0.0, ceilf(fontHeight.ascent)));
1147 
1148 		// the update text is updated in SetValue() only
1149 		if (fUpdateText != NULL) {
1150 			view->DrawString(fUpdateText, BPoint(bounds.right
1151 				- StringWidth(fUpdateText), ceilf(fontHeight.ascent)));
1152 		}
1153 
1154 		if (fMinLimitLabel) {
1155 			view->DrawString(fMinLimitLabel, BPoint(0.0, bounds.bottom
1156 				- fontHeight.descent));
1157 		}
1158 
1159 		if (fMaxLimitLabel) {
1160 			view->DrawString(fMaxLimitLabel, BPoint(bounds.right
1161 				- StringWidth(fMaxLimitLabel), bounds.bottom
1162 				- fontHeight.descent));
1163 		}
1164 	} else {
1165 		float lineHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent)
1166 			+ ceilf(fontHeight.leading);
1167 		float baseLine = ceilf(fontHeight.ascent);
1168 
1169 		if (Label()) {
1170 			view->DrawString(Label(), BPoint((bounds.Width()
1171 				- StringWidth(Label())) / 2.0, baseLine));
1172 			baseLine += lineHeight;
1173 		}
1174 
1175 		if (fMaxLimitLabel) {
1176 			view->DrawString(fMaxLimitLabel, BPoint((bounds.Width()
1177 				- StringWidth(fMaxLimitLabel)) / 2.0, baseLine));
1178 		}
1179 
1180 		baseLine = bounds.bottom - ceilf(fontHeight.descent);
1181 
1182 		if (fMinLimitLabel) {
1183 			view->DrawString(fMinLimitLabel, BPoint((bounds.Width()
1184 				- StringWidth(fMinLimitLabel)) / 2.0, baseLine));
1185 			baseLine -= lineHeight;
1186 		}
1187 
1188 		if (fUpdateText != NULL) {
1189 			view->DrawString(fUpdateText, BPoint((bounds.Width()
1190 				- StringWidth(fUpdateText)) / 2.0, baseLine));
1191 		}
1192 	}
1193 }
1194 
1195 
1196 // #pragma mark -
1197 
1198 
1199 const char*
1200 BSlider::UpdateText() const
1201 {
1202 	return NULL;
1203 }
1204 
1205 
1206 void
1207 BSlider::UpdateTextChanged()
1208 {
1209 	// update text label
1210 	float oldWidth = 0.0;
1211 	if (fUpdateText != NULL)
1212 		oldWidth = StringWidth(fUpdateText);
1213 
1214 	const char* oldUpdateText = fUpdateText;
1215 	fUpdateText = UpdateText();
1216 	bool updateTextOnOff = (fUpdateText == NULL && oldUpdateText != NULL)
1217 		|| (fUpdateText != NULL && oldUpdateText == NULL);
1218 
1219 	float newWidth = 0.0;
1220 	if (fUpdateText != NULL)
1221 		newWidth = StringWidth(fUpdateText);
1222 
1223 	float width = ceilf(max_c(newWidth, oldWidth)) + 2.0f;
1224 	if (width != 0) {
1225 		font_height fontHeight;
1226 		GetFontHeight(&fontHeight);
1227 
1228 		float height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
1229 		float lineHeight = height + ceilf(fontHeight.leading);
1230 		BRect invalid(Bounds());
1231 		if (fOrientation == B_HORIZONTAL)
1232 			invalid = BRect(invalid.right - width, 0, invalid.right, height);
1233 		else {
1234 			if (!updateTextOnOff) {
1235 				invalid.left = (invalid.left + invalid.right - width) / 2;
1236 				invalid.right = invalid.left + width;
1237 				if (fMinLimitLabel)
1238 					invalid.bottom -= lineHeight;
1239 				invalid.top = invalid.bottom - height;
1240 			}
1241 		}
1242 		Invalidate(invalid);
1243 	}
1244 
1245 	float oldMaxUpdateTextWidth = fMaxUpdateTextWidth;
1246 	fMaxUpdateTextWidth = MaxUpdateTextWidth();
1247 	if (oldMaxUpdateTextWidth != fMaxUpdateTextWidth)
1248 		InvalidateLayout();
1249 }
1250 
1251 
1252 BRect
1253 BSlider::BarFrame() const
1254 {
1255 	BRect frame(Bounds());
1256 
1257 	font_height fontHeight;
1258 	GetFontHeight(&fontHeight);
1259 
1260 	float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
1261 	float leading = ceilf(fontHeight.leading);
1262 
1263 	float thumbInset;
1264 	if (fStyle == B_BLOCK_THUMB)
1265 		thumbInset = 8.0;
1266 	else
1267 		thumbInset = 7.0;
1268 
1269 	if (Orientation() == B_HORIZONTAL) {
1270 		frame.left = thumbInset;
1271 		frame.top = 6.0 + (Label() || fUpdateText ? textHeight + 4.0 : 0.0);
1272 		frame.right -= thumbInset;
1273 		frame.bottom = frame.top + fBarThickness;
1274 	} else {
1275 		frame.left = floorf((frame.Width() - fBarThickness) / 2.0);
1276 		frame.top = thumbInset;
1277 		if (Label())
1278 			frame.top += textHeight;
1279 		if (fMaxLimitLabel) {
1280 			frame.top += textHeight;
1281 			if (Label())
1282 				frame.top += leading;
1283 		}
1284 
1285 		frame.right = frame.left + fBarThickness;
1286 		frame.bottom = frame.bottom - thumbInset;
1287 		if (fMinLimitLabel)
1288 			frame.bottom -= textHeight;
1289 		if (fUpdateText) {
1290 			frame.bottom -= textHeight;
1291 			if (fMinLimitLabel)
1292 				frame.bottom -= leading;
1293 		}
1294 	}
1295 
1296 	return frame;
1297 }
1298 
1299 
1300 BRect
1301 BSlider::HashMarksFrame() const
1302 {
1303 	BRect frame(BarFrame());
1304 
1305 	if (fOrientation == B_HORIZONTAL) {
1306 		frame.top -= 6.0;
1307 		frame.bottom += 6.0;
1308 	} else {
1309 		frame.left -= 6.0;
1310 		frame.right += 6.0;
1311 	}
1312 
1313 	return frame;
1314 }
1315 
1316 
1317 BRect
1318 BSlider::ThumbFrame() const
1319 {
1320 	// TODO: The slider looks really ugly and broken when it is too little.
1321 	// I would suggest using BarFrame() here to get the top and bottom coords
1322 	// and spread them further apart for the thumb
1323 
1324 	BRect frame = Bounds();
1325 
1326 	font_height fontHeight;
1327 	GetFontHeight(&fontHeight);
1328 
1329 	float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
1330 
1331 	if (fStyle == B_BLOCK_THUMB) {
1332 		if (Orientation() == B_HORIZONTAL) {
1333 			frame.left = floorf(Position() * (_MaxPosition()
1334 				- _MinPosition()) + _MinPosition()) - 8;
1335 			frame.top = 2 + (Label() || fUpdateText ? textHeight + 4 : 0);
1336 			frame.right = frame.left + 17;
1337 			frame.bottom = frame.top + fBarThickness + 7;
1338 		} else {
1339 			frame.left = floor((frame.Width() - fBarThickness) / 2) - 4;
1340 			frame.top = floorf(Position() * (_MaxPosition()
1341 				- _MinPosition()) + _MinPosition()) - 8;
1342 			frame.right = frame.left + fBarThickness + 7;
1343 			frame.bottom = frame.top + 17;
1344 		}
1345 	} else {
1346 		if (Orientation() == B_HORIZONTAL) {
1347 			frame.left = floorf(Position() * (_MaxPosition()
1348 				- _MinPosition()) + _MinPosition()) - 6;
1349 			frame.right = frame.left + 12;
1350 			frame.top = 3 + fBarThickness + (Label() ? textHeight + 4 : 0);
1351 			frame.bottom = frame.top + 8;
1352 		} else {
1353 			frame.left = floorf((frame.Width() + fBarThickness) / 2) - 3;
1354 			frame.top = floorf(Position() * (_MaxPosition()
1355 				- _MinPosition())) + _MinPosition() - 6;
1356 			frame.right = frame.left + 8;
1357 			frame.bottom = frame.top + 12;
1358 		}
1359 	}
1360 
1361 	return frame;
1362 }
1363 
1364 
1365 void
1366 BSlider::SetFlags(uint32 flags)
1367 {
1368 	BControl::SetFlags(flags);
1369 }
1370 
1371 
1372 void
1373 BSlider::SetResizingMode(uint32 mode)
1374 {
1375 	BControl::SetResizingMode(mode);
1376 }
1377 
1378 
1379 void
1380 BSlider::GetPreferredSize(float* _width, float* _height)
1381 {
1382 	BSize preferredSize = PreferredSize();
1383 
1384 	if (_width) {
1385 //		*_width = preferredSize.width;
1386 		// NOTE: For compatibility reasons, the BSlider never shrinks
1387 		// horizontally. This only affects applications which do not
1388 		// use the new layout system.
1389 		*_width = max_c(Bounds().Width(), preferredSize.width);
1390 	}
1391 
1392 	if (_height)
1393 		*_height = preferredSize.height;
1394 }
1395 
1396 
1397 void
1398 BSlider::ResizeToPreferred()
1399 {
1400 	BControl::ResizeToPreferred();
1401 }
1402 
1403 
1404 status_t
1405 BSlider::Invoke(BMessage* message)
1406 {
1407 	return BControl::Invoke(message);
1408 }
1409 
1410 
1411 BHandler*
1412 BSlider::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
1413 	int32 command, const char *property)
1414 {
1415 	return BControl::ResolveSpecifier(message, index, specifier, command,
1416 		property);
1417 }
1418 
1419 
1420 status_t
1421 BSlider::GetSupportedSuites(BMessage* message)
1422 {
1423 	return BControl::GetSupportedSuites(message);
1424 }
1425 
1426 
1427 void
1428 BSlider::SetModificationMessage(BMessage* message)
1429 {
1430 	delete fModificationMessage;
1431 	fModificationMessage = message;
1432 }
1433 
1434 
1435 BMessage*
1436 BSlider::ModificationMessage() const
1437 {
1438 	return fModificationMessage;
1439 }
1440 
1441 
1442 void
1443 BSlider::SetSnoozeAmount(int32 snoozeTime)
1444 {
1445 	if (snoozeTime < 10000)
1446 		snoozeTime = 10000;
1447 	else if (snoozeTime > 1000000)
1448 		snoozeTime = 1000000;
1449 
1450 	fSnoozeAmount = snoozeTime;
1451 }
1452 
1453 
1454 int32
1455 BSlider::SnoozeAmount() const
1456 {
1457 	return fSnoozeAmount;
1458 }
1459 
1460 
1461 void
1462 BSlider::SetKeyIncrementValue(int32 incrementValue)
1463 {
1464 	fKeyIncrementValue = incrementValue;
1465 }
1466 
1467 
1468 int32
1469 BSlider::KeyIncrementValue() const
1470 {
1471 	return fKeyIncrementValue;
1472 }
1473 
1474 
1475 void
1476 BSlider::SetHashMarkCount(int32 hashMarkCount)
1477 {
1478 	fHashMarkCount = hashMarkCount;
1479 	Invalidate();
1480 }
1481 
1482 
1483 int32
1484 BSlider::HashMarkCount() const
1485 {
1486 	return fHashMarkCount;
1487 }
1488 
1489 
1490 void
1491 BSlider::SetHashMarks(hash_mark_location where)
1492 {
1493 	fHashMarks = where;
1494 // TODO: enable if the hashmark look is influencing the control size!
1495 //	InvalidateLayout();
1496 	Invalidate();
1497 }
1498 
1499 
1500 hash_mark_location
1501 BSlider::HashMarks() const
1502 {
1503 	return fHashMarks;
1504 }
1505 
1506 
1507 void
1508 BSlider::SetStyle(thumb_style style)
1509 {
1510 	fStyle = style;
1511 	InvalidateLayout();
1512 	Invalidate();
1513 }
1514 
1515 
1516 thumb_style
1517 BSlider::Style() const
1518 {
1519 	return fStyle;
1520 }
1521 
1522 
1523 void
1524 BSlider::SetBarColor(rgb_color barColor)
1525 {
1526 	fBarColor = barColor;
1527 	Invalidate(BarFrame());
1528 }
1529 
1530 
1531 rgb_color
1532 BSlider::BarColor() const
1533 {
1534 	return fBarColor;
1535 }
1536 
1537 
1538 void
1539 BSlider::UseFillColor(bool useFill, const rgb_color* barColor)
1540 {
1541 	fUseFillColor = useFill;
1542 
1543 	if (useFill && barColor)
1544 		fFillColor = *barColor;
1545 
1546 	Invalidate(BarFrame());
1547 }
1548 
1549 
1550 bool
1551 BSlider::FillColor(rgb_color* barColor) const
1552 {
1553 	if (barColor && fUseFillColor)
1554 		*barColor = fFillColor;
1555 
1556 	return fUseFillColor;
1557 }
1558 
1559 
1560 BView*
1561 BSlider::OffscreenView() const
1562 {
1563 #if USE_OFF_SCREEN_VIEW
1564 	return fOffScreenView;
1565 #else
1566 	return (BView*)this;
1567 #endif
1568 }
1569 
1570 
1571 orientation
1572 BSlider::Orientation() const
1573 {
1574 	return fOrientation;
1575 }
1576 
1577 
1578 void
1579 BSlider::SetOrientation(orientation posture)
1580 {
1581 	if (fOrientation == posture)
1582 		return;
1583 
1584 	fOrientation = posture;
1585 	InvalidateLayout();
1586 	Invalidate();
1587 }
1588 
1589 
1590 float
1591 BSlider::BarThickness() const
1592 {
1593 	return fBarThickness;
1594 }
1595 
1596 
1597 void
1598 BSlider::SetBarThickness(float thickness)
1599 {
1600 	if (thickness < 1.0)
1601 		thickness = 1.0;
1602 	else
1603 		thickness = roundf(thickness);
1604 
1605 	if (thickness != fBarThickness) {
1606 		// calculate invalid barframe and extend by hashmark size
1607 		float hInset = 0.0;
1608 		float vInset = 0.0;
1609 		if (fOrientation == B_HORIZONTAL)
1610 			vInset = -6.0;
1611 		else
1612 			hInset = -6.0;
1613 		BRect invalid = BarFrame().InsetByCopy(hInset, vInset) | ThumbFrame();
1614 
1615 		fBarThickness = thickness;
1616 
1617 		invalid = invalid | BarFrame().InsetByCopy(hInset, vInset)
1618 			| ThumbFrame();
1619 		Invalidate(invalid);
1620 		InvalidateLayout();
1621 	}
1622 }
1623 
1624 
1625 void
1626 BSlider::SetFont(const BFont *font, uint32 properties)
1627 {
1628 	BControl::SetFont(font, properties);
1629 
1630 #if USE_OFF_SCREEN_VIEW
1631 	if (fOffScreenView && fOffScreenBits) {
1632 		if (fOffScreenBits->Lock()) {
1633 			fOffScreenView->SetFont(font, properties);
1634 			fOffScreenBits->Unlock();
1635 		}
1636 	}
1637 #endif
1638 
1639 	InvalidateLayout();
1640 }
1641 
1642 
1643 void
1644 BSlider::SetLimits(int32 minimum, int32 maximum)
1645 {
1646 	if (minimum <= maximum) {
1647 		fMinValue = minimum;
1648 		fMaxValue = maximum;
1649 
1650 		int32 value = Value();
1651 		value = max_c(minimum, value);
1652 		value = min_c(maximum, value);
1653 
1654 		if (value != Value()) {
1655 			SetValue(value);
1656 		}
1657 	}
1658 }
1659 
1660 
1661 float
1662 BSlider::MaxUpdateTextWidth()
1663 {
1664 	// very simplistic implementation that assumes the string will be widest
1665 	// at the maximum value
1666 	int32 value = Value();
1667 	SetValueNoUpdate(fMaxValue);
1668 	float width = StringWidth(UpdateText());
1669 	SetValueNoUpdate(value);
1670 	// in case the derived class uses a fixed buffer, the contents
1671 	// should be reset for the old value
1672 	UpdateText();
1673 	return width;
1674 }
1675 
1676 
1677 // #pragma mark - layout related
1678 
1679 
1680 void
1681 BSlider::InvalidateLayout(bool descendants)
1682 {
1683 	// invalidate cached preferred size
1684 	fMinSize.Set(-1, -1);
1685 
1686 	BControl::InvalidateLayout(descendants);
1687 }
1688 
1689 
1690 BSize
1691 BSlider::MinSize()
1692 {
1693 	return BLayoutUtils::ComposeSize(ExplicitMinSize(),
1694 		_ValidateMinSize());
1695 }
1696 
1697 
1698 BSize
1699 BSlider::MaxSize()
1700 {
1701 	BSize maxSize = _ValidateMinSize();
1702 	if (fOrientation == B_HORIZONTAL)
1703 		maxSize.width = B_SIZE_UNLIMITED;
1704 	else
1705 		maxSize.height = B_SIZE_UNLIMITED;
1706 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), maxSize);
1707 }
1708 
1709 
1710 BSize
1711 BSlider::PreferredSize()
1712 {
1713 	BSize preferredSize = _ValidateMinSize();
1714 	if (fOrientation == B_HORIZONTAL)
1715 		preferredSize.width = max_c(100.0, preferredSize.width);
1716 	else
1717 		preferredSize.height = max_c(100.0, preferredSize.height);
1718 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), preferredSize);
1719 }
1720 
1721 
1722 // #pragma mark - private
1723 
1724 void
1725 BSlider::_DrawBlockThumb()
1726 {
1727 	BRect frame = ThumbFrame();
1728 	BView *view = OffscreenView();
1729 
1730 	if (be_control_look != NULL) {
1731 		rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
1732 		uint32 flags = be_control_look->Flags(this);
1733 		be_control_look->DrawSliderThumb(view, frame, frame, base, flags,
1734 			fOrientation);
1735 		return;
1736 	}
1737 
1738 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
1739 	rgb_color lighten2;
1740 	rgb_color lighten1;
1741 	rgb_color darken2;
1742 	rgb_color darken3;
1743 	rgb_color darkenmax;
1744 
1745 	if (IsEnabled()) {
1746 		lighten2	= tint_color(no_tint, B_LIGHTEN_2_TINT);
1747 		lighten1	= no_tint;
1748 		darken2		= tint_color(no_tint, B_DARKEN_2_TINT);
1749 		darken3		= tint_color(no_tint, B_DARKEN_3_TINT);
1750 		darkenmax	= tint_color(no_tint, B_DARKEN_MAX_TINT);
1751 	} else {
1752 		lighten2	= tint_color(no_tint, B_LIGHTEN_2_TINT);
1753 		lighten1	= tint_color(no_tint, B_LIGHTEN_1_TINT);
1754 		darken2		= tint_color(no_tint, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
1755 		darken3		= tint_color(no_tint, B_DARKEN_1_TINT);
1756 		darkenmax	= tint_color(no_tint, B_DARKEN_3_TINT);
1757 	}
1758 
1759 	// blank background for shadow
1760 	// ToDo: this also draws over the hash marks (though it's not *that* noticeable)
1761 	view->SetHighColor(no_tint);
1762 	view->StrokeLine(BPoint(frame.left, frame.top),
1763 					 BPoint(frame.left, frame.top));
1764 
1765 	BRect barFrame = BarFrame();
1766 	if (barFrame.right >= frame.right) {
1767 		// leave out barFrame from shadow background clearing
1768 		view->StrokeLine(BPoint(frame.right, frame.top),
1769 						 BPoint(frame.right, barFrame.top - 1.0f));
1770 		view->StrokeLine(BPoint(frame.right, barFrame.bottom + 1.0f),
1771 						 BPoint(frame.right, frame.bottom));
1772 	} else {
1773 		view->StrokeLine(BPoint(frame.right, frame.top),
1774 						 BPoint(frame.right, frame.bottom));
1775 	}
1776 
1777 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1778 					 BPoint(frame.right - 1.0f, frame.bottom));
1779 	view->StrokeLine(BPoint(frame.left, frame.bottom - 1.0f),
1780 					 BPoint(frame.left, frame.bottom - 1.0f));
1781 	view->StrokeLine(BPoint(frame.right - 1.0f, frame.top),
1782 					 BPoint(frame.right - 1.0f, frame.top));
1783 
1784 	// Outline (top, left)
1785 	view->SetHighColor(darken3);
1786 	view->StrokeLine(BPoint(frame.left, frame.bottom - 2.0f),
1787 					 BPoint(frame.left, frame.top + 1.0f));
1788 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
1789 					 BPoint(frame.right - 2.0f, frame.top));
1790 
1791 	// Shadow
1792 	view->SetHighColor(0, 0, 0, IsEnabled() ? 100 : 50);
1793 	view->SetDrawingMode(B_OP_ALPHA);
1794 	view->StrokeLine(BPoint(frame.right, frame.top + 2.0f),
1795 					 BPoint(frame.right, frame.bottom - 1.0f));
1796 	view->StrokeLine(BPoint(frame.left + 2.0f, frame.bottom),
1797 					 BPoint(frame.right - 1.0f, frame.bottom));
1798 
1799 	view->SetDrawingMode(B_OP_COPY);
1800 	view->SetHighColor(darken3);
1801 	view->StrokeLine(BPoint(frame.right - 1.0f, frame.bottom - 1.0f),
1802 					 BPoint(frame.right - 1.0f, frame.bottom - 1.0f));
1803 
1804 
1805 	// First bevel
1806 	frame.InsetBy(1.0f, 1.0f);
1807 
1808 	view->SetHighColor(darkenmax);
1809 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1810 					 BPoint(frame.right - 1.0f, frame.bottom));
1811 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
1812 					 BPoint(frame.right, frame.top));
1813 
1814 	view->SetHighColor(lighten2);
1815 	view->StrokeLine(BPoint(frame.left, frame.top),
1816 					 BPoint(frame.left, frame.bottom - 1.0f));
1817 	view->StrokeLine(BPoint(frame.left + 1.0f, frame.top),
1818 					 BPoint(frame.right - 1.0f, frame.top));
1819 
1820 	frame.InsetBy(1.0f, 1.0f);
1821 
1822 	view->FillRect(BRect(frame.left, frame.top, frame.right - 1.0f, frame.bottom - 1.0f));
1823 
1824 	// Second bevel and center dots
1825 	view->SetHighColor(darken2);
1826 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1827 					 BPoint(frame.right, frame.bottom));
1828 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
1829 					 BPoint(frame.right, frame.top));
1830 
1831 	if (Orientation() == B_HORIZONTAL) {
1832 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 2.0f),
1833 						 BPoint(frame.left + 6.0f, frame.top + 2.0f));
1834 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 4.0f),
1835 						 BPoint(frame.left + 6.0f, frame.top + 4.0f));
1836 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 6.0f),
1837 						 BPoint(frame.left + 6.0f, frame.top + 6.0f));
1838 	} else {
1839 		view->StrokeLine(BPoint(frame.left + 2.0f, frame.top + 6.0f),
1840 						 BPoint(frame.left + 2.0f, frame.top + 6.0f));
1841 		view->StrokeLine(BPoint(frame.left + 4.0f, frame.top + 6.0f),
1842 						 BPoint(frame.left + 4.0f, frame.top + 6.0f));
1843 		view->StrokeLine(BPoint(frame.left + 6.0f, frame.top + 6.0f),
1844 						 BPoint(frame.left + 6.0f, frame.top + 6.0f));
1845 	}
1846 
1847 	frame.InsetBy(1.0f, 1.0f);
1848 
1849 	// Third bevel
1850 	view->SetHighColor(lighten1);
1851 	view->StrokeLine(BPoint(frame.left, frame.bottom),
1852 					 BPoint(frame.right, frame.bottom));
1853 	view->StrokeLine(BPoint(frame.right, frame.bottom - 1.0f),
1854 					 BPoint(frame.right, frame.top));
1855 }
1856 
1857 
1858 void
1859 BSlider::_DrawTriangleThumb()
1860 {
1861 	BRect frame = ThumbFrame();
1862 	BView *view = OffscreenView();
1863 
1864 	if (be_control_look != NULL) {
1865 		rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
1866 		uint32 flags = be_control_look->Flags(this);
1867 		be_control_look->DrawSliderTriangle(view, frame, frame, base, flags,
1868 			fOrientation);
1869 		return;
1870 	}
1871 
1872 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR);
1873 	rgb_color lightenmax;
1874 	rgb_color lighten1;
1875 	rgb_color darken2;
1876 	rgb_color darken3;
1877 	rgb_color darkenmax;
1878 
1879 	if (IsEnabled()) {
1880 		lightenmax	= tint_color(no_tint, B_LIGHTEN_MAX_TINT);
1881 		lighten1	= no_tint;
1882 		darken2		= tint_color(no_tint, B_DARKEN_2_TINT);
1883 		darken3		= tint_color(no_tint, B_DARKEN_3_TINT);
1884 		darkenmax	= tint_color(no_tint, B_DARKEN_MAX_TINT);
1885 	} else {
1886 		lightenmax	= tint_color(no_tint, B_LIGHTEN_2_TINT);
1887 		lighten1	= tint_color(no_tint, B_LIGHTEN_1_TINT);
1888 		darken2		= tint_color(no_tint, (B_NO_TINT + B_DARKEN_1_TINT) / 2);
1889 		darken3		= tint_color(no_tint, B_DARKEN_1_TINT);
1890 		darkenmax	= tint_color(no_tint, B_DARKEN_3_TINT);
1891 	}
1892 
1893 	if (Orientation() == B_HORIZONTAL) {
1894 		view->SetHighColor(lighten1);
1895 		view->FillTriangle(
1896 			BPoint(frame.left + 1, frame.bottom - 3),
1897 			BPoint((frame.left + frame.right) / 2, frame.top + 1),
1898 			BPoint(frame.right - 1, frame.bottom - 3));
1899 
1900 		view->SetHighColor(no_tint);
1901 		view->StrokeLine(BPoint(frame.right - 2, frame.bottom - 3),
1902 			BPoint(frame.left + 3, frame.bottom - 3));
1903 
1904 		view->SetHighColor(darkenmax);
1905 		view->StrokeLine(BPoint(frame.left, frame.bottom - 1),
1906 			BPoint(frame.right, frame.bottom - 1));
1907 		view->StrokeLine(BPoint(frame.right, frame.bottom - 2),
1908 			BPoint((frame.left + frame.right) / 2, frame.top));
1909 
1910 		view->SetHighColor(darken2);
1911 		view->StrokeLine(BPoint(frame.right - 1, frame.bottom - 2),
1912 			BPoint(frame.left + 1, frame.bottom - 2));
1913 		view->SetHighColor(darken3);
1914 		view->StrokeLine(BPoint(frame.left, frame.bottom - 2),
1915 			BPoint((frame.left + frame.right) / 2 - 1, frame.top + 1));
1916 
1917 		view->SetHighColor(lightenmax);
1918 		view->StrokeLine(BPoint(frame.left + 2, frame.bottom - 3),
1919 			BPoint((frame.left + frame.right) / 2, frame.top + 1));
1920 
1921 		// Shadow
1922 		view->SetHighColor(0, 0, 0, IsEnabled() ? 80 : 40);
1923 		view->SetDrawingMode(B_OP_ALPHA);
1924 		view->StrokeLine(BPoint(frame.left + 1, frame.bottom),
1925 			BPoint(frame.right, frame.bottom));
1926 	} else {
1927 		view->SetHighColor(lighten1);
1928 		view->FillTriangle(
1929 			BPoint(frame.left, (frame.top + frame.bottom) / 2),
1930 			BPoint(frame.right - 1, frame.top + 1),
1931 			BPoint(frame.right - 1, frame.bottom - 1));
1932 
1933 		view->SetHighColor(darkenmax);
1934 		view->StrokeLine(BPoint(frame.right - 1, frame.top),
1935 			BPoint(frame.right - 1, frame.bottom));
1936 		view->StrokeLine(BPoint(frame.right - 1, frame.bottom),
1937 			BPoint(frame.right - 2, frame.bottom));
1938 
1939 		view->SetHighColor(darken2);
1940 		view->StrokeLine(BPoint(frame.right - 2, frame.top + 2),
1941 			BPoint(frame.right - 2, frame.bottom - 1));
1942 		view->StrokeLine(
1943 			BPoint(frame.left, (frame.top + frame.bottom) / 2),
1944 			BPoint(frame.right - 2, frame.top));
1945 		view->SetHighColor(darken3);
1946 		view->StrokeLine(
1947 			BPoint(frame.left + 1, (frame.top + frame.bottom) / 2 + 1),
1948 			BPoint(frame.right - 3, frame.bottom - 1));
1949 
1950 		view->SetHighColor(lightenmax);
1951 		view->StrokeLine(
1952 			BPoint(frame.left + 1, (frame.top + frame.bottom) / 2),
1953 			BPoint(frame.right - 2, frame.top + 1));
1954 
1955 		// Shadow
1956 		view->SetHighColor(0, 0, 0, IsEnabled() ? 80 : 40);
1957 		view->SetDrawingMode(B_OP_ALPHA);
1958 		view->StrokeLine(BPoint(frame.right, frame.top + 1),
1959 			BPoint(frame.right, frame.bottom));
1960 	}
1961 
1962 	view->SetDrawingMode(B_OP_COPY);
1963 }
1964 
1965 
1966 BPoint
1967 BSlider::_Location() const
1968 {
1969 	return fLocation;
1970 }
1971 
1972 
1973 void
1974 BSlider::_SetLocation(BPoint p)
1975 {
1976 	fLocation = p;
1977 }
1978 
1979 
1980 float
1981 BSlider::_MinPosition() const
1982 {
1983 	if (fOrientation == B_HORIZONTAL)
1984 		return BarFrame().left + 1.0f;
1985 
1986 	return BarFrame().bottom - 1.0f;
1987 }
1988 
1989 
1990 float
1991 BSlider::_MaxPosition() const
1992 {
1993 	if (fOrientation == B_HORIZONTAL)
1994 		return BarFrame().right - 1.0f;
1995 
1996 	return BarFrame().top + 1.0f;
1997 }
1998 
1999 
2000 BSize
2001 BSlider::_ValidateMinSize()
2002 {
2003 	if (fMinSize.width >= 0) {
2004 		// the preferred size is up to date
2005 		return fMinSize;
2006 	}
2007 
2008 	font_height fontHeight;
2009 	GetFontHeight(&fontHeight);
2010 
2011 	float width = 0.0;
2012 	float height = 0.0;
2013 
2014 	if (fMaxUpdateTextWidth < 0.0)
2015 		fMaxUpdateTextWidth = MaxUpdateTextWidth();
2016 
2017 	if (Orientation() == B_HORIZONTAL) {
2018 		height = 12.0 + fBarThickness;
2019 		int32 rows = 0;
2020 
2021 		float labelWidth = 0;
2022 		int32 labelRows = 0;
2023 		float labelSpacing = StringWidth("M") * 2;
2024 		if (Label()) {
2025 			labelWidth = StringWidth(Label());
2026 			labelRows = 1;
2027 		}
2028 		if (fMaxUpdateTextWidth > 0.0) {
2029 			if (labelWidth > 0)
2030 				labelWidth += labelSpacing;
2031 			labelWidth += fMaxUpdateTextWidth;
2032 			labelRows = 1;
2033 		}
2034 		rows += labelRows;
2035 
2036 		if (MinLimitLabel())
2037 			width = StringWidth(MinLimitLabel());
2038 		if (MaxLimitLabel()) {
2039 			// some space between the labels
2040 			if (MinLimitLabel())
2041 				width += labelSpacing;
2042 
2043 			width += StringWidth(MaxLimitLabel());
2044 		}
2045 
2046 		if (labelWidth > width)
2047 			width = labelWidth;
2048 		if (width < 32.0)
2049 			width = 32.0;
2050 
2051 		if (MinLimitLabel() || MaxLimitLabel())
2052 			rows++;
2053 
2054 		height += rows * (ceilf(fontHeight.ascent)
2055 			+ ceilf(fontHeight.descent) + 4.0);
2056 	} else {
2057 		// B_VERTICAL
2058 		width = 12.0 + fBarThickness;
2059 		height = 32.0;
2060 
2061 		float lineHeightNoLeading = ceilf(fontHeight.ascent)
2062 			+ ceilf(fontHeight.descent);
2063 		float lineHeight = lineHeightNoLeading + ceilf(fontHeight.leading);
2064 
2065 		// find largest label
2066 		float labelWidth = 0;
2067 		if (Label()) {
2068 			labelWidth = StringWidth(Label());
2069 			height += lineHeightNoLeading;
2070 		}
2071 		if (MaxLimitLabel()) {
2072 			labelWidth = max_c(labelWidth, StringWidth(MaxLimitLabel()));
2073 			height += Label() ? lineHeight : lineHeightNoLeading;
2074 		}
2075 		if (MinLimitLabel()) {
2076 			labelWidth = max_c(labelWidth, StringWidth(MinLimitLabel()));
2077 			height += lineHeightNoLeading;
2078 		}
2079 		if (fMaxUpdateTextWidth > 0.0) {
2080 			labelWidth = max_c(labelWidth, fMaxUpdateTextWidth);
2081 			height += MinLimitLabel() ? lineHeight : lineHeightNoLeading;
2082 		}
2083 
2084 		width = max_c(labelWidth, width);
2085 	}
2086 
2087 	fMinSize.width = width;
2088 	fMinSize.height = height;
2089 
2090 	return fMinSize;
2091 }
2092 
2093 
2094 // #pragma mark - FBC padding
2095 
2096 void BSlider::_ReservedSlider6() {}
2097 void BSlider::_ReservedSlider7() {}
2098 void BSlider::_ReservedSlider8() {}
2099 void BSlider::_ReservedSlider9() {}
2100 void BSlider::_ReservedSlider10() {}
2101 void BSlider::_ReservedSlider11() {}
2102 void BSlider::_ReservedSlider12() {}
2103 
2104 
2105 BSlider &
2106 BSlider::operator=(const BSlider &)
2107 {
2108 	return *this;
2109 }
2110 
2111 
2112 //	#pragma mark - BeOS compatibility
2113 
2114 
2115 #if __GNUC__ < 3
2116 
2117 extern "C" void
2118 GetLimits__7BSliderPlT1(BSlider* slider, int32* minimum, int32* maximum)
2119 {
2120 	slider->GetLimits(minimum, maximum);
2121 }
2122 
2123 
2124 extern "C" void
2125 _ReservedSlider4__7BSlider(BSlider *slider, int32 minimum, int32 maximum)
2126 {
2127 	slider->BSlider::SetLimits(minimum, maximum);
2128 }
2129 
2130 extern "C" float
2131 _ReservedSlider5__7BSlider(BSlider *slider)
2132 {
2133 	return slider->BSlider::MaxUpdateTextWidth();
2134 }
2135 
2136 
2137 extern "C" void
2138 _ReservedSlider1__7BSlider(BSlider* slider, orientation _orientation)
2139 {
2140 	slider->BSlider::SetOrientation(_orientation);
2141 }
2142 
2143 
2144 extern "C" void
2145 _ReservedSlider2__7BSlider(BSlider* slider, float thickness)
2146 {
2147 	slider->BSlider::SetBarThickness(thickness);
2148 }
2149 
2150 
2151 extern "C" void
2152 _ReservedSlider3__7BSlider(BSlider* slider, const BFont* font,
2153 	uint32 properties)
2154 {
2155 	slider->BSlider::SetFont(font, properties);
2156 }
2157 
2158 #endif	// __GNUC__ < 3
2159