tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / ChannelSlider.cpp
blob8f8d41a0d95430b6d0fceb1c61634a9dafa76137
1 /*
2 * Copyright 2005-2015, Haiku Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stefano Ceccherini (stefano.ceccherini@gmail.com)
7 * Stephan Aßmus <superstippi@gmx.de>
8 */
10 #include <ChannelSlider.h>
12 #include <new>
14 #include <Bitmap.h>
15 #include <ControlLook.h>
16 #include <Debug.h>
17 #include <PropertyInfo.h>
18 #include <Screen.h>
19 #include <Window.h>
22 const static unsigned char
23 kVerticalKnobData[] = {
24 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
25 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
26 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff,
27 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff,
28 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
29 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
30 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
31 0xff, 0x00, 0x3f, 0x3f, 0xcb, 0xcb, 0xcb, 0xcb, 0x3f, 0x3f, 0x00, 0x12,
32 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
33 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
34 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
35 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
36 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12,
37 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12,
38 0xff, 0xff, 0xff, 0xff, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff
42 const static unsigned char
43 kHorizontalKnobData[] = {
44 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
46 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x3f,
47 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff,
48 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xcb, 0x3f, 0x3f, 0x3f, 0x3f,
49 0x3f, 0x00, 0x12, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xcb,
50 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 0xff, 0x00, 0x3f, 0x3f,
51 0x3f, 0x3f, 0x3f, 0xcb, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff,
52 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xcb, 0x3f, 0x3f, 0x3f, 0x3f,
53 0x3f, 0x00, 0x12, 0xff, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
54 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 0xff, 0x00, 0x3f, 0x3f,
55 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff,
56 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x0c, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0x12, 0x12, 0x12, 0x12,
58 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
63 static property_info
64 sPropertyInfo[] = {
65 { "Orientation",
66 { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
67 { B_DIRECT_SPECIFIER, 0 }, NULL, 0, { B_INT32_TYPE }
70 { 0 }
74 const static float kPadding = 3.0;
77 BChannelSlider::BChannelSlider(BRect area, const char* name, const char* label,
78 BMessage* model, int32 channels, uint32 resizeMode, uint32 flags)
79 : BChannelControl(area, name, label, model, channels, resizeMode, flags)
81 _InitData();
85 BChannelSlider::BChannelSlider(BRect area, const char* name, const char* label,
86 BMessage* model, orientation orientation, int32 channels,
87 uint32 resizeMode, uint32 flags)
88 : BChannelControl(area, name, label, model, channels, resizeMode, flags)
91 _InitData();
92 SetOrientation(orientation);
96 BChannelSlider::BChannelSlider(const char* name, const char* label,
97 BMessage* model, orientation orientation, int32 channels,
98 uint32 flags)
99 : BChannelControl(name, label, model, channels, flags)
102 _InitData();
103 SetOrientation(orientation);
107 BChannelSlider::BChannelSlider(BMessage* archive)
108 : BChannelControl(archive)
110 _InitData();
112 orientation orient;
113 if (archive->FindInt32("_orient", (int32*)&orient) == B_OK)
114 SetOrientation(orient);
118 BChannelSlider::~BChannelSlider()
120 delete fBacking;
121 delete fLeftKnob;
122 delete fMidKnob;
123 delete fRightKnob;
124 delete[] fInitialValues;
128 BArchivable*
129 BChannelSlider::Instantiate(BMessage* archive)
131 if (validate_instantiation(archive, "BChannelSlider"))
132 return new (std::nothrow) BChannelSlider(archive);
134 return NULL;
138 status_t
139 BChannelSlider::Archive(BMessage* into, bool deep) const
141 status_t status = BChannelControl::Archive(into, deep);
142 if (status == B_OK)
143 status = into->AddInt32("_orient", (int32)Orientation());
145 return status;
149 void
150 BChannelSlider::AttachedToWindow()
152 BView* parent = Parent();
153 if (parent != NULL)
154 SetViewColor(parent->ViewColor());
156 BChannelControl::AttachedToWindow();
160 void
161 BChannelSlider::AllAttached()
163 BChannelControl::AllAttached();
167 void
168 BChannelSlider::DetachedFromWindow()
170 BChannelControl::DetachedFromWindow();
174 void
175 BChannelSlider::AllDetached()
177 BChannelControl::AllDetached();
181 void
182 BChannelSlider::MessageReceived(BMessage* message)
184 switch (message->what) {
185 case B_SET_PROPERTY: {
186 case B_GET_PROPERTY:
187 BMessage reply(B_REPLY);
188 int32 index = 0;
189 BMessage specifier;
190 int32 what = 0;
191 const char* property = NULL;
192 bool handled = false;
193 status_t status = message->GetCurrentSpecifier(&index, &specifier,
194 &what, &property);
195 BPropertyInfo propInfo(sPropertyInfo);
196 if (status == B_OK
197 && propInfo.FindMatch(message, index, &specifier, what,
198 property) >= 0) {
199 handled = true;
200 if (message->what == B_SET_PROPERTY) {
201 orientation orient;
202 if (specifier.FindInt32("data", (int32*)&orient) == B_OK) {
203 SetOrientation(orient);
204 Invalidate(Bounds());
206 } else if (message->what == B_GET_PROPERTY)
207 reply.AddInt32("result", (int32)Orientation());
208 else
209 status = B_BAD_SCRIPT_SYNTAX;
212 if (handled) {
213 reply.AddInt32("error", status);
214 message->SendReply(&reply);
215 } else {
216 BChannelControl::MessageReceived(message);
218 } break;
220 default:
221 BChannelControl::MessageReceived(message);
222 break;
227 void
228 BChannelSlider::Draw(BRect updateRect)
230 _UpdateFontDimens();
231 _DrawThumbs();
233 BRect bounds(Bounds());
234 if (Label()) {
235 float labelWidth = StringWidth(Label());
236 DrawString(Label(), BPoint((bounds.Width() - labelWidth) / 2.0,
237 fBaseLine));
240 if (MinLimitLabel()) {
241 if (fIsVertical) {
242 if (MinLimitLabel()) {
243 float x = (bounds.Width() - StringWidth(MinLimitLabel()))
244 / 2.0;
245 DrawString(MinLimitLabel(), BPoint(x, bounds.bottom
246 - kPadding));
248 } else {
249 if (MinLimitLabel()) {
250 DrawString(MinLimitLabel(), BPoint(kPadding, bounds.bottom
251 - kPadding));
256 if (MaxLimitLabel()) {
257 if (fIsVertical) {
258 if (MaxLimitLabel()) {
259 float x = (bounds.Width() - StringWidth(MaxLimitLabel()))
260 / 2.0;
261 DrawString(MaxLimitLabel(), BPoint(x, 2 * fLineFeed));
263 } else {
264 if (MaxLimitLabel()) {
265 DrawString(MaxLimitLabel(), BPoint(bounds.right - kPadding
266 - StringWidth(MaxLimitLabel()), bounds.bottom - kPadding));
273 void
274 BChannelSlider::MouseDown(BPoint where)
276 if (!IsEnabled())
277 BControl::MouseDown(where);
278 else {
279 fCurrentChannel = -1;
280 fMinPoint = 0;
282 // Search the channel on which the mouse was over
283 int32 numChannels = CountChannels();
284 for (int32 channel = 0; channel < numChannels; channel++) {
285 BRect frame = ThumbFrameFor(channel);
286 frame.OffsetBy(fClickDelta);
288 float range = ThumbRangeFor(channel);
289 if (fIsVertical) {
290 fMinPoint = frame.top + frame.Height() / 2;
291 frame.bottom += range;
292 } else {
293 // TODO: Fix this, the clickzone isn't perfect
294 frame.right += range;
295 fMinPoint = frame.Width();
298 // Click was on a slider.
299 if (frame.Contains(where)) {
300 fCurrentChannel = channel;
301 SetCurrentChannel(channel);
302 break;
306 // Click wasn't on a slider. Bail out.
307 if (fCurrentChannel == -1)
308 return;
310 uint32 buttons = 0;
311 BMessage* currentMessage = Window()->CurrentMessage();
312 if (currentMessage != NULL)
313 currentMessage->FindInt32("buttons", (int32*)&buttons);
315 fAllChannels = (buttons & B_SECONDARY_MOUSE_BUTTON) == 0;
317 if (fInitialValues != NULL && fAllChannels) {
318 delete[] fInitialValues;
319 fInitialValues = NULL;
322 if (fInitialValues == NULL)
323 fInitialValues = new (std::nothrow) int32[numChannels];
325 if (fInitialValues) {
326 if (fAllChannels) {
327 for (int32 i = 0; i < numChannels; i++)
328 fInitialValues[i] = ValueFor(i);
329 } else {
330 fInitialValues[fCurrentChannel] = ValueFor(fCurrentChannel);
334 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
335 if (!IsTracking()) {
336 SetTracking(true);
337 _DrawThumbs();
338 Flush();
341 _MouseMovedCommon(where, B_ORIGIN);
342 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS |
343 B_NO_POINTER_HISTORY);
344 } else {
345 do {
346 snooze(30000);
347 GetMouse(&where, &buttons);
348 _MouseMovedCommon(where, B_ORIGIN);
349 } while (buttons != 0);
350 _FinishChange();
351 fCurrentChannel = -1;
352 fAllChannels = false;
358 void
359 BChannelSlider::MouseUp(BPoint where)
361 if (IsEnabled() && IsTracking()) {
362 _FinishChange();
363 SetTracking(false);
364 fAllChannels = false;
365 fCurrentChannel = -1;
366 fMinPoint = 0;
367 } else {
368 BChannelControl::MouseUp(where);
373 void
374 BChannelSlider::MouseMoved(BPoint where, uint32 code, const BMessage* message)
376 if (IsEnabled() && IsTracking())
377 _MouseMovedCommon(where, B_ORIGIN);
378 else
379 BChannelControl::MouseMoved(where, code, message);
383 void
384 BChannelSlider::WindowActivated(bool state)
386 BChannelControl::WindowActivated(state);
390 void
391 BChannelSlider::KeyDown(const char* bytes, int32 numBytes)
393 BControl::KeyDown(bytes, numBytes);
397 void
398 BChannelSlider::KeyUp(const char* bytes, int32 numBytes)
400 BView::KeyUp(bytes, numBytes);
404 void
405 BChannelSlider::FrameResized(float newWidth, float newHeight)
407 BChannelControl::FrameResized(newWidth, newHeight);
409 delete fBacking;
410 fBacking = NULL;
412 Invalidate(Bounds());
416 void
417 BChannelSlider::SetFont(const BFont* font, uint32 mask)
419 BChannelControl::SetFont(font, mask);
423 void
424 BChannelSlider::MakeFocus(bool focusState)
426 if (focusState && !IsFocus())
427 fFocusChannel = -1;
428 BChannelControl::MakeFocus(focusState);
432 void
433 BChannelSlider::GetPreferredSize(float* width, float* height)
435 _UpdateFontDimens();
437 if (fIsVertical) {
438 *width = 11.0 * CountChannels();
439 *width = max_c(*width, ceilf(StringWidth(Label())));
440 *width = max_c(*width, ceilf(StringWidth(MinLimitLabel())));
441 *width = max_c(*width, ceilf(StringWidth(MaxLimitLabel())));
442 *width += kPadding * 2.0;
444 *height = (fLineFeed * 3.0) + (kPadding * 2.0) + 147.0;
445 } else {
446 *width = max_c(64.0, ceilf(StringWidth(Label())));
447 *width = max_c(*width, ceilf(StringWidth(MinLimitLabel()))
448 + ceilf(StringWidth(MaxLimitLabel())) + 10.0);
449 *width += kPadding * 2.0;
451 *height = 11.0 * CountChannels() + (fLineFeed * 2.0)
452 + (kPadding * 2.0);
457 BHandler*
458 BChannelSlider::ResolveSpecifier(BMessage* message, int32 index,
459 BMessage* specifier, int32 form, const char* property)
461 BHandler* target = this;
462 BPropertyInfo propertyInfo(sPropertyInfo);
463 if (propertyInfo.FindMatch(message, index, specifier, form,
464 property) != B_OK) {
465 target = BChannelControl::ResolveSpecifier(message, index, specifier,
466 form, property);
468 return target;
472 status_t
473 BChannelSlider::GetSupportedSuites(BMessage* data)
475 if (data == NULL)
476 return B_BAD_VALUE;
478 status_t err = data->AddString("suites", "suite/vnd.Be-channel-slider");
480 BPropertyInfo propInfo(sPropertyInfo);
481 if (err == B_OK)
482 err = data->AddFlat("messages", &propInfo);
484 if (err == B_OK)
485 return BChannelControl::GetSupportedSuites(data);
486 return err;
490 void
491 BChannelSlider::SetEnabled(bool on)
493 BChannelControl::SetEnabled(on);
497 orientation
498 BChannelSlider::Orientation() const
500 return fIsVertical ? B_VERTICAL : B_HORIZONTAL;
504 void
505 BChannelSlider::SetOrientation(orientation orientation)
507 bool isVertical = orientation == B_VERTICAL;
508 if (isVertical != fIsVertical) {
509 fIsVertical = isVertical;
510 InvalidateLayout();
511 Invalidate(Bounds());
516 int32
517 BChannelSlider::MaxChannelCount() const
519 return 32;
523 bool
524 BChannelSlider::SupportsIndividualLimits() const
526 return false;
530 void
531 BChannelSlider::DrawChannel(BView* into, int32 channel, BRect area,
532 bool pressed)
534 float hCenter = area.Width() / 2;
535 float vCenter = area.Height() / 2;
537 BPoint leftTop;
538 BPoint bottomRight;
539 if (fIsVertical) {
540 leftTop.Set(area.left + hCenter, area.top + vCenter);
541 bottomRight.Set(leftTop.x, leftTop.y + ThumbRangeFor(channel));
542 } else {
543 leftTop.Set(area.left, area.top + vCenter);
544 bottomRight.Set(area.left + ThumbRangeFor(channel), leftTop.y);
547 DrawGroove(into, channel, leftTop, bottomRight);
549 BPoint thumbLocation = leftTop;
550 if (fIsVertical)
551 thumbLocation.y += ThumbDeltaFor(channel);
552 else
553 thumbLocation.x += ThumbDeltaFor(channel);
555 DrawThumb(into, channel, thumbLocation, pressed);
559 void
560 BChannelSlider::DrawGroove(BView* into, int32 channel, BPoint leftTop,
561 BPoint bottomRight)
563 ASSERT(into != NULL);
564 BRect rect(leftTop, bottomRight);
566 rect.InsetBy(-2.5, -2.5);
567 rect.left = floorf(rect.left);
568 rect.top = floorf(rect.top);
569 rect.right = floorf(rect.right);
570 rect.bottom = floorf(rect.bottom);
571 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
572 rgb_color barColor = be_control_look->SliderBarColor(base);
573 uint32 flags = 0;
574 be_control_look->DrawSliderBar(into, rect, rect, base,
575 barColor, flags, Orientation());
579 void
580 BChannelSlider::DrawThumb(BView* into, int32 channel, BPoint where,
581 bool pressed)
583 ASSERT(into != NULL);
585 const BBitmap* thumb = ThumbFor(channel, pressed);
586 if (thumb == NULL)
587 return;
589 BRect bitmapBounds(thumb->Bounds());
590 where.x -= bitmapBounds.right / 2.0;
591 where.y -= bitmapBounds.bottom / 2.0;
593 BRect rect(bitmapBounds.OffsetToCopy(where));
594 rect.InsetBy(1, 1);
595 rect.left = floorf(rect.left);
596 rect.top = floorf(rect.top);
597 rect.right = ceilf(rect.right + 0.5);
598 rect.bottom = ceilf(rect.bottom + 0.5);
599 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
600 uint32 flags = 0;
601 be_control_look->DrawSliderThumb(into, rect, rect, base,
602 flags, Orientation());
606 const BBitmap*
607 BChannelSlider::ThumbFor(int32 channel, bool pressed)
609 if (fLeftKnob != NULL)
610 return fLeftKnob;
612 if (fIsVertical) {
613 fLeftKnob = new (std::nothrow) BBitmap(BRect(0, 0, 11, 14),
614 B_CMAP8);
615 if (fLeftKnob != NULL) {
616 fLeftKnob->SetBits(kVerticalKnobData,
617 sizeof(kVerticalKnobData), 0, B_CMAP8);
619 } else {
620 fLeftKnob = new (std::nothrow) BBitmap(BRect(0, 0, 14, 11),
621 B_CMAP8);
622 if (fLeftKnob != NULL) {
623 fLeftKnob->SetBits(kHorizontalKnobData,
624 sizeof(kHorizontalKnobData), 0, B_CMAP8);
628 return fLeftKnob;
632 BRect
633 BChannelSlider::ThumbFrameFor(int32 channel)
635 _UpdateFontDimens();
637 BRect frame(0.0, 0.0, 0.0, 0.0);
638 const BBitmap* thumb = ThumbFor(channel, false);
639 if (thumb != NULL) {
640 frame = thumb->Bounds();
641 if (fIsVertical) {
642 frame.OffsetBy(channel * frame.Width(), (frame.Height() / 2.0) -
643 (kPadding * 2.0) - 1.0);
644 } else {
645 frame.OffsetBy(frame.Width() / 2.0, channel * frame.Height()
646 + 1.0);
649 return frame;
653 float
654 BChannelSlider::ThumbDeltaFor(int32 channel)
656 float delta = 0.0;
657 if (channel >= 0 && channel < MaxChannelCount()) {
658 float range = ThumbRangeFor(channel);
659 int32 limitRange = MaxLimitList()[channel] - MinLimitList()[channel];
660 delta = (ValueList()[channel] - MinLimitList()[channel]) * range
661 / limitRange;
663 if (fIsVertical)
664 delta = range - delta;
667 return delta;
671 float
672 BChannelSlider::ThumbRangeFor(int32 channel)
674 _UpdateFontDimens();
676 float range = 0;
677 BRect bounds = Bounds();
678 BRect frame = ThumbFrameFor(channel);
679 if (fIsVertical) {
680 // *height = (fLineFeed * 3.0) + (kPadding * 2.0) + 100.0;
681 range = bounds.Height() - frame.Height() - (fLineFeed * 3.0) -
682 (kPadding * 2.0);
683 } else {
684 // *width = some width + kPadding * 2.0;
685 range = bounds.Width() - frame.Width() - (kPadding * 2.0);
687 return range;
691 // #pragma mark -
694 void
695 BChannelSlider::_InitData()
697 _UpdateFontDimens();
699 fLeftKnob = NULL;
700 fMidKnob = NULL;
701 fRightKnob = NULL;
702 fBacking = NULL;
703 fBackingView = NULL;
704 fIsVertical = Bounds().Width() / Bounds().Height() < 1;
705 fClickDelta = B_ORIGIN;
707 fCurrentChannel = -1;
708 fAllChannels = false;
709 fInitialValues = NULL;
710 fMinPoint = 0;
711 fFocusChannel = -1;
713 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
717 void
718 BChannelSlider::_FinishChange(bool update)
720 if (fInitialValues != NULL) {
721 bool* inMask = NULL;
722 int32 numChannels = CountChannels();
723 if (!fAllChannels) {
724 inMask = new (std::nothrow) bool[CountChannels()];
725 if (inMask) {
726 for (int i = 0; i < numChannels; i++)
727 inMask[i] = false;
728 inMask[fCurrentChannel] = true;
731 InvokeChannel(update ? ModificationMessage() : NULL, 0, numChannels,
732 inMask);
734 delete[] inMask;
737 if (!update) {
738 SetTracking(false);
739 Invalidate();
744 void
745 BChannelSlider::_UpdateFontDimens()
747 font_height height;
748 GetFontHeight(&height);
749 fBaseLine = height.ascent + height.leading;
750 fLineFeed = fBaseLine + height.descent;
754 void
755 BChannelSlider::_DrawThumbs()
757 if (fBacking == NULL) {
758 // This is the idea: we build a bitmap by taking the coordinates
759 // of the first and last thumb frames (top/left and bottom/right)
760 BRect first = ThumbFrameFor(0);
761 BRect last = ThumbFrameFor(CountChannels() - 1);
762 BRect rect(first.LeftTop(), last.RightBottom());
764 if (fIsVertical)
765 rect.top -= ThumbRangeFor(0);
766 else
767 rect.right += ThumbRangeFor(0);
769 rect.OffsetTo(B_ORIGIN);
770 fBacking = new (std::nothrow) BBitmap(rect, B_RGB32, true);
771 if (fBacking) {
772 fBackingView = new (std::nothrow) BView(rect, "", 0, B_WILL_DRAW);
773 if (fBackingView) {
774 if (fBacking->Lock()) {
775 fBacking->AddChild(fBackingView);
776 fBackingView->SetFontSize(10.0);
777 fBackingView->SetLowColor(
778 ui_color(B_PANEL_BACKGROUND_COLOR));
779 fBackingView->SetViewColor(
780 ui_color(B_PANEL_BACKGROUND_COLOR));
781 fBacking->Unlock();
783 } else {
784 delete fBacking;
785 fBacking = NULL;
790 if (fBacking && fBackingView) {
791 BPoint drawHere;
793 BRect bounds(fBacking->Bounds());
794 drawHere.x = (Bounds().Width() - bounds.Width()) / 2.0;
795 drawHere.y = (Bounds().Height() - bounds.Height()) - kPadding
796 - fLineFeed;
798 if (fBacking->Lock()) {
799 // Clear the view's background
800 fBackingView->FillRect(fBackingView->Bounds(), B_SOLID_LOW);
802 BRect channelArea;
803 // draw the entire control
804 for (int32 channel = 0; channel < CountChannels(); channel++) {
805 channelArea = ThumbFrameFor(channel);
806 bool pressed = IsTracking()
807 && (channel == fCurrentChannel || fAllChannels);
808 DrawChannel(fBackingView, channel, channelArea, pressed);
811 // draw some kind of current value tool tip
812 if (fCurrentChannel != -1 && fMinPoint != 0) {
813 char valueString[32];
814 snprintf(valueString, 32, "%" B_PRId32,
815 ValueFor(fCurrentChannel));
816 float stringWidth = fBackingView->StringWidth(valueString);
817 float width = max_c(10.0, stringWidth);
818 BRect valueRect(0.0, 0.0, width, 10.0);
820 BRect thumbFrame(ThumbFrameFor(fCurrentChannel));
821 float thumbDelta(ThumbDeltaFor(fCurrentChannel));
823 if (fIsVertical) {
824 valueRect.OffsetTo((thumbFrame.Width() - width) / 2.0
825 + fCurrentChannel * thumbFrame.Width(),
826 thumbDelta + thumbFrame.Height() + 2.0);
827 if (valueRect.bottom > fBackingView->Frame().bottom)
828 valueRect.OffsetBy(0.0, -(thumbFrame.Height() + 12.0));
829 } else {
830 valueRect.OffsetTo((thumbDelta - (width + 2.0)),
831 thumbFrame.top);
832 if (valueRect.left < fBackingView->Frame().left) {
833 valueRect.OffsetBy(thumbFrame.Width() + width + 2.0,
834 0.0);
838 rgb_color oldColor = fBackingView->HighColor();
839 fBackingView->SetHighColor(255, 255, 172);
840 fBackingView->FillRect(valueRect);
841 fBackingView->SetHighColor(0, 0, 0);
842 fBackingView->DrawString(valueString, BPoint(valueRect.left
843 + (valueRect.Width() - stringWidth) / 2.0, valueRect.bottom
844 - 1.0));
845 fBackingView->StrokeRect(valueRect.InsetByCopy(-0.5, -0.5));
846 fBackingView->SetHighColor(oldColor);
849 fBackingView->Sync();
850 fBacking->Unlock();
853 DrawBitmapAsync(fBacking, drawHere);
855 // fClickDelta is used in MouseMoved()
856 fClickDelta = drawHere;
861 void
862 BChannelSlider::_DrawGrooveFrame(BView* into, const BRect& area)
864 if (into) {
865 rgb_color oldColor = into->HighColor();
867 into->SetHighColor(255, 255, 255);
868 into->StrokeRect(area);
869 into->SetHighColor(tint_color(into->ViewColor(), B_DARKEN_1_TINT));
870 into->StrokeLine(area.LeftTop(), BPoint(area.right, area.top));
871 into->StrokeLine(area.LeftTop(), BPoint(area.left, area.bottom - 1));
872 into->SetHighColor(tint_color(into->ViewColor(), B_DARKEN_2_TINT));
873 into->StrokeLine(BPoint(area.left + 1, area.top + 1),
874 BPoint(area.right - 1, area.top + 1));
875 into->StrokeLine(BPoint(area.left + 1, area.top + 1),
876 BPoint(area.left + 1, area.bottom - 2));
878 into->SetHighColor(oldColor);
883 void
884 BChannelSlider::_MouseMovedCommon(BPoint point, BPoint point2)
886 float floatValue = 0;
887 int32 limitRange = MaxLimitList()[fCurrentChannel] -
888 MinLimitList()[fCurrentChannel];
889 float range = ThumbRangeFor(fCurrentChannel);
890 if (fIsVertical)
891 floatValue = range - (point.y - fMinPoint);
892 else
893 floatValue = range + (point.x - fMinPoint);
895 int32 value = (int32)(floatValue / range * limitRange) +
896 MinLimitList()[fCurrentChannel];
897 if (fAllChannels)
898 SetAllValue(value);
899 else
900 SetValueFor(fCurrentChannel, value);
902 if (ModificationMessage())
903 _FinishChange(true);
905 _DrawThumbs();
909 // #pragma mark - FBC padding
912 void BChannelSlider::_Reserved_BChannelSlider_0(void*, ...) {}
913 void BChannelSlider::_Reserved_BChannelSlider_1(void*, ...) {}
914 void BChannelSlider::_Reserved_BChannelSlider_2(void*, ...) {}
915 void BChannelSlider::_Reserved_BChannelSlider_3(void*, ...) {}
916 void BChannelSlider::_Reserved_BChannelSlider_4(void*, ...) {}
917 void BChannelSlider::_Reserved_BChannelSlider_5(void*, ...) {}
918 void BChannelSlider::_Reserved_BChannelSlider_6(void*, ...) {}
919 void BChannelSlider::_Reserved_BChannelSlider_7(void*, ...) {}