1 /*
2 * Copyright 2001-2016 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 * Axel Dörfler, axeld@pinc-software.de
8 * Marc Flerackers (mflerackers@androme.be)
9 */
10
11
12 #include <Slider.h>
13
14 #include <algorithm>
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <Bitmap.h>
21 #include <ControlLook.h>
22 #include <Errors.h>
23 #include <LayoutUtils.h>
24 #include <Message.h>
25 #include <Region.h>
26 #include <String.h>
27 #include <Window.h>
28
29 #include <binary_compatibility/Interface.h>
30
31
32 #define USE_OFF_SCREEN_VIEW 0
33
34
BSlider(BRect frame,const char * name,const char * label,BMessage * message,int32 minValue,int32 maxValue,thumb_style thumbType,uint32 resizingMode,uint32 flags)35 BSlider::BSlider(
36 BRect frame, const char* name, const char* label, BMessage* message,
37 int32 minValue, int32 maxValue, thumb_style thumbType, uint32 resizingMode,
38 uint32 flags)
39 :
40 BControl(frame, name, label, message, resizingMode, flags),
41 fModificationMessage(NULL),
42 fSnoozeAmount(20000),
43
44 fMinLimitLabel(NULL),
45 fMaxLimitLabel(NULL),
46
47 fMinValue(minValue),
48 fMaxValue(maxValue),
49 fKeyIncrementValue(1),
50
51 fHashMarkCount(0),
52 fHashMarks(B_HASH_MARKS_NONE),
53
54 fStyle(thumbType),
55
56 fOrientation(B_HORIZONTAL),
57 fBarThickness(6.0)
58 {
59 _InitBarColor();
60
61 _InitObject();
62 SetValue(0);
63 }
64
65
BSlider(BRect frame,const char * name,const char * label,BMessage * message,int32 minValue,int32 maxValue,orientation posture,thumb_style thumbType,uint32 resizingMode,uint32 flags)66 BSlider::BSlider(BRect frame, const char* name, const char* label,
67 BMessage* message, int32 minValue, int32 maxValue, orientation posture,
68 thumb_style thumbType, uint32 resizingMode, uint32 flags)
69 :
70 BControl(frame, name, label, message, resizingMode, flags),
71 fModificationMessage(NULL),
72 fSnoozeAmount(20000),
73
74 fMinLimitLabel(NULL),
75 fMaxLimitLabel(NULL),
76
77 fMinValue(minValue),
78 fMaxValue(maxValue),
79 fKeyIncrementValue(1),
80
81 fHashMarkCount(0),
82 fHashMarks(B_HASH_MARKS_NONE),
83
84 fStyle(thumbType),
85
86 fOrientation(posture),
87 fBarThickness(6.0)
88 {
89 _InitBarColor();
90
91 _InitObject();
92 SetValue(0);
93 }
94
95
BSlider(const char * name,const char * label,BMessage * message,int32 minValue,int32 maxValue,orientation posture,thumb_style thumbType,uint32 flags)96 BSlider::BSlider(const char* name, const char* label, BMessage* message,
97 int32 minValue, int32 maxValue, orientation posture, thumb_style thumbType,
98 uint32 flags)
99 :
100 BControl(name, label, message, flags),
101 fModificationMessage(NULL),
102 fSnoozeAmount(20000),
103
104 fMinLimitLabel(NULL),
105 fMaxLimitLabel(NULL),
106
107 fMinValue(minValue),
108 fMaxValue(maxValue),
109 fKeyIncrementValue(1),
110
111 fHashMarkCount(0),
112 fHashMarks(B_HASH_MARKS_NONE),
113
114 fStyle(thumbType),
115
116 fOrientation(posture),
117 fBarThickness(6.0)
118 {
119 _InitBarColor();
120
121 _InitObject();
122 SetValue(0);
123 }
124
125
BSlider(BMessage * archive)126 BSlider::BSlider(BMessage* archive)
127 :
128 BControl(archive)
129 {
130 fModificationMessage = NULL;
131
132 if (archive->HasMessage("_mod_msg")) {
133 BMessage* message = new BMessage;
134
135 archive->FindMessage("_mod_msg", message);
136
137 SetModificationMessage(message);
138 }
139
140 if (archive->FindInt32("_sdelay", &fSnoozeAmount) != B_OK)
141 SetSnoozeAmount(20000);
142
143 rgb_color color;
144 if (archive->FindInt32("_fcolor", (int32*)&color) == B_OK)
145 UseFillColor(true, &color);
146 else
147 UseFillColor(false);
148
149 int32 orient;
150 if (archive->FindInt32("_orient", &orient) == B_OK)
151 fOrientation = (orientation)orient;
152 else
153 fOrientation = B_HORIZONTAL;
154
155 fMinLimitLabel = NULL;
156 fMaxLimitLabel = NULL;
157
158 const char* minlbl = NULL;
159 const char* maxlbl = NULL;
160
161 archive->FindString("_minlbl", &minlbl);
162 archive->FindString("_maxlbl", &maxlbl);
163
164 SetLimitLabels(minlbl, maxlbl);
165
166 if (archive->FindInt32("_min", &fMinValue) != B_OK)
167 fMinValue = 0;
168
169 if (archive->FindInt32("_max", &fMaxValue) != B_OK)
170 fMaxValue = 100;
171
172 if (archive->FindInt32("_incrementvalue", &fKeyIncrementValue) != B_OK)
173 fKeyIncrementValue = 1;
174
175 if (archive->FindInt32("_hashcount", &fHashMarkCount) != B_OK)
176 fHashMarkCount = 11;
177
178 int16 hashloc;
179 if (archive->FindInt16("_hashloc", &hashloc) == B_OK)
180 fHashMarks = (hash_mark_location)hashloc;
181 else
182 fHashMarks = B_HASH_MARKS_NONE;
183
184 int16 sstyle;
185 if (archive->FindInt16("_sstyle", &sstyle) == B_OK)
186 fStyle = (thumb_style)sstyle;
187 else
188 fStyle = B_BLOCK_THUMB;
189
190 if (archive->FindInt32("_bcolor", (int32*)&color) != B_OK)
191 color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_4_TINT);
192 SetBarColor(color);
193
194 float bthickness;
195 if (archive->FindFloat("_bthickness", &bthickness) == B_OK)
196 fBarThickness = bthickness;
197 else
198 fBarThickness = 6.0f;
199
200 _InitObject();
201 }
202
203
~BSlider()204 BSlider::~BSlider()
205 {
206 #if USE_OFF_SCREEN_VIEW
207 delete fOffScreenBits;
208 #endif
209
210 delete fModificationMessage;
211 free(fMinLimitLabel);
212 free(fMaxLimitLabel);
213 }
214
215
216 void
_InitBarColor()217 BSlider::_InitBarColor()
218 {
219 SetBarColor(be_control_look->SliderBarColor(
220 ui_color(B_PANEL_BACKGROUND_COLOR)));
221 UseFillColor(false, NULL);
222 }
223
224
225 void
_InitObject()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*
Instantiate(BMessage * archive)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
Archive(BMessage * archive,bool deep) const255 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
265 if (ret == B_OK)
266 ret = archive->AddInt32("_bcolor", (const uint32&)fBarColor);
267
268 if (FillColor(NULL) && ret == B_OK)
269 ret = archive->AddInt32("_fcolor", (const uint32&)fFillColor);
270
271 if (ret == B_OK && fMinLimitLabel != NULL)
272 ret = archive->AddString("_minlbl", fMinLimitLabel);
273
274 if (ret == B_OK && fMaxLimitLabel != NULL)
275 ret = archive->AddString("_maxlbl", fMaxLimitLabel);
276
277 if (ret == B_OK)
278 ret = archive->AddInt32("_min", fMinValue);
279
280 if (ret == B_OK)
281 ret = archive->AddInt32("_max", fMaxValue);
282
283 if (ret == B_OK)
284 ret = archive->AddInt32("_incrementvalue", fKeyIncrementValue);
285
286 if (ret == B_OK)
287 ret = archive->AddInt32("_hashcount", fHashMarkCount);
288
289 if (ret == B_OK)
290 ret = archive->AddInt16("_hashloc", fHashMarks);
291
292 if (ret == B_OK)
293 ret = archive->AddInt16("_sstyle", fStyle);
294
295 if (ret == B_OK)
296 ret = archive->AddInt32("_orient", fOrientation);
297
298 if (ret == B_OK)
299 ret = archive->AddFloat("_bthickness", fBarThickness);
300
301 return ret;
302 }
303
304
305 status_t
Perform(perform_code code,void * _data)306 BSlider::Perform(perform_code code, void* _data)
307 {
308 switch (code) {
309 case PERFORM_CODE_MIN_SIZE:
310 ((perform_data_min_size*)_data)->return_value = BSlider::MinSize();
311 return B_OK;
312
313 case PERFORM_CODE_MAX_SIZE:
314 ((perform_data_max_size*)_data)->return_value = BSlider::MaxSize();
315 return B_OK;
316
317 case PERFORM_CODE_PREFERRED_SIZE:
318 ((perform_data_preferred_size*)_data)->return_value
319 = BSlider::PreferredSize();
320 return B_OK;
321
322 case PERFORM_CODE_LAYOUT_ALIGNMENT:
323 ((perform_data_layout_alignment*)_data)->return_value
324 = BSlider::LayoutAlignment();
325 return B_OK;
326
327 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
328 ((perform_data_has_height_for_width*)_data)->return_value
329 = BSlider::HasHeightForWidth();
330 return B_OK;
331
332 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
333 {
334 perform_data_get_height_for_width* data
335 = (perform_data_get_height_for_width*)_data;
336 BSlider::GetHeightForWidth(data->width, &data->min, &data->max,
337 &data->preferred);
338 return B_OK;
339 }
340
341 case PERFORM_CODE_SET_LAYOUT:
342 {
343 perform_data_set_layout* data = (perform_data_set_layout*)_data;
344 BSlider::SetLayout(data->layout);
345 return B_OK;
346 }
347
348 case PERFORM_CODE_LAYOUT_INVALIDATED:
349 {
350 perform_data_layout_invalidated* data
351 = (perform_data_layout_invalidated*)_data;
352 BSlider::LayoutInvalidated(data->descendants);
353 return B_OK;
354 }
355
356 case PERFORM_CODE_DO_LAYOUT:
357 {
358 BSlider::DoLayout();
359 return B_OK;
360 }
361
362 case PERFORM_CODE_SET_ICON:
363 {
364 perform_data_set_icon* data = (perform_data_set_icon*)_data;
365 return BSlider::SetIcon(data->icon, data->flags);
366 }
367 }
368
369 return BControl::Perform(code, _data);
370 }
371
372
373 void
WindowActivated(bool state)374 BSlider::WindowActivated(bool state)
375 {
376 BControl::WindowActivated(state);
377 }
378
379
380 void
AttachedToWindow()381 BSlider::AttachedToWindow()
382 {
383 ResizeToPreferred();
384
385 #if USE_OFF_SCREEN_VIEW
386 BRect bounds(Bounds());
387
388 if (!fOffScreenView) {
389 fOffScreenView = new BView(bounds, "", B_FOLLOW_ALL, B_WILL_DRAW);
390
391 BFont font;
392 GetFont(&font);
393 fOffScreenView->SetFont(&font);
394 }
395
396 if (!fOffScreenBits) {
397 fOffScreenBits = new BBitmap(bounds, B_RGBA32, true, false);
398
399 if (fOffScreenBits && fOffScreenView)
400 fOffScreenBits->AddChild(fOffScreenView);
401
402 } else if (fOffScreenView)
403 fOffScreenBits->AddChild(fOffScreenView);
404 #endif // USE_OFF_SCREEN_VIEW
405
406 BControl::AttachedToWindow();
407
408 BView* view = OffscreenView();
409 if (view != NULL && view->LockLooper()) {
410 view->SetViewColor(B_TRANSPARENT_COLOR);
411 if (LowUIColor() != B_NO_COLOR)
412 view->SetLowUIColor(LowUIColor());
413 else
414 view->SetLowColor(LowColor());
415
416 view->UnlockLooper();
417 }
418
419 int32 value = Value();
420 SetValue(value);
421 // makes sure the value is within valid bounds
422 _SetLocationForValue(Value());
423 // makes sure the location is correct
424 UpdateTextChanged();
425 }
426
427
428 void
AllAttached()429 BSlider::AllAttached()
430 {
431 BControl::AllAttached();
432
433 // When using a layout we may not have a parent, so we need to employ the
434 // standard system colors manually. Due to how layouts work, this must
435 // happen here, rather than in AttachedToWindow().
436 if (Parent() == NULL)
437 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
438 }
439
440
441 void
AllDetached()442 BSlider::AllDetached()
443 {
444 BControl::AllDetached();
445 }
446
447
448 void
DetachedFromWindow()449 BSlider::DetachedFromWindow()
450 {
451 BControl::DetachedFromWindow();
452
453 #if USE_OFF_SCREEN_VIEW
454 if (fOffScreenBits) {
455 delete fOffScreenBits;
456 fOffScreenBits = NULL;
457 fOffScreenView = NULL;
458 }
459 #endif
460 }
461
462
463 void
MessageReceived(BMessage * message)464 BSlider::MessageReceived(BMessage* message)
465 {
466 BControl::MessageReceived(message);
467 }
468
469
470 void
FrameMoved(BPoint new_position)471 BSlider::FrameMoved(BPoint new_position)
472 {
473 BControl::FrameMoved(new_position);
474 }
475
476
477 void
FrameResized(float w,float h)478 BSlider::FrameResized(float w,float h)
479 {
480 BControl::FrameResized(w, h);
481
482 BRect bounds(Bounds());
483
484 if (bounds.right <= 0.0f || bounds.bottom <= 0.0f)
485 return;
486
487 #if USE_OFF_SCREEN_VIEW
488 if (fOffScreenBits) {
489 fOffScreenBits->RemoveChild(fOffScreenView);
490 delete fOffScreenBits;
491
492 fOffScreenView->ResizeTo(bounds.Width(), bounds.Height());
493
494 fOffScreenBits = new BBitmap(Bounds(), B_RGBA32, true, false);
495 fOffScreenBits->AddChild(fOffScreenView);
496 }
497 #endif
498
499 Invalidate();
500 }
501
502
503 void
KeyDown(const char * bytes,int32 numBytes)504 BSlider::KeyDown(const char* bytes, int32 numBytes)
505 {
506 if (!IsEnabled() || IsHidden())
507 return;
508
509 int32 newValue = Value();
510
511 switch (bytes[0]) {
512 case B_LEFT_ARROW:
513 case B_DOWN_ARROW:
514 newValue -= KeyIncrementValue();
515 break;
516
517 case B_RIGHT_ARROW:
518 case B_UP_ARROW:
519 newValue += KeyIncrementValue();
520 break;
521
522 case B_HOME:
523 newValue = fMinValue;
524 break;
525
526 case B_END:
527 newValue = fMaxValue;
528 break;
529
530 default:
531 BControl::KeyDown(bytes, numBytes);
532 return;
533 }
534
535 if (newValue < fMinValue)
536 newValue = fMinValue;
537
538 if (newValue > fMaxValue)
539 newValue = fMaxValue;
540
541 if (newValue != Value()) {
542 fInitialLocation = _Location();
543 SetValue(newValue);
544 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
545 }
546 }
547
548 void
KeyUp(const char * bytes,int32 numBytes)549 BSlider::KeyUp(const char* bytes, int32 numBytes)
550 {
551 if (fInitialLocation != _Location()) {
552 // The last KeyDown event triggered the modification message or no
553 // notification at all, we may also have sent the modification message
554 // continually while the user kept pressing the key. In either case,
555 // finish with the final message to make the behavior consistent with
556 // changing the value by mouse.
557 Invoke();
558 }
559 }
560
561
562 /*!
563 Makes sure the \a point is within valid bounds.
564 Returns \c true if the relevant coordinate (depending on the orientation
565 of the slider) differs from \a comparePoint.
566 */
567 bool
_ConstrainPoint(BPoint & point,BPoint comparePoint) const568 BSlider::_ConstrainPoint(BPoint& point, BPoint comparePoint) const
569 {
570 if (fOrientation == B_HORIZONTAL) {
571 if (point.x != comparePoint.x) {
572 if (point.x < _MinPosition())
573 point.x = _MinPosition();
574 else if (point.x > _MaxPosition())
575 point.x = _MaxPosition();
576
577 return true;
578 }
579 } else {
580 if (point.y != comparePoint.y) {
581 if (point.y > _MinPosition())
582 point.y = _MinPosition();
583 else if (point.y < _MaxPosition())
584 point.y = _MaxPosition();
585
586 return true;
587 }
588 }
589
590 return false;
591 }
592
593
594 void
MouseDown(BPoint point)595 BSlider::MouseDown(BPoint point)
596 {
597 if (!IsEnabled())
598 return;
599
600 if (BarFrame().Contains(point) || ThumbFrame().Contains(point))
601 fInitialLocation = _Location();
602
603 uint32 buttons;
604 GetMouse(&point, &buttons, true);
605
606 _ConstrainPoint(point, fInitialLocation);
607 SetValue(ValueForPoint(point));
608
609 if (_Location() != fInitialLocation)
610 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
611
612 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
613 SetTracking(true);
614 SetMouseEventMask(B_POINTER_EVENTS,
615 B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
616 } else {
617 // synchronous mouse tracking
618 BPoint prevPoint;
619
620 while (buttons) {
621 prevPoint = point;
622
623 snooze(SnoozeAmount());
624 GetMouse(&point, &buttons, true);
625
626 if (_ConstrainPoint(point, prevPoint)) {
627 int32 value = ValueForPoint(point);
628 if (value != Value()) {
629 SetValue(value);
630 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
631 }
632 }
633 }
634 if (_Location() != fInitialLocation)
635 Invoke();
636 }
637 }
638
639
640 void
MouseUp(BPoint point)641 BSlider::MouseUp(BPoint point)
642 {
643 if (IsTracking()) {
644 if (_Location() != fInitialLocation)
645 Invoke();
646
647 SetTracking(false);
648 } else
649 BControl::MouseUp(point);
650 }
651
652
653 void
MouseMoved(BPoint point,uint32 transit,const BMessage * message)654 BSlider::MouseMoved(BPoint point, uint32 transit, const BMessage* message)
655 {
656 if (IsTracking()) {
657 if (_ConstrainPoint(point, _Location())) {
658 int32 value = ValueForPoint(point);
659 if (value != Value()) {
660 SetValue(value);
661 InvokeNotify(ModificationMessage(), B_CONTROL_MODIFIED);
662 }
663 }
664 } else
665 BControl::MouseMoved(point, transit, message);
666 }
667
668
669 void
Pulse()670 BSlider::Pulse()
671 {
672 BControl::Pulse();
673 }
674
675
676 void
SetLabel(const char * label)677 BSlider::SetLabel(const char* label)
678 {
679 BControl::SetLabel(label);
680 }
681
682
683 void
SetLimitLabels(const char * minLabel,const char * maxLabel)684 BSlider::SetLimitLabels(const char* minLabel, const char* maxLabel)
685 {
686 free(fMinLimitLabel);
687 fMinLimitLabel = minLabel ? strdup(minLabel) : NULL;
688
689 free(fMaxLimitLabel);
690 fMaxLimitLabel = maxLabel ? strdup(maxLabel) : NULL;
691
692 InvalidateLayout();
693
694 // TODO: This is for backwards compatibility and should
695 // probably be removed when breaking binary compatiblity.
696 // Applications like our own Mouse rely on this behavior.
697 if ((Flags() & B_SUPPORTS_LAYOUT) == 0)
698 ResizeToPreferred();
699
700 Invalidate();
701 }
702
703
704 const char*
MinLimitLabel() const705 BSlider::MinLimitLabel() const
706 {
707 return fMinLimitLabel;
708 }
709
710
711 const char*
MaxLimitLabel() const712 BSlider::MaxLimitLabel() const
713 {
714 return fMaxLimitLabel;
715 }
716
717
718 void
SetValue(int32 value)719 BSlider::SetValue(int32 value)
720 {
721 if (value < fMinValue)
722 value = fMinValue;
723
724 if (value > fMaxValue)
725 value = fMaxValue;
726
727 if (value == Value())
728 return;
729
730 _SetLocationForValue(value);
731
732 BRect oldThumbFrame = ThumbFrame();
733
734 // While it would be enough to do this dependent on fUseFillColor,
735 // that doesn't work out if DrawBar() has been overridden by a sub class
736 if (fOrientation == B_HORIZONTAL)
737 oldThumbFrame.top = BarFrame().top;
738 else
739 oldThumbFrame.left = BarFrame().left;
740
741 BControl::SetValueNoUpdate(value);
742 BRect invalid = oldThumbFrame | ThumbFrame();
743
744 if (Style() == B_TRIANGLE_THUMB) {
745 // 1) We need to take care of pixels touched because of anti-aliasing.
746 // 2) We need to update the region with the focus mark as well. (A
747 // method BSlider::FocusMarkFrame() would be nice as well.)
748 if (fOrientation == B_HORIZONTAL) {
749 if (IsFocus())
750 invalid.bottom += 2;
751 invalid.InsetBy(-1, 0);
752 } else {
753 if (IsFocus())
754 invalid.left -= 2;
755 invalid.InsetBy(0, -1);
756 }
757 }
758
759 Invalidate(invalid);
760
761 UpdateTextChanged();
762 }
763
764
765 int32
ValueForPoint(BPoint location) const766 BSlider::ValueForPoint(BPoint location) const
767 {
768 float min;
769 float max;
770 float position;
771 if (fOrientation == B_HORIZONTAL) {
772 min = _MinPosition();
773 max = _MaxPosition();
774 position = location.x;
775 } else {
776 max = _MinPosition();
777 min = _MaxPosition();
778 position = min + (max - location.y);
779 }
780
781 if (position < min)
782 position = min;
783
784 if (position > max)
785 position = max;
786
787 return (int32)roundf(((position - min) * (fMaxValue - fMinValue)
788 / (max - min)) + fMinValue);
789 }
790
791
792 void
SetPosition(float position)793 BSlider::SetPosition(float position)
794 {
795 if (position <= 0.0f)
796 SetValue(fMinValue);
797 else if (position >= 1.0f)
798 SetValue(fMaxValue);
799 else
800 SetValue((int32)(position * (fMaxValue - fMinValue) + fMinValue));
801 }
802
803
804 float
Position() const805 BSlider::Position() const
806 {
807 float range = (float)(fMaxValue - fMinValue);
808 if (range == 0.0f)
809 range = 1.0f;
810
811 return (float)(Value() - fMinValue) / range;
812 }
813
814
815 void
SetEnabled(bool on)816 BSlider::SetEnabled(bool on)
817 {
818 BControl::SetEnabled(on);
819 }
820
821
822 void
GetLimits(int32 * minimum,int32 * maximum) const823 BSlider::GetLimits(int32* minimum, int32* maximum) const
824 {
825 if (minimum != NULL)
826 *minimum = fMinValue;
827
828 if (maximum != NULL)
829 *maximum = fMaxValue;
830 }
831
832
833 // #pragma mark - drawing
834
835
836 void
Draw(BRect updateRect)837 BSlider::Draw(BRect updateRect)
838 {
839 // clear out background
840 BRegion background(updateRect);
841 background.Exclude(BarFrame());
842 bool drawBackground = true;
843 if (Parent() != NULL && (Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) {
844 // This view is embedded somewhere, most likely the Tracker Desktop
845 // shelf.
846 drawBackground = false;
847 }
848
849 #if USE_OFF_SCREEN_VIEW
850 if (!fOffScreenBits)
851 return;
852
853 if (fOffScreenBits->Lock()) {
854 fOffScreenView->SetViewColor(ViewColor());
855 fOffScreenView->SetLowColor(LowColor());
856 #endif
857
858 if (drawBackground && background.Frame().IsValid())
859 OffscreenView()->FillRegion(&background, B_SOLID_LOW);
860
861 #if USE_OFF_SCREEN_VIEW
862 fOffScreenView->Sync();
863 fOffScreenBits->Unlock();
864 }
865 #endif
866
867 DrawSlider();
868 }
869
870
871 void
DrawSlider()872 BSlider::DrawSlider()
873 {
874 if (LockLooper()) {
875 #if USE_OFF_SCREEN_VIEW
876 if (fOffScreenBits == NULL)
877 return;
878
879 if (fOffScreenBits->Lock()) {
880 #endif
881 DrawBar();
882 DrawHashMarks();
883 DrawThumb();
884 DrawFocusMark();
885 DrawText();
886
887 #if USE_OFF_SCREEN_VIEW
888 fOffScreenView->Sync();
889 fOffScreenBits->Unlock();
890
891 DrawBitmap(fOffScreenBits, B_ORIGIN);
892 }
893 #endif
894 UnlockLooper();
895 }
896 }
897
898
899 void
DrawBar()900 BSlider::DrawBar()
901 {
902 BRect frame = BarFrame();
903 BView* view = OffscreenView();
904
905 uint32 flags = be_control_look->Flags(this);
906 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
907 rgb_color rightFillColor = fBarColor;
908 rgb_color leftFillColor = fUseFillColor ? fFillColor : fBarColor;
909 be_control_look->DrawSliderBar(view, frame, frame, base, leftFillColor,
910 rightFillColor, Position(), flags, fOrientation);
911 }
912
913
914 void
DrawHashMarks()915 BSlider::DrawHashMarks()
916 {
917 if (fHashMarks == B_HASH_MARKS_NONE)
918 return;
919
920 BRect frame = HashMarksFrame();
921 BView* view = OffscreenView();
922
923 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
924 uint32 flags = be_control_look->Flags(this);
925 be_control_look->DrawSliderHashMarks(view, frame, frame, base,
926 fHashMarkCount, fHashMarks, flags, fOrientation);
927 }
928
929
930 void
DrawThumb()931 BSlider::DrawThumb()
932 {
933 if (Style() == B_BLOCK_THUMB)
934 _DrawBlockThumb();
935 else
936 _DrawTriangleThumb();
937 }
938
939
940 void
DrawFocusMark()941 BSlider::DrawFocusMark()
942 {
943 if (!IsFocus())
944 return;
945
946 OffscreenView()->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
947
948 BRect frame = ThumbFrame();
949
950 if (fStyle == B_BLOCK_THUMB) {
951 frame.left += 2.0f;
952 frame.top += 2.0f;
953 frame.right -= 3.0f;
954 frame.bottom -= 3.0f;
955 OffscreenView()->StrokeRect(frame);
956 } else {
957 if (fOrientation == B_HORIZONTAL) {
958 OffscreenView()->StrokeLine(BPoint(frame.left, frame.bottom + 2.0f),
959 BPoint(frame.right, frame.bottom + 2.0f));
960 } else {
961 OffscreenView()->StrokeLine(BPoint(frame.left - 2.0f, frame.top),
962 BPoint(frame.left - 2.0f, frame.bottom));
963 }
964 }
965 }
966
967
968 void
DrawText()969 BSlider::DrawText()
970 {
971 BRect bounds(Bounds());
972 BView* view = OffscreenView();
973
974 rgb_color base = ViewColor();
975 uint32 flags = be_control_look->Flags(this);
976
977 font_height fontHeight;
978 GetFontHeight(&fontHeight);
979 if (Orientation() == B_HORIZONTAL) {
980 if (Label() != NULL) {
981 be_control_look->DrawLabel(view, Label(), base, flags,
982 BPoint(0.0f, ceilf(fontHeight.ascent)));
983 }
984
985 // the update text is updated in SetValue() only
986 if (fUpdateText != NULL) {
987 be_control_look->DrawLabel(view, fUpdateText, base, flags,
988 BPoint(bounds.right - StringWidth(fUpdateText),
989 ceilf(fontHeight.ascent)));
990 }
991
992 if (fMinLimitLabel != NULL) {
993 be_control_look->DrawLabel(view, fMinLimitLabel, base, flags,
994 BPoint(0.0f, bounds.bottom - fontHeight.descent));
995 }
996
997 if (fMaxLimitLabel != NULL) {
998 be_control_look->DrawLabel(view, fMaxLimitLabel, base, flags,
999 BPoint(bounds.right - StringWidth(fMaxLimitLabel),
1000 bounds.bottom - fontHeight.descent));
1001 }
1002 } else {
1003 float lineHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent)
1004 + ceilf(fontHeight.leading);
1005 float baseLine = ceilf(fontHeight.ascent);
1006
1007 if (Label() != NULL) {
1008 be_control_look->DrawLabel(view, Label(), base, flags,
1009 BPoint((bounds.Width() - StringWidth(Label())) / 2.0,
1010 baseLine));
1011 baseLine += lineHeight;
1012 }
1013
1014 if (fMaxLimitLabel != NULL) {
1015 be_control_look->DrawLabel(view, fMaxLimitLabel, base, flags,
1016 BPoint((bounds.Width() - StringWidth(fMaxLimitLabel)) / 2.0,
1017 baseLine));
1018 }
1019
1020 baseLine = bounds.bottom - ceilf(fontHeight.descent);
1021
1022 if (fMinLimitLabel != NULL) {
1023 be_control_look->DrawLabel(view, fMinLimitLabel, base, flags,
1024 BPoint((bounds.Width() - StringWidth(fMinLimitLabel)) / 2.0,
1025 baseLine));
1026 baseLine -= lineHeight;
1027 }
1028
1029 if (fUpdateText != NULL) {
1030 be_control_look->DrawLabel(view, fUpdateText, base, flags,
1031 BPoint((bounds.Width() - StringWidth(fUpdateText)) / 2.0,
1032 baseLine));
1033 }
1034 }
1035 }
1036
1037
1038 // #pragma mark -
1039
1040
1041 const char*
UpdateText() const1042 BSlider::UpdateText() const
1043 {
1044 return NULL;
1045 }
1046
1047
1048 void
UpdateTextChanged()1049 BSlider::UpdateTextChanged()
1050 {
1051 // update text label
1052 float oldWidth = 0.0;
1053 if (fUpdateText != NULL)
1054 oldWidth = StringWidth(fUpdateText);
1055
1056 const char* oldUpdateText = fUpdateText;
1057 fUpdateText = UpdateText();
1058 bool updateTextOnOff = (fUpdateText == NULL && oldUpdateText != NULL)
1059 || (fUpdateText != NULL && oldUpdateText == NULL);
1060
1061 float newWidth = 0.0;
1062 if (fUpdateText != NULL)
1063 newWidth = StringWidth(fUpdateText);
1064
1065 float width = ceilf(std::max(newWidth, oldWidth)) + 2.0f;
1066 if (width != 0) {
1067 font_height fontHeight;
1068 GetFontHeight(&fontHeight);
1069
1070 float height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
1071 float lineHeight = height + ceilf(fontHeight.leading);
1072 BRect invalid(Bounds());
1073 if (fOrientation == B_HORIZONTAL)
1074 invalid = BRect(invalid.right - width, 0, invalid.right, height);
1075 else {
1076 if (!updateTextOnOff) {
1077 invalid.left = (invalid.left + invalid.right - width) / 2;
1078 invalid.right = invalid.left + width;
1079 if (fMinLimitLabel != NULL)
1080 invalid.bottom -= lineHeight;
1081
1082 invalid.top = invalid.bottom - height;
1083 }
1084 }
1085 Invalidate(invalid);
1086 }
1087
1088 float oldMaxUpdateTextWidth = fMaxUpdateTextWidth;
1089 fMaxUpdateTextWidth = MaxUpdateTextWidth();
1090 if (oldMaxUpdateTextWidth != fMaxUpdateTextWidth)
1091 InvalidateLayout();
1092 }
1093
1094
1095 BRect
BarFrame() const1096 BSlider::BarFrame() const
1097 {
1098 BRect frame(Bounds());
1099
1100 font_height fontHeight;
1101 GetFontHeight(&fontHeight);
1102
1103 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
1104 float leading = ceilf(fontHeight.leading);
1105
1106 float thumbInset;
1107 if (fStyle == B_BLOCK_THUMB)
1108 thumbInset = 8.0;
1109 else
1110 thumbInset = 7.0;
1111
1112 if (Orientation() == B_HORIZONTAL) {
1113 frame.left = thumbInset;
1114 frame.top = 6.0 + (Label() || fUpdateText ? textHeight + 4.0 : 0.0);
1115 frame.right -= thumbInset;
1116 frame.bottom = frame.top + fBarThickness;
1117 } else {
1118 frame.left = floorf((frame.Width() - fBarThickness) / 2.0);
1119 frame.top = thumbInset;
1120 if (Label() != NULL)
1121 frame.top += textHeight;
1122
1123 if (fMaxLimitLabel != NULL) {
1124 frame.top += textHeight;
1125 if (Label())
1126 frame.top += leading;
1127 }
1128
1129 frame.right = frame.left + fBarThickness;
1130 frame.bottom = frame.bottom - thumbInset;
1131 if (fMinLimitLabel != NULL)
1132 frame.bottom -= textHeight;
1133
1134 if (fUpdateText != NULL) {
1135 frame.bottom -= textHeight;
1136 if (fMinLimitLabel != NULL)
1137 frame.bottom -= leading;
1138 }
1139 }
1140
1141 return frame;
1142 }
1143
1144
1145 BRect
HashMarksFrame() const1146 BSlider::HashMarksFrame() const
1147 {
1148 BRect frame(BarFrame());
1149
1150 if (fOrientation == B_HORIZONTAL) {
1151 frame.top -= 6.0;
1152 frame.bottom += 6.0;
1153 } else {
1154 frame.left -= 6.0;
1155 frame.right += 6.0;
1156 }
1157
1158 return frame;
1159 }
1160
1161
1162 BRect
ThumbFrame() const1163 BSlider::ThumbFrame() const
1164 {
1165 // TODO: The slider looks really ugly and broken when it is too little.
1166 // I would suggest using BarFrame() here to get the top and bottom coords
1167 // and spread them further apart for the thumb
1168
1169 BRect frame = Bounds();
1170
1171 font_height fontHeight;
1172 GetFontHeight(&fontHeight);
1173
1174 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
1175
1176 if (fStyle == B_BLOCK_THUMB) {
1177 if (Orientation() == B_HORIZONTAL) {
1178 frame.left = floorf(Position() * (_MaxPosition()
1179 - _MinPosition()) + _MinPosition()) - 8;
1180 frame.top = 2 + (Label() || fUpdateText ? textHeight + 4 : 0);
1181 frame.right = frame.left + 17;
1182 frame.bottom = frame.top + fBarThickness + 7;
1183 } else {
1184 frame.left = floor((frame.Width() - fBarThickness) / 2) - 4;
1185 frame.top = floorf(Position() * (_MaxPosition()
1186 - _MinPosition()) + _MinPosition()) - 8;
1187 frame.right = frame.left + fBarThickness + 7;
1188 frame.bottom = frame.top + 17;
1189 }
1190 } else {
1191 if (Orientation() == B_HORIZONTAL) {
1192 frame.left = floorf(Position() * (_MaxPosition()
1193 - _MinPosition()) + _MinPosition()) - 6;
1194 frame.right = frame.left + 12;
1195 frame.top = 3 + fBarThickness + (Label() ? textHeight + 4 : 0);
1196 frame.bottom = frame.top + 8;
1197 } else {
1198 frame.left = floorf((frame.Width() + fBarThickness) / 2) - 3;
1199 frame.top = floorf(Position() * (_MaxPosition()
1200 - _MinPosition())) + _MinPosition() - 6;
1201 frame.right = frame.left + 8;
1202 frame.bottom = frame.top + 12;
1203 }
1204 }
1205
1206 return frame;
1207 }
1208
1209
1210 void
SetFlags(uint32 flags)1211 BSlider::SetFlags(uint32 flags)
1212 {
1213 BControl::SetFlags(flags);
1214 }
1215
1216
1217 void
SetResizingMode(uint32 mode)1218 BSlider::SetResizingMode(uint32 mode)
1219 {
1220 BControl::SetResizingMode(mode);
1221 }
1222
1223
1224 void
GetPreferredSize(float * _width,float * _height)1225 BSlider::GetPreferredSize(float* _width, float* _height)
1226 {
1227 BSize preferredSize = PreferredSize();
1228
1229 if (Orientation() == B_HORIZONTAL) {
1230 if (_width != NULL) {
1231 // NOTE: For compatibility reasons, a horizontal BSlider
1232 // never shrinks horizontally. This only affects applications
1233 // which do not use the new layout system.
1234 *_width = std::max(Bounds().Width(), preferredSize.width);
1235 }
1236
1237 if (_height != NULL)
1238 *_height = preferredSize.height;
1239 } else {
1240 if (_width != NULL)
1241 *_width = preferredSize.width;
1242
1243 if (_height != NULL) {
1244 // NOTE: Similarly, a vertical BSlider never shrinks
1245 // vertically. This only affects applications which do not
1246 // use the new layout system.
1247 *_height = std::max(Bounds().Height(), preferredSize.height);
1248 }
1249 }
1250 }
1251
1252
1253 void
ResizeToPreferred()1254 BSlider::ResizeToPreferred()
1255 {
1256 BControl::ResizeToPreferred();
1257 }
1258
1259
1260 status_t
Invoke(BMessage * message)1261 BSlider::Invoke(BMessage* message)
1262 {
1263 return BControl::Invoke(message);
1264 }
1265
1266
1267 BHandler*
ResolveSpecifier(BMessage * message,int32 index,BMessage * specifier,int32 command,const char * property)1268 BSlider::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
1269 int32 command, const char* property)
1270 {
1271 return BControl::ResolveSpecifier(message, index, specifier, command,
1272 property);
1273 }
1274
1275
1276 status_t
GetSupportedSuites(BMessage * message)1277 BSlider::GetSupportedSuites(BMessage* message)
1278 {
1279 return BControl::GetSupportedSuites(message);
1280 }
1281
1282
1283 void
SetModificationMessage(BMessage * message)1284 BSlider::SetModificationMessage(BMessage* message)
1285 {
1286 delete fModificationMessage;
1287 fModificationMessage = message;
1288 }
1289
1290
1291 BMessage*
ModificationMessage() const1292 BSlider::ModificationMessage() const
1293 {
1294 return fModificationMessage;
1295 }
1296
1297
1298 void
SetSnoozeAmount(int32 snoozeTime)1299 BSlider::SetSnoozeAmount(int32 snoozeTime)
1300 {
1301 if (snoozeTime < 10000)
1302 snoozeTime = 10000;
1303 else if (snoozeTime > 1000000)
1304 snoozeTime = 1000000;
1305
1306 fSnoozeAmount = snoozeTime;
1307 }
1308
1309
1310 int32
SnoozeAmount() const1311 BSlider::SnoozeAmount() const
1312 {
1313 return fSnoozeAmount;
1314 }
1315
1316
1317 void
SetKeyIncrementValue(int32 incrementValue)1318 BSlider::SetKeyIncrementValue(int32 incrementValue)
1319 {
1320 fKeyIncrementValue = incrementValue;
1321 }
1322
1323
1324 int32
KeyIncrementValue() const1325 BSlider::KeyIncrementValue() const
1326 {
1327 return fKeyIncrementValue;
1328 }
1329
1330
1331 void
SetHashMarkCount(int32 hashMarkCount)1332 BSlider::SetHashMarkCount(int32 hashMarkCount)
1333 {
1334 fHashMarkCount = hashMarkCount;
1335 Invalidate();
1336 }
1337
1338
1339 int32
HashMarkCount() const1340 BSlider::HashMarkCount() const
1341 {
1342 return fHashMarkCount;
1343 }
1344
1345
1346 void
SetHashMarks(hash_mark_location where)1347 BSlider::SetHashMarks(hash_mark_location where)
1348 {
1349 fHashMarks = where;
1350 // TODO: enable if the hashmark look is influencing the control size!
1351 // InvalidateLayout();
1352 Invalidate();
1353 }
1354
1355
1356 hash_mark_location
HashMarks() const1357 BSlider::HashMarks() const
1358 {
1359 return fHashMarks;
1360 }
1361
1362
1363 void
SetStyle(thumb_style style)1364 BSlider::SetStyle(thumb_style style)
1365 {
1366 fStyle = style;
1367 InvalidateLayout();
1368 Invalidate();
1369 }
1370
1371
1372 thumb_style
Style() const1373 BSlider::Style() const
1374 {
1375 return fStyle;
1376 }
1377
1378
1379 void
SetBarColor(rgb_color barColor)1380 BSlider::SetBarColor(rgb_color barColor)
1381 {
1382 fBarColor = barColor;
1383 Invalidate(BarFrame());
1384 }
1385
1386
1387 rgb_color
BarColor() const1388 BSlider::BarColor() const
1389 {
1390 return fBarColor;
1391 }
1392
1393
1394 void
UseFillColor(bool useFill,const rgb_color * barColor)1395 BSlider::UseFillColor(bool useFill, const rgb_color* barColor)
1396 {
1397 fUseFillColor = useFill;
1398
1399 if (useFill && barColor)
1400 fFillColor = *barColor;
1401
1402 Invalidate(BarFrame());
1403 }
1404
1405
1406 bool
FillColor(rgb_color * barColor) const1407 BSlider::FillColor(rgb_color* barColor) const
1408 {
1409 if (barColor && fUseFillColor)
1410 *barColor = fFillColor;
1411
1412 return fUseFillColor;
1413 }
1414
1415
1416 BView*
OffscreenView() const1417 BSlider::OffscreenView() const
1418 {
1419 #if USE_OFF_SCREEN_VIEW
1420 return fOffScreenView;
1421 #else
1422 return (BView*)this;
1423 #endif
1424 }
1425
1426
1427 orientation
Orientation() const1428 BSlider::Orientation() const
1429 {
1430 return fOrientation;
1431 }
1432
1433
1434 void
SetOrientation(orientation posture)1435 BSlider::SetOrientation(orientation posture)
1436 {
1437 if (fOrientation == posture)
1438 return;
1439
1440 fOrientation = posture;
1441 InvalidateLayout();
1442 Invalidate();
1443 }
1444
1445
1446 float
BarThickness() const1447 BSlider::BarThickness() const
1448 {
1449 return fBarThickness;
1450 }
1451
1452
1453 void
SetBarThickness(float thickness)1454 BSlider::SetBarThickness(float thickness)
1455 {
1456 if (thickness < 1.0)
1457 thickness = 1.0;
1458 else
1459 thickness = roundf(thickness);
1460
1461 if (thickness != fBarThickness) {
1462 // calculate invalid barframe and extend by hashmark size
1463 float hInset = 0.0;
1464 float vInset = 0.0;
1465 if (fOrientation == B_HORIZONTAL)
1466 vInset = -6.0;
1467 else
1468 hInset = -6.0;
1469 BRect invalid = BarFrame().InsetByCopy(hInset, vInset) | ThumbFrame();
1470
1471 fBarThickness = thickness;
1472
1473 invalid = invalid | BarFrame().InsetByCopy(hInset, vInset)
1474 | ThumbFrame();
1475 Invalidate(invalid);
1476 InvalidateLayout();
1477 }
1478 }
1479
1480
1481 void
SetFont(const BFont * font,uint32 properties)1482 BSlider::SetFont(const BFont* font, uint32 properties)
1483 {
1484 BControl::SetFont(font, properties);
1485
1486 #if USE_OFF_SCREEN_VIEW
1487 if (fOffScreenView && fOffScreenBits) {
1488 if (fOffScreenBits->Lock()) {
1489 fOffScreenView->SetFont(font, properties);
1490 fOffScreenBits->Unlock();
1491 }
1492 }
1493 #endif
1494
1495 InvalidateLayout();
1496 }
1497
1498
1499 void
SetLimits(int32 minimum,int32 maximum)1500 BSlider::SetLimits(int32 minimum, int32 maximum)
1501 {
1502 if (minimum <= maximum) {
1503 fMinValue = minimum;
1504 fMaxValue = maximum;
1505
1506 int32 value = Value();
1507 value = std::max(minimum, value);
1508 value = std::min(maximum, value);
1509
1510 if (value != Value())
1511 SetValue(value);
1512 }
1513 }
1514
1515
1516 float
MaxUpdateTextWidth()1517 BSlider::MaxUpdateTextWidth()
1518 {
1519 // very simplistic implementation that assumes the string will be widest
1520 // at the maximum value
1521 int32 value = Value();
1522 SetValueNoUpdate(fMaxValue);
1523 float width = StringWidth(UpdateText());
1524 SetValueNoUpdate(value);
1525 // in case the derived class uses a fixed buffer, the contents
1526 // should be reset for the old value
1527 UpdateText();
1528
1529 return width;
1530 }
1531
1532
1533 // #pragma mark - layout related
1534
1535
1536 BSize
MinSize()1537 BSlider::MinSize()
1538 {
1539 return BLayoutUtils::ComposeSize(ExplicitMinSize(), _ValidateMinSize());
1540 }
1541
1542
1543 BSize
MaxSize()1544 BSlider::MaxSize()
1545 {
1546 BSize maxSize = _ValidateMinSize();
1547 if (fOrientation == B_HORIZONTAL)
1548 maxSize.width = B_SIZE_UNLIMITED;
1549 else
1550 maxSize.height = B_SIZE_UNLIMITED;
1551
1552 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), maxSize);
1553 }
1554
1555
1556 BSize
PreferredSize()1557 BSlider::PreferredSize()
1558 {
1559 BSize preferredSize = _ValidateMinSize();
1560 if (fOrientation == B_HORIZONTAL)
1561 preferredSize.width = std::max(100.0f, preferredSize.width);
1562 else
1563 preferredSize.height = std::max(100.0f, preferredSize.height);
1564
1565 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), preferredSize);
1566 }
1567
1568
1569 status_t
SetIcon(const BBitmap * icon,uint32 flags)1570 BSlider::SetIcon(const BBitmap* icon, uint32 flags)
1571 {
1572 return BControl::SetIcon(icon, flags);
1573 }
1574
1575
1576 void
LayoutInvalidated(bool descendants)1577 BSlider::LayoutInvalidated(bool descendants)
1578 {
1579 // invalidate cached preferred size
1580 fMinSize.Set(-1, -1);
1581 }
1582
1583
1584 // #pragma mark - private
1585
1586
1587 void
_DrawBlockThumb()1588 BSlider::_DrawBlockThumb()
1589 {
1590 BRect frame = ThumbFrame();
1591 BView* view = OffscreenView();
1592
1593 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
1594 uint32 flags = be_control_look->Flags(this);
1595 be_control_look->DrawSliderThumb(view, frame, frame, base, flags,
1596 fOrientation);
1597 }
1598
1599
1600 void
_DrawTriangleThumb()1601 BSlider::_DrawTriangleThumb()
1602 {
1603 BRect frame = ThumbFrame();
1604 BView* view = OffscreenView();
1605 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
1606 uint32 flags = be_control_look->Flags(this);
1607 be_control_look->DrawSliderTriangle(view, frame, frame, base, flags,
1608 fOrientation);
1609 }
1610
1611
1612 BPoint
_Location() const1613 BSlider::_Location() const
1614 {
1615 return fLocation;
1616 }
1617
1618
1619 void
_SetLocationForValue(int32 value)1620 BSlider::_SetLocationForValue(int32 value)
1621 {
1622 BPoint loc;
1623 float range = (float)(fMaxValue - fMinValue);
1624 if (range == 0)
1625 range = 1;
1626
1627 float pos = (float)(value - fMinValue) / range *
1628 (_MaxPosition() - _MinPosition());
1629
1630 if (fOrientation == B_HORIZONTAL) {
1631 loc.x = ceil(_MinPosition() + pos);
1632 loc.y = 0;
1633 } else {
1634 loc.x = 0;
1635 loc.y = floor(_MaxPosition() - pos);
1636 }
1637 fLocation = loc;
1638 }
1639
1640
1641 float
_MinPosition() const1642 BSlider::_MinPosition() const
1643 {
1644 if (fOrientation == B_HORIZONTAL)
1645 return BarFrame().left + 1.0f;
1646
1647 return BarFrame().bottom - 1.0f;
1648 }
1649
1650
1651 float
_MaxPosition() const1652 BSlider::_MaxPosition() const
1653 {
1654 if (fOrientation == B_HORIZONTAL)
1655 return BarFrame().right - 1.0f;
1656
1657 return BarFrame().top + 1.0f;
1658 }
1659
1660
1661 BSize
_ValidateMinSize()1662 BSlider::_ValidateMinSize()
1663 {
1664 if (fMinSize.width >= 0) {
1665 // the preferred size is up to date
1666 return fMinSize;
1667 }
1668
1669 font_height fontHeight;
1670 GetFontHeight(&fontHeight);
1671
1672 float width = 0.0f;
1673 float height = 0.0f;
1674
1675 if (fMaxUpdateTextWidth < 0.0f)
1676 fMaxUpdateTextWidth = MaxUpdateTextWidth();
1677
1678 if (Orientation() == B_HORIZONTAL) {
1679 height = 12.0f + fBarThickness;
1680 int32 rows = 0;
1681
1682 float labelWidth = 0;
1683 int32 labelRows = 0;
1684 float labelSpacing = StringWidth("M") * 2;
1685 if (Label() != NULL) {
1686 labelWidth = StringWidth(Label());
1687 labelRows = 1;
1688 }
1689 if (fMaxUpdateTextWidth > 0.0f) {
1690 if (labelWidth > 0)
1691 labelWidth += labelSpacing;
1692
1693 labelWidth += fMaxUpdateTextWidth;
1694 labelRows = 1;
1695 }
1696 rows += labelRows;
1697
1698 if (MinLimitLabel() != NULL)
1699 width = StringWidth(MinLimitLabel());
1700
1701 if (MaxLimitLabel() != NULL) {
1702 // some space between the labels
1703 if (MinLimitLabel() != NULL)
1704 width += labelSpacing;
1705
1706 width += StringWidth(MaxLimitLabel());
1707 }
1708
1709 if (labelWidth > width)
1710 width = labelWidth;
1711
1712 if (width < 32.0f)
1713 width = 32.0f;
1714
1715 if (MinLimitLabel() || MaxLimitLabel())
1716 rows++;
1717
1718 height += rows * (ceilf(fontHeight.ascent)
1719 + ceilf(fontHeight.descent) + 4.0);
1720 } else {
1721 // B_VERTICAL
1722 width = 12.0f + fBarThickness;
1723 height = 32.0f;
1724
1725 float lineHeightNoLeading = ceilf(fontHeight.ascent)
1726 + ceilf(fontHeight.descent);
1727 float lineHeight = lineHeightNoLeading + ceilf(fontHeight.leading);
1728
1729 // find largest label
1730 float labelWidth = 0;
1731 if (Label() != NULL) {
1732 labelWidth = StringWidth(Label());
1733 height += lineHeightNoLeading;
1734 }
1735 if (MaxLimitLabel() != NULL) {
1736 labelWidth = std::max(labelWidth, StringWidth(MaxLimitLabel()));
1737 height += Label() ? lineHeight : lineHeightNoLeading;
1738 }
1739 if (MinLimitLabel() != NULL) {
1740 labelWidth = std::max(labelWidth, StringWidth(MinLimitLabel()));
1741 height += lineHeightNoLeading;
1742 }
1743 if (fMaxUpdateTextWidth > 0.0f) {
1744 labelWidth = std::max(labelWidth, fMaxUpdateTextWidth);
1745 height += MinLimitLabel() ? lineHeight : lineHeightNoLeading;
1746 }
1747
1748 width = std::max(labelWidth, width);
1749 }
1750
1751 fMinSize.width = width;
1752 fMinSize.height = height;
1753
1754 ResetLayoutInvalidation();
1755
1756 return fMinSize;
1757 }
1758
1759
1760 // #pragma mark - FBC padding
1761
_ReservedSlider6()1762 void BSlider::_ReservedSlider6() {}
_ReservedSlider7()1763 void BSlider::_ReservedSlider7() {}
_ReservedSlider8()1764 void BSlider::_ReservedSlider8() {}
_ReservedSlider9()1765 void BSlider::_ReservedSlider9() {}
_ReservedSlider10()1766 void BSlider::_ReservedSlider10() {}
_ReservedSlider11()1767 void BSlider::_ReservedSlider11() {}
_ReservedSlider12()1768 void BSlider::_ReservedSlider12() {}
1769
1770
1771 BSlider&
operator =(const BSlider &)1772 BSlider::operator=(const BSlider&)
1773 {
1774 return *this;
1775 }
1776
1777
1778 // #pragma mark - BeOS compatibility
1779
1780
1781 #if __GNUC__ < 3
1782
1783 extern "C" void
GetLimits__7BSliderPlT1(BSlider * slider,int32 * minimum,int32 * maximum)1784 GetLimits__7BSliderPlT1(BSlider* slider, int32* minimum, int32* maximum)
1785 {
1786 slider->GetLimits(minimum, maximum);
1787 }
1788
1789
1790 extern "C" void
_ReservedSlider4__7BSlider(BSlider * slider,int32 minimum,int32 maximum)1791 _ReservedSlider4__7BSlider(BSlider* slider, int32 minimum, int32 maximum)
1792 {
1793 slider->BSlider::SetLimits(minimum, maximum);
1794 }
1795
1796 extern "C" float
_ReservedSlider5__7BSlider(BSlider * slider)1797 _ReservedSlider5__7BSlider(BSlider* slider)
1798 {
1799 return slider->BSlider::MaxUpdateTextWidth();
1800 }
1801
1802
1803 extern "C" void
_ReservedSlider1__7BSlider(BSlider * slider,orientation _orientation)1804 _ReservedSlider1__7BSlider(BSlider* slider, orientation _orientation)
1805 {
1806 slider->BSlider::SetOrientation(_orientation);
1807 }
1808
1809
1810 extern "C" void
_ReservedSlider2__7BSlider(BSlider * slider,float thickness)1811 _ReservedSlider2__7BSlider(BSlider* slider, float thickness)
1812 {
1813 slider->BSlider::SetBarThickness(thickness);
1814 }
1815
1816
1817 extern "C" void
_ReservedSlider3__7BSlider(BSlider * slider,const BFont * font,uint32 properties)1818 _ReservedSlider3__7BSlider(BSlider* slider, const BFont* font,
1819 uint32 properties)
1820 {
1821 slider->BSlider::SetFont(font, properties);
1822 }
1823
1824
1825 #endif // __GNUC__ < 3
1826
1827
1828 extern "C" void
B_IF_GCC_2(InvalidateLayout__7BSliderb,_ZN7BSlider16InvalidateLayoutEb)1829 B_IF_GCC_2(InvalidateLayout__7BSliderb, _ZN7BSlider16InvalidateLayoutEb)(
1830 BView* view, bool descendants)
1831 {
1832 perform_data_layout_invalidated data;
1833 data.descendants = descendants;
1834
1835 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
1836 }
1837