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