1 /* 2 * Copyright 2005, Haiku Inc. All Rights Reserved. 3 * Author: Stefano Ceccherini (burton666@libero.it) 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include <Bitmap.h> 8 #include <ChannelSlider.h> 9 #include <Debug.h> 10 #include <PropertyInfo.h> 11 #include <Screen.h> 12 #include <Window.h> 13 14 const static unsigned char 15 kVerticalKnobData[] = { 16 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 17 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 18 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 19 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 20 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 21 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 22 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 23 0xff, 0x00, 0x3f, 0x3f, 0xcb, 0xcb, 0xcb, 0xcb, 0x3f, 0x3f, 0x00, 0x12, 24 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 25 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 26 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 27 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 28 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 29 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, 30 0xff, 0xff, 0xff, 0xff, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff 31 }; 32 33 34 const static unsigned char 35 kHorizontalKnobData[] = { 36 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 37 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 38 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0xff, 0xff, 39 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xcb, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 40 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xcb, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 41 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xcb, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 42 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xcb, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 43 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 44 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x12, 0xff, 45 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, 0xff, 46 0xff, 0xff, 0xff, 0xff, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0xff, 0xff 47 }; 48 49 50 static property_info 51 sPropertyInfo[] = { 52 { "Orientation", 53 { B_GET_PROPERTY, B_SET_PROPERTY, 0 }, 54 { B_DIRECT_SPECIFIER, 0 }, "" }, 55 56 { 0 } 57 }; 58 59 60 const static float kPadding = 10.0; 61 62 BChannelSlider::BChannelSlider(BRect area, const char *name, const char *label, 63 BMessage *model, int32 channels, uint32 resizeMode, uint32 flags) 64 : BChannelControl(area, name, label, model, channels, resizeMode, flags) 65 { 66 InitData(); 67 } 68 69 70 BChannelSlider::BChannelSlider(BRect area, const char *name, const char *label, 71 BMessage *model, orientation o, int32 channels, uint32 resizeMode, uint32 flags) 72 : BChannelControl(area, name, label, model, channels, resizeMode, flags) 73 74 { 75 InitData(); 76 SetOrientation(o); 77 } 78 79 80 BChannelSlider::BChannelSlider(BMessage *archive) 81 : BChannelControl(archive) 82 { 83 InitData(); 84 85 orientation orient; 86 if (archive->FindInt32("_orient", (int32 *)&orient) == B_OK) 87 SetOrientation(orient); 88 } 89 90 91 BChannelSlider::~BChannelSlider() 92 { 93 delete fLeftKnob; 94 delete fMidKnob; 95 delete fRightKnob; 96 delete[] fInitialValues; 97 } 98 99 100 BArchivable * 101 BChannelSlider::Instantiate(BMessage *archive) 102 { 103 if (validate_instantiation(archive, "BChannelSlider")) 104 return new BChannelSlider(archive); 105 else 106 return NULL; 107 } 108 109 110 status_t 111 BChannelSlider::Archive(BMessage *into, bool deep) const 112 { 113 status_t status = BChannelControl::Archive(into, deep); 114 if (status == B_OK) 115 status = into->AddInt32("_orient", (int32)Orientation()); 116 117 return status; 118 } 119 120 121 orientation 122 BChannelSlider::Orientation() const 123 { 124 return Vertical() ? B_VERTICAL : B_HORIZONTAL; 125 } 126 127 128 void 129 BChannelSlider::SetOrientation(orientation _orientation) 130 { 131 bool isVertical = _orientation == B_VERTICAL; 132 if (isVertical != Vertical()) { 133 fVertical = isVertical; 134 Invalidate(Bounds()); 135 } 136 } 137 138 139 int32 140 BChannelSlider::MaxChannelCount() const 141 { 142 return 32; 143 } 144 145 146 bool 147 BChannelSlider::SupportsIndividualLimits() const 148 { 149 return false; 150 } 151 152 153 void 154 BChannelSlider::AttachedToWindow() 155 { 156 BView *parent = Parent(); 157 if (parent != NULL) 158 SetViewColor(parent->ViewColor()); 159 160 inherited::AttachedToWindow(); 161 } 162 163 164 void 165 BChannelSlider::AllAttached() 166 { 167 BControl::AllAttached(); 168 } 169 170 171 void 172 BChannelSlider::DetachedFromWindow() 173 { 174 inherited::DetachedFromWindow(); 175 } 176 177 178 void 179 BChannelSlider::AllDetached() 180 { 181 BControl::AllDetached(); 182 } 183 184 185 void 186 BChannelSlider::MessageReceived(BMessage *message) 187 { 188 switch (message->what) { 189 case B_SET_PROPERTY: 190 case B_GET_PROPERTY: 191 { 192 BMessage reply(B_REPLY); 193 int32 index = 0; 194 BMessage specifier; 195 int32 what = 0; 196 const char *property = NULL; 197 bool handled = false; 198 status_t status = message->GetCurrentSpecifier(&index, &specifier, &what, &property); 199 BPropertyInfo propInfo(sPropertyInfo); 200 if (status == B_OK 201 && propInfo.FindMatch(message, index, &specifier, what, property) >= 0) { 202 handled = true; 203 if (message->what == B_SET_PROPERTY) { 204 orientation orient; 205 if (specifier.FindInt32("data", (int32 *)&orient) == B_OK) { 206 SetOrientation(orient); 207 Invalidate(Bounds()); 208 } 209 } else if (message->what == B_GET_PROPERTY) 210 reply.AddInt32("result", (int32)Orientation()); 211 else 212 status = B_BAD_SCRIPT_SYNTAX; 213 } 214 215 if (handled) { 216 reply.AddInt32("error", status); 217 message->SendReply(&reply); 218 } else 219 inherited::MessageReceived(message); 220 break; 221 } 222 default: 223 inherited::MessageReceived(message); 224 break; 225 } 226 } 227 228 229 void 230 BChannelSlider::Draw(BRect updateRect) 231 { 232 UpdateFontDimens(); 233 DrawThumbs(); 234 235 BRect bounds(Bounds()); 236 float labelWidth = StringWidth(Label()); 237 238 DrawString(Label(), BPoint((bounds.Width() - labelWidth) / 2, fBaseLine)); 239 } 240 241 242 void 243 BChannelSlider::MouseDown(BPoint where) 244 { 245 if (!IsEnabled()) 246 BControl::MouseDown(where); 247 else { 248 fCurrentChannel = -1; 249 fMinpoint = 0; 250 251 // Search the channel on which the mouse was over 252 int32 numChannels = CountChannels(); 253 for (int32 channel = 0; channel < numChannels; channel++) { 254 BRect frame = ThumbFrameFor(channel); 255 frame.OffsetBy(fClickDelta); 256 257 float range = ThumbRangeFor(channel); 258 if (Vertical()) { 259 fMinpoint = frame.top + frame.Height() / 2; 260 frame.bottom += range; 261 } else { 262 // TODO: Fix this, the clickzone isn't perfect 263 frame.right += range; 264 fMinpoint = frame.Width(); 265 } 266 267 // Click was on a slider. 268 if (frame.Contains(where)) { 269 fCurrentChannel = channel; 270 break; 271 } 272 } 273 274 // Click wasn't on a slider. Bail out. 275 if (fCurrentChannel == -1) 276 return; 277 278 uint32 buttons = 0; 279 BMessage *currentMessage = Window()->CurrentMessage(); 280 if (currentMessage != NULL) 281 currentMessage->FindInt32("buttons", (int32 *)&buttons); 282 283 fAllChannels = (buttons & B_SECONDARY_MOUSE_BUTTON) == 0; 284 285 if (fInitialValues != NULL && fAllChannels) { 286 delete[] fInitialValues; 287 fInitialValues = NULL; 288 } 289 290 if (fInitialValues == NULL) 291 fInitialValues = new int32[numChannels]; 292 293 if (fAllChannels) { 294 for (int32 i = 0; i < numChannels; i++) 295 fInitialValues[i] = ValueFor(i); 296 } else 297 fInitialValues[fCurrentChannel] = ValueFor(fCurrentChannel); 298 299 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) { 300 if (!IsTracking()) { 301 SetTracking(true); 302 DrawThumbs(); 303 Flush(); 304 } 305 306 MouseMovedCommon(where, B_ORIGIN); 307 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY); 308 } else { 309 do { 310 snooze(30000); 311 GetMouse(&where, &buttons); 312 MouseMovedCommon(where, B_ORIGIN); 313 } while (buttons != 0); 314 FinishChange(); 315 fCurrentChannel = -1; 316 fAllChannels = false; 317 } 318 } 319 } 320 321 322 void 323 BChannelSlider::MouseUp(BPoint where) 324 { 325 if (IsEnabled() && IsTracking()) { 326 FinishChange(); 327 SetTracking(false); 328 fAllChannels = false; 329 fCurrentChannel = -1; 330 fMinpoint = 0; 331 } else 332 BControl::MouseUp(where); 333 } 334 335 336 void 337 BChannelSlider::MouseMoved(BPoint where, uint32 code, const BMessage *message) 338 { 339 if (IsEnabled() && IsTracking()) 340 MouseMovedCommon(where, B_ORIGIN); 341 else 342 BControl::MouseMoved(where, code, message); 343 } 344 345 346 void 347 BChannelSlider::WindowActivated(bool state) 348 { 349 BControl::WindowActivated(state); 350 } 351 352 353 void 354 BChannelSlider::KeyDown(const char *bytes, int32 numBytes) 355 { 356 BControl::KeyDown(bytes, numBytes); 357 } 358 359 360 void 361 BChannelSlider::KeyUp(const char *bytes, int32 numBytes) 362 { 363 BView::KeyUp(bytes, numBytes); 364 } 365 366 367 void 368 BChannelSlider::FrameResized(float newWidth, float newHeight) 369 { 370 inherited::FrameResized(newWidth, newHeight); 371 Invalidate(Bounds()); 372 } 373 374 375 void 376 BChannelSlider::SetFont(const BFont *font, uint32 mask) 377 { 378 inherited::SetFont(font, mask); 379 } 380 381 382 void 383 BChannelSlider::MakeFocus(bool focusState) 384 { 385 if (focusState && !IsFocus()) 386 fFocusChannel = -1; 387 BControl::MakeFocus(focusState); 388 } 389 390 391 void 392 BChannelSlider::SetEnabled(bool on) 393 { 394 BControl::SetEnabled(on); 395 } 396 397 398 void 399 BChannelSlider::GetPreferredSize(float *width, float *height) 400 { 401 // TODO: Implement 402 } 403 404 405 BHandler * 406 BChannelSlider::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, 407 int32 form, const char *property) 408 { 409 BHandler *target = this; 410 BPropertyInfo propertyInfo(sPropertyInfo); 411 if (propertyInfo.FindMatch(msg, index, specifier, form, property) < B_OK) 412 target = BChannelControl::ResolveSpecifier(msg, index, specifier, form, property); 413 414 return target; 415 } 416 417 418 status_t 419 BChannelSlider::GetSupportedSuites(BMessage *data) 420 { 421 if (data == NULL) 422 return B_BAD_VALUE; 423 424 data->AddString("suites", "suite/vnd.Be-channel-slider"); 425 426 BPropertyInfo propInfo(sPropertyInfo); 427 data->AddFlat("messages", &propInfo, 1); 428 429 return inherited::GetSupportedSuites(data); 430 } 431 432 433 void 434 BChannelSlider::DrawChannel(BView *into, int32 channel, BRect area, bool pressed) 435 { 436 float hCenter = area.Width() / 2; 437 float vCenter = area.Height() / 2; 438 439 BPoint leftTop; 440 BPoint bottomRight; 441 if (Vertical()) { 442 leftTop.Set(area.left + hCenter, area.top + vCenter); 443 bottomRight.Set(leftTop.x, leftTop.y + ThumbRangeFor(channel)); 444 } else { 445 leftTop.Set(area.left, area.top + vCenter); 446 bottomRight.Set(area.left + ThumbRangeFor(channel), leftTop.y); 447 } 448 449 DrawGroove(into, channel, leftTop, bottomRight); 450 451 BPoint thumbLocation = leftTop; 452 if (Vertical()) 453 thumbLocation.y += ThumbDeltaFor(channel); 454 else 455 thumbLocation.x += ThumbDeltaFor(channel); 456 457 DrawThumb(into, channel, thumbLocation, pressed); 458 } 459 460 461 void 462 BChannelSlider::DrawGroove(BView *into, int32 channel, BPoint topLeft, BPoint bottomRight) 463 { 464 ASSERT(into != NULL); 465 BRect rect(topLeft, bottomRight); 466 467 DrawThumbFrame(fBackingView, rect.InsetByCopy(-2.5, -2.5)); 468 469 rect.InsetBy(-0.5, -0.5); 470 into->FillRect(rect, B_SOLID_HIGH); 471 } 472 473 474 void 475 BChannelSlider::DrawThumb(BView *into, int32 channel, BPoint where, bool pressed) 476 { 477 ASSERT(into != NULL); 478 479 const BBitmap *thumb = ThumbFor(channel, pressed); 480 if (thumb == NULL) 481 return; 482 483 BRect bitmapBounds = thumb->Bounds(); 484 where.x -= bitmapBounds.right / 2; 485 where.y -= bitmapBounds.bottom / 2; 486 487 into->PushState(); 488 489 into->SetDrawingMode(B_OP_OVER); 490 into->DrawBitmapAsync(thumb, where); 491 492 if (pressed) { 493 into->SetDrawingMode(B_OP_ALPHA); 494 495 rgb_color color = tint_color(into->ViewColor(), B_DARKEN_4_TINT); 496 color.alpha = 128; 497 into->SetHighColor(color); 498 499 BRect destRect(where, where); 500 destRect.right += bitmapBounds.right; 501 destRect.bottom += bitmapBounds.bottom; 502 503 into->FillRect(destRect); 504 } 505 506 into->PopState(); 507 } 508 509 510 const BBitmap * 511 BChannelSlider::ThumbFor(int32 channel, bool pressed) 512 { 513 // TODO: Finish me 514 if (fLeftKnob == NULL) { 515 if (Vertical()) { 516 fLeftKnob = new BBitmap(BRect(0, 0, 11, 14), B_CMAP8); 517 fLeftKnob->SetBits(kVerticalKnobData, sizeof(kVerticalKnobData), 0, B_CMAP8); 518 } else { 519 fLeftKnob = new BBitmap(BRect(0, 0, 14, 10), B_CMAP8); 520 fLeftKnob->SetBits(kHorizontalKnobData, sizeof(kHorizontalKnobData), 0, B_CMAP8); 521 } 522 } 523 524 return fLeftKnob; 525 } 526 527 528 BRect 529 BChannelSlider::ThumbFrameFor(int32 channel) 530 { 531 UpdateFontDimens(); 532 533 BRect frame(0, 0, 0, 0); 534 const BBitmap *thumb = ThumbFor(channel, false); 535 if (thumb != NULL) { 536 frame = thumb->Bounds(); 537 if (Vertical()) 538 frame.OffsetBy(channel * frame.Width(), fLineFeed + kPadding); 539 else 540 frame.OffsetBy(kPadding, fLineFeed + channel * frame.Height()); 541 } 542 543 return frame; 544 } 545 546 547 float 548 BChannelSlider::ThumbDeltaFor(int32 channel) 549 { 550 float delta = 0; 551 if (channel >= 0 && channel < MaxChannelCount()) { 552 float range = ThumbRangeFor(channel); 553 int32 limitRange = MaxLimitList()[channel] - MinLimitList()[channel]; 554 delta = ValueList()[channel] * range / limitRange; 555 556 if (Vertical()) 557 delta = range - delta; 558 } 559 560 return delta; 561 } 562 563 564 float 565 BChannelSlider::ThumbRangeFor(int32 channel) 566 { 567 UpdateFontDimens(); 568 569 float range = 0; 570 BRect bounds = Bounds(); 571 BRect frame = ThumbFrameFor(channel); 572 if (Vertical()) 573 range = bounds.Height() - frame.Height() - (kPadding + fLineFeed) * 2; 574 else 575 range = bounds.Width() - frame.Width() - kPadding * 2; 576 577 return range; 578 } 579 580 581 void 582 BChannelSlider::InitData() 583 { 584 UpdateFontDimens(); 585 586 fLeftKnob = NULL; 587 fMidKnob = NULL; 588 fRightKnob = NULL; 589 fBacking = NULL; 590 fBackingView = NULL; 591 fVertical = Bounds().Width() / Bounds().Height() < 1; 592 fClickDelta = B_ORIGIN; 593 594 fCurrentChannel = -1; 595 fAllChannels = false; 596 fInitialValues = NULL; 597 fMinpoint = 0; 598 fFocusChannel = -1; 599 600 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 601 } 602 603 604 void 605 BChannelSlider::FinishChange() 606 { 607 if (fInitialValues != NULL) { 608 if (fAllChannels) { 609 // TODO: Iterate through the list of channels, and invoke only 610 // for changed values ? 611 612 InvokeChannel(); 613 614 } else { 615 if (ValueList()[fCurrentChannel] != fInitialValues[fCurrentChannel]) { 616 SetValueFor(fCurrentChannel, ValueList()[fCurrentChannel]); 617 Invoke(); 618 } 619 } 620 } 621 622 SetTracking(false); 623 Redraw(); 624 } 625 626 627 void 628 BChannelSlider::UpdateFontDimens() 629 { 630 font_height height; 631 GetFontHeight(&height); 632 fBaseLine = height.ascent + height.leading; 633 fLineFeed = fBaseLine + height.descent; 634 } 635 636 637 void 638 BChannelSlider::DrawThumbs() 639 { 640 if (fBacking == NULL) { 641 // This is the idea: we build a bitmap by taking the coordinates 642 // of the first and last thumb frames (top/left and bottom/right), 643 // and by enlarging this rectangle a bit (hence the "InsetBy(-3, -3)"). 644 BRect first = ThumbFrameFor(0); 645 BRect last = ThumbFrameFor(CountChannels() - 1); 646 BRect bitmapFrame(first.LeftTop(), last.RightBottom()); 647 648 if (Vertical()) 649 bitmapFrame.top -= ThumbRangeFor(0); 650 else 651 bitmapFrame.right += ThumbRangeFor(0); 652 653 bitmapFrame.InsetBy(-3, -3); 654 fBacking = new BBitmap(bitmapFrame, BScreen(Window()).ColorSpace(), true, false); 655 if (fBacking->Lock()) { 656 fBackingView = new BView(bitmapFrame.OffsetToCopy(B_ORIGIN), "backing view", B_FOLLOW_NONE, B_WILL_DRAW); 657 fBacking->AddChild(fBackingView); 658 fBackingView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 659 fBackingView->SetLowColor(fBackingView->ViewColor()); 660 fBacking->Unlock(); 661 } 662 } 663 664 BPoint drawHere; 665 drawHere.x = (Bounds().Width() - fBacking->Bounds().Width()) / 2; 666 drawHere.y = (Bounds().Height() - fBacking->Bounds().Height() + fLineFeed) / 2; 667 668 if (fBacking->Lock()) { 669 // Clear the view's background 670 fBackingView->FillRect(fBackingView->Bounds(), B_SOLID_LOW); 671 672 BRect channelArea; 673 int32 channelCount = CountChannels(); 674 for (int32 channel = 0; channel < channelCount; channel++) { 675 channelArea = ThumbFrameFor(channel); 676 // TODO: This is (apparently) needed because ThumbFrameFor() doesn't 677 // take into account that the view we draw on is attached to an offscreen 678 // bitmap. Still this doesn't make much sense: 679 // could be that I'm simply missing something. 680 if (Vertical()) 681 channelArea.OffsetBy(0, -channelArea.top); 682 else 683 channelArea.OffsetBy(0, -channelArea.Height()); 684 685 bool pressed = fMinpoint != 0 && (channel == fCurrentChannel || fAllChannels); 686 DrawChannel(fBackingView, channel, channelArea, pressed); 687 } 688 689 #if 1 690 // This part draws the current value over the thumb. 691 // TODO: make it nicer. Simplify the code. 692 if (fCurrentChannel != -1 && fMinpoint != 0) { 693 char valueString[32]; 694 snprintf(valueString, 32, "%ld", ValueFor(fCurrentChannel)); 695 float width = fBackingView->StringWidth(valueString); 696 BRect valueRect(0, 0, width, 10); 697 rgb_color oldColor = fBackingView->HighColor(); 698 if (Vertical()) 699 valueRect.OffsetTo((ThumbFrameFor(fCurrentChannel).Width() - width) / 2 + fCurrentChannel * ThumbFrameFor(fCurrentChannel).Width(), 700 ThumbDeltaFor(fCurrentChannel)); 701 else 702 valueRect.OffsetTo(ThumbDeltaFor(fCurrentChannel), ThumbFrameFor(fCurrentChannel).top - 10); 703 fBackingView->SetHighColor(255, 255, 172); 704 fBackingView->FillRect(valueRect); 705 fBackingView->SetHighColor(0, 0, 0); 706 valueRect.OffsetBy(1 , 9); 707 fBackingView->DrawString(valueString, valueRect.LeftTop()); 708 fBackingView->SetHighColor(oldColor); 709 } 710 #endif 711 fBackingView->Sync(); 712 fBacking->Unlock(); 713 } 714 715 DrawBitmapAsync(fBacking, drawHere); 716 717 #if 0 718 // this part draws the value at the bottom of the sliders. 719 if (fCurrentChannel != -1 && fMinpoint != 0) { 720 char valueString[32]; 721 snprintf(valueString, 32, "%ld", ValueFor(fCurrentChannel)); 722 BPoint stringPoint = drawHere; 723 float stringWidth = StringWidth(valueString); 724 stringPoint.x += (fBacking->Bounds().Width() - stringWidth) / 2; 725 stringPoint.y += fBacking->Bounds().Height() + fBaseLine; 726 BRect stringRect(stringPoint, stringPoint); 727 stringRect.left -= 10; 728 stringRect.right += StringWidth("100"); 729 stringRect.top -= fLineFeed; 730 731 SetHighColor(ViewColor()); 732 FillRect(stringRect); 733 734 SetHighColor(0, 0, 0); 735 DrawString(valueString, stringPoint); 736 } 737 #endif 738 739 // fClickDelta is used in MouseMoved() 740 fClickDelta = drawHere; 741 742 // TODO: See above 743 if (Vertical()) 744 fClickDelta.y -= ThumbFrameFor(0).top; 745 else 746 fClickDelta.y -= ThumbFrameFor(0).Height(); 747 } 748 749 750 void 751 BChannelSlider::DrawThumbFrame(BView *into, const BRect &area) 752 { 753 rgb_color oldColor = into->HighColor(); 754 755 into->SetHighColor(255, 255, 255); 756 into->StrokeRect(area); 757 into->SetHighColor(tint_color(into->ViewColor(), B_DARKEN_1_TINT)); 758 into->StrokeLine(area.LeftTop(), BPoint(area.right, area.top)); 759 into->StrokeLine(area.LeftTop(), BPoint(area.left, area.bottom - 1)); 760 into->SetHighColor(tint_color(into->ViewColor(), B_DARKEN_2_TINT)); 761 into->StrokeLine(BPoint(area.left + 1, area.top + 1), BPoint(area.right - 1, area.top + 1)); 762 into->StrokeLine(BPoint(area.left + 1, area.top + 1), BPoint(area.left + 1, area.bottom - 2)); 763 764 into->SetHighColor(oldColor); 765 } 766 767 768 bool 769 BChannelSlider::Vertical() const 770 { 771 return fVertical; 772 } 773 774 775 void 776 BChannelSlider::Redraw() 777 { 778 Invalidate(Bounds()); 779 Flush(); 780 } 781 782 783 void 784 BChannelSlider::MouseMovedCommon(BPoint point, BPoint point2) 785 { 786 float floatValue = 0; 787 int32 limitRange = MaxLimitList()[fCurrentChannel] - MinLimitList()[fCurrentChannel]; 788 float range = ThumbRangeFor(fCurrentChannel); 789 if (Vertical()) 790 floatValue = range - (point.y - fMinpoint); 791 else 792 floatValue = range + (point.x - fMinpoint); 793 794 int32 value = (int32)(floatValue / range * limitRange); 795 if (fAllChannels) 796 SetAllValue(value); 797 else 798 SetValueFor(fCurrentChannel, value); 799 800 InvokeNotifyChannel(ModificationMessage()); 801 DrawThumbs(); 802 } 803 804 805 void BChannelSlider::_Reserved_BChannelSlider_0(void *, ...) {} 806 void BChannelSlider::_Reserved_BChannelSlider_1(void *, ...) {} 807 void BChannelSlider::_Reserved_BChannelSlider_2(void *, ...) {} 808 void BChannelSlider::_Reserved_BChannelSlider_3(void *, ...) {} 809 void BChannelSlider::_Reserved_BChannelSlider_4(void *, ...) {} 810 void BChannelSlider::_Reserved_BChannelSlider_5(void *, ...) {} 811 void BChannelSlider::_Reserved_BChannelSlider_6(void *, ...) {} 812 void BChannelSlider::_Reserved_BChannelSlider_7(void *, ...) {} 813