1 /* 2 * Copyright 2001-2013 Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Alexandre Deckner, alex@zappotek.com 7 * Axel Dörfler, axeld@pinc-software.de 8 * Jérôme Duval 9 * Marc Flerackers, mflerackers@androme.be 10 * John Scipione, jscipione@gmail.com 11 */ 12 13 /** BColorControl displays a palette of selectable colors. */ 14 15 #include <ColorControl.h> 16 17 #include <algorithm> 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 22 #include <ControlLook.h> 23 #include <Bitmap.h> 24 #include <TextControl.h> 25 #include <Region.h> 26 #include <Screen.h> 27 #include <SystemCatalog.h> 28 #include <Window.h> 29 30 using BPrivate::gSystemCatalog; 31 32 #include <binary_compatibility/Interface.h> 33 34 35 #undef B_TRANSLATION_CONTEXT 36 #define B_TRANSLATION_CONTEXT "ColorControl" 37 38 static const uint32 kMsgColorEntered = 'ccol'; 39 static const float kMinCellSize = 6.0f; 40 static const float kSelectorPenSize = 2.0f; 41 static const float kSelectorSize = 4.0f; 42 static const float kSelectorHSpacing = 2.0f; 43 static const float kTextFieldsHSpacing = 6.0f; 44 static const float kDefaultFontSize = 12.0f; 45 static const float kBevelSpacing = 2.0f; 46 static const uint32 kRampCount = 4; 47 48 49 BColorControl::BColorControl(BPoint leftTop, color_control_layout layout, 50 float cellSize, const char* name, BMessage* message, bool useOffscreen) 51 : 52 BControl(BRect(leftTop, leftTop), name, NULL, message, 53 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE), 54 fRedText(NULL), 55 fGreenText(NULL), 56 fBlueText(NULL), 57 fOffscreenBitmap(NULL) 58 { 59 _InitData(layout, cellSize, useOffscreen, NULL); 60 } 61 62 63 BColorControl::BColorControl(BMessage* data) 64 : 65 BControl(data), 66 fRedText(NULL), 67 fGreenText(NULL), 68 fBlueText(NULL), 69 fOffscreenBitmap(NULL) 70 { 71 int32 layout; 72 float cellSize; 73 bool useOffscreen; 74 75 data->FindInt32("_layout", &layout); 76 data->FindFloat("_csize", &cellSize); 77 data->FindBool("_use_off", &useOffscreen); 78 79 _InitData((color_control_layout)layout, cellSize, useOffscreen, data); 80 } 81 82 83 BColorControl::~BColorControl() 84 { 85 delete fOffscreenBitmap; 86 } 87 88 89 void 90 BColorControl::_InitData(color_control_layout layout, float size, 91 bool useOffscreen, BMessage* data) 92 { 93 fPaletteMode = BScreen(B_MAIN_SCREEN_ID).ColorSpace() == B_CMAP8; 94 //TODO: we don't support workspace and colorspace changing for now 95 // so we take the main_screen colorspace at startup 96 fColumns = layout; 97 fRows = 256 / fColumns; 98 99 _SetCellSize(size); 100 101 fSelectedPaletteColorIndex = -1; 102 fPreviousSelectedPaletteColorIndex = -1; 103 fFocusedRamp = !fPaletteMode && IsFocus() ? 1 : -1; 104 fClickedRamp = -1; 105 106 const char* red = B_TRANSLATE_MARK("Red:"); 107 const char* green = B_TRANSLATE_MARK("Green:"); 108 const char* blue = B_TRANSLATE_MARK("Blue:"); 109 red = gSystemCatalog.GetString(red, "ColorControl"); 110 green = gSystemCatalog.GetString(green, "ColorControl"); 111 blue = gSystemCatalog.GetString(blue, "ColorControl"); 112 113 if (data != NULL) { 114 fRedText = (BTextControl*)FindView("_red"); 115 fGreenText = (BTextControl*)FindView("_green"); 116 fBlueText = (BTextControl*)FindView("_blue"); 117 118 int32 value = 0; 119 data->FindInt32("_val", &value); 120 121 SetValue(value); 122 } else { 123 BRect textRect(0.0f, 0.0f, 0.0f, 0.0f); 124 float labelWidth = std::max(StringWidth(red), 125 std::max(StringWidth(green), StringWidth(blue))) 126 + kTextFieldsHSpacing; 127 textRect.right = labelWidth + StringWidth("999999"); 128 // enough room for 3 digits plus 3 digits of padding 129 font_height fontHeight; 130 GetFontHeight(&fontHeight); 131 float labelHeight = fontHeight.ascent + fontHeight.descent; 132 textRect.bottom = labelHeight; 133 134 // red 135 136 fRedText = new BTextControl(textRect, "_red", red, "0", 137 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 138 B_WILL_DRAW | B_NAVIGABLE); 139 fRedText->SetDivider(labelWidth); 140 141 for (int32 i = 0; i < 256; i++) 142 fRedText->TextView()->DisallowChar(i); 143 for (int32 i = '0'; i <= '9'; i++) 144 fRedText->TextView()->AllowChar(i); 145 fRedText->TextView()->SetMaxBytes(3); 146 147 // green 148 149 textRect.OffsetBy(0, _TextRectOffset()); 150 fGreenText = new BTextControl(textRect, "_green", green, "0", 151 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 152 B_WILL_DRAW | B_NAVIGABLE); 153 fGreenText->SetDivider(labelWidth); 154 155 for (int32 i = 0; i < 256; i++) 156 fGreenText->TextView()->DisallowChar(i); 157 for (int32 i = '0'; i <= '9'; i++) 158 fGreenText->TextView()->AllowChar(i); 159 fGreenText->TextView()->SetMaxBytes(3); 160 161 // blue 162 163 textRect.OffsetBy(0, _TextRectOffset()); 164 fBlueText = new BTextControl(textRect, "_blue", blue, "0", 165 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 166 B_WILL_DRAW | B_NAVIGABLE); 167 fBlueText->SetDivider(labelWidth); 168 169 for (int32 i = 0; i < 256; i++) 170 fBlueText->TextView()->DisallowChar(i); 171 for (int32 i = '0'; i <= '9'; i++) 172 fBlueText->TextView()->AllowChar(i); 173 fBlueText->TextView()->SetMaxBytes(3); 174 175 AddChild(fRedText); 176 AddChild(fGreenText); 177 AddChild(fBlueText); 178 } 179 180 ResizeToPreferred(); 181 182 if (useOffscreen) { 183 if (fOffscreenBitmap != NULL) { 184 BRect bounds = _PaletteFrame(); 185 fOffscreenBitmap = new BBitmap(bounds, B_RGB32, true, false); 186 BView* offscreenView = new BView(bounds, "off_view", 0, 0); 187 188 fOffscreenBitmap->Lock(); 189 fOffscreenBitmap->AddChild(offscreenView); 190 fOffscreenBitmap->Unlock(); 191 } 192 } else { 193 delete fOffscreenBitmap; 194 fOffscreenBitmap = NULL; 195 } 196 } 197 198 199 void 200 BColorControl::_LayoutView() 201 { 202 fPaletteFrame.Set(0, 0, fColumns * fCellSize, fRows * fCellSize); 203 fPaletteFrame.OffsetBy(kBevelSpacing, kBevelSpacing); 204 if (!fPaletteMode) { 205 // Reduce the inner space by 1 pixel so that the frame 206 // is exactly rows * cellsize pixels in height 207 fPaletteFrame.bottom -= 1; 208 } 209 210 float rampHeight = (float)(fRows * fCellSize / kRampCount); 211 float offset = _TextRectOffset(); 212 float y = 0; 213 if (rampHeight > fRedText->Frame().Height()) { 214 // there is enough room to fit kRampCount labels, 215 // shift text controls down by one ramp 216 offset = rampHeight; 217 y = floorf(offset + (offset - fRedText->Frame().Height()) / 2); 218 } 219 220 BRect rect = _PaletteFrame(); 221 fRedText->MoveTo(rect.right + kTextFieldsHSpacing, y); 222 223 y += offset; 224 fGreenText->MoveTo(rect.right + kTextFieldsHSpacing, y); 225 226 y += offset; 227 fBlueText->MoveTo(rect.right + kTextFieldsHSpacing, y); 228 } 229 230 231 BArchivable* 232 BColorControl::Instantiate(BMessage* data) 233 { 234 if (validate_instantiation(data, "BColorControl")) 235 return new BColorControl(data); 236 237 return NULL; 238 } 239 240 241 status_t 242 BColorControl::Archive(BMessage* data, bool deep) const 243 { 244 status_t status = BControl::Archive(data, deep); 245 246 if (status == B_OK) 247 status = data->AddInt32("_layout", Layout()); 248 249 if (status == B_OK) 250 status = data->AddFloat("_csize", fCellSize); 251 252 if (status == B_OK) 253 status = data->AddBool("_use_off", fOffscreenBitmap != NULL); 254 255 return status; 256 } 257 258 259 void 260 BColorControl::SetLayout(BLayout* layout) 261 { 262 // We need to implement this method, since we have another SetLayout() 263 // method and C++ has this special method hiding "feature". 264 BControl::SetLayout(layout); 265 } 266 267 268 void 269 BColorControl::SetValue(int32 value) 270 { 271 rgb_color c1 = ValueAsColor(); 272 rgb_color c2; 273 c2.red = (value & 0xFF000000) >> 24; 274 c2.green = (value & 0x00FF0000) >> 16; 275 c2.blue = (value & 0x0000FF00) >> 8; 276 c2.alpha = 255; 277 278 if (fPaletteMode) { 279 //workaround when two indexes have the same color 280 rgb_color c 281 = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex); 282 c.alpha = 255; 283 if (fSelectedPaletteColorIndex == -1 || c != c2) { 284 //here SetValue hasn't been called by mouse tracking 285 fSelectedPaletteColorIndex = BScreen(Window()).IndexForColor(c2); 286 } 287 288 c2 = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex); 289 290 Invalidate(_PaletteSelectorFrame(fPreviousSelectedPaletteColorIndex)); 291 Invalidate(_PaletteSelectorFrame(fSelectedPaletteColorIndex)); 292 293 fPreviousSelectedPaletteColorIndex = fSelectedPaletteColorIndex; 294 } else if (c1 != c2) 295 Invalidate(); 296 297 // Set the value here, since BTextControl will trigger 298 // Window()->UpdateIfNeeded() which will cause us to draw the indicators 299 // at the old offset. 300 if (Value() != value) 301 BControl::SetValueNoUpdate(value); 302 303 // the textcontrols have to be updated even when the color 304 // hasn't changed since the value is clamped upstream 305 // and the textcontrols would still show the unclamped value 306 char string[4]; 307 sprintf(string, "%d", c2.red); 308 fRedText->SetText(string); 309 sprintf(string, "%d", c2.green); 310 fGreenText->SetText(string); 311 sprintf(string, "%d", c2.blue); 312 fBlueText->SetText(string); 313 } 314 315 316 rgb_color 317 BColorControl::ValueAsColor() 318 { 319 int32 value = Value(); 320 rgb_color color; 321 322 color.red = (value & 0xFF000000) >> 24; 323 color.green = (value & 0x00FF0000) >> 16; 324 color.blue = (value & 0x0000FF00) >> 8; 325 color.alpha = 255; 326 327 return color; 328 } 329 330 331 void 332 BColorControl::SetEnabled(bool enabled) 333 { 334 BControl::SetEnabled(enabled); 335 336 fRedText->SetEnabled(enabled); 337 fGreenText->SetEnabled(enabled); 338 fBlueText->SetEnabled(enabled); 339 } 340 341 342 void 343 BColorControl::AttachedToWindow() 344 { 345 BControl::AttachedToWindow(); 346 347 AdoptParentColors(); 348 349 fRedText->SetTarget(this); 350 fGreenText->SetTarget(this); 351 fBlueText->SetTarget(this); 352 353 if (fOffscreenBitmap != NULL) 354 _InitOffscreen(); 355 } 356 357 358 void 359 BColorControl::MessageReceived(BMessage* message) 360 { 361 switch (message->what) { 362 case kMsgColorEntered: 363 { 364 rgb_color color; 365 color.red = min_c(strtol(fRedText->Text(), NULL, 10), 255); 366 color.green = min_c(strtol(fGreenText->Text(), NULL, 10), 255); 367 color.blue = min_c(strtol(fBlueText->Text(), NULL, 10), 255); 368 color.alpha = 255; 369 370 SetValue(color); 371 Invoke(); 372 break; 373 } 374 375 case B_SCREEN_CHANGED: 376 { 377 BRect frame; 378 uint32 mode; 379 if (message->FindRect("frame", &frame) == B_OK 380 && message->FindInt32("mode", (int32*)&mode) == B_OK) { 381 if ((fPaletteMode && mode == B_CMAP8) 382 || (!fPaletteMode && mode != B_CMAP8)) { 383 // not switching to or from B_CMAP8, break 384 break; 385 } 386 387 // fake an archive message (so we don't rebuild views) 388 BMessage* data = new BMessage(); 389 data->AddInt32("_val", Value()); 390 391 // reinititialize 392 bool useOffscreen = fOffscreenBitmap != NULL; 393 _InitData((color_control_layout)fColumns, fCellSize, 394 useOffscreen, data); 395 if (useOffscreen) 396 _InitOffscreen(); 397 398 // cleanup 399 delete data; 400 } 401 break; 402 } 403 404 default: 405 BControl::MessageReceived(message); 406 } 407 } 408 409 410 void 411 BColorControl::Draw(BRect updateRect) 412 { 413 if (fOffscreenBitmap != NULL) 414 DrawBitmap(fOffscreenBitmap, B_ORIGIN); 415 else 416 _DrawColorArea(this, updateRect); 417 418 _DrawSelectors(this); 419 } 420 421 422 void 423 BColorControl::_DrawColorArea(BView* target, BRect updateRect) 424 { 425 BRect rect = _PaletteFrame(); 426 bool enabled = IsEnabled(); 427 428 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 429 rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT); 430 431 uint32 flags = be_control_look->Flags(this); 432 be_control_look->DrawTextControlBorder(target, rect, updateRect, 433 base, flags); 434 435 if (fPaletteMode) { 436 int colBegin = max_c(0, -1 + int(updateRect.left) / int(fCellSize)); 437 int colEnd = min_c(fColumns, 438 2 + int(updateRect.right) / int(fCellSize)); 439 int rowBegin = max_c(0, -1 + int(updateRect.top) / int(fCellSize)); 440 int rowEnd = min_c(fRows, 2 + int(updateRect.bottom) 441 / int(fCellSize)); 442 443 // grid 444 target->SetHighColor(enabled ? darken1 : base); 445 446 for (int xi = 0; xi < fColumns + 1; xi++) { 447 float x = fPaletteFrame.left + float(xi) * fCellSize; 448 target->StrokeLine(BPoint(x, fPaletteFrame.top), 449 BPoint(x, fPaletteFrame.bottom)); 450 } 451 for (int yi = 0; yi < fRows + 1; yi++) { 452 float y = fPaletteFrame.top + float(yi) * fCellSize; 453 target->StrokeLine(BPoint(fPaletteFrame.left, y), 454 BPoint(fPaletteFrame.right, y)); 455 } 456 457 // colors 458 for (int col = colBegin; col < colEnd; col++) { 459 for (int row = rowBegin; row < rowEnd; row++) { 460 uint8 colorIndex = row * fColumns + col; 461 float x = fPaletteFrame.left + col * fCellSize; 462 float y = fPaletteFrame.top + row * fCellSize; 463 464 target->SetHighColor(system_colors()->color_list[colorIndex]); 465 target->FillRect(BRect(x + 1, y + 1, 466 x + fCellSize - 1, y + fCellSize - 1)); 467 } 468 } 469 } else { 470 rgb_color white = { 255, 255, 255, 255 }; 471 rgb_color red = { 255, 0, 0, 255 }; 472 rgb_color green = { 0, 255, 0, 255 }; 473 rgb_color blue = { 0, 0, 255, 255 }; 474 475 rgb_color compColor = { 0, 0, 0, 255 }; 476 if (!enabled) { 477 compColor.red = compColor.green = compColor.blue = 156; 478 red.red = green.green = blue.blue = 70; 479 white.red = white.green = white.blue = 70; 480 } 481 _DrawColorRamp(_RampFrame(0), target, white, compColor, 0, false, 482 updateRect); 483 _DrawColorRamp(_RampFrame(1), target, red, compColor, 0, false, 484 updateRect); 485 _DrawColorRamp(_RampFrame(2), target, green, compColor, 0, false, 486 updateRect); 487 _DrawColorRamp(_RampFrame(3), target, blue, compColor, 0, false, 488 updateRect); 489 } 490 } 491 492 493 void 494 BColorControl::_DrawSelectors(BView* target) 495 { 496 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 497 rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT); 498 499 if (fPaletteMode) { 500 if (fSelectedPaletteColorIndex != -1) { 501 target->SetHighColor(lightenmax); 502 target->StrokeRect( 503 _PaletteSelectorFrame(fSelectedPaletteColorIndex)); 504 } 505 } else { 506 rgb_color color = ValueAsColor(); 507 target->SetHighColor(255, 255, 255); 508 target->SetLowColor(0, 0, 0); 509 510 int components[4] = { color.alpha, color.red, color.green, color.blue }; 511 512 for (int i = 1; i < 4; i++) { 513 BPoint center = _SelectorPosition(_RampFrame(i), components[i]); 514 515 target->SetPenSize(kSelectorPenSize); 516 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 517 target->SetPenSize(kSelectorPenSize / 2); 518 target->StrokeEllipse(center, kSelectorSize, kSelectorSize, 519 B_SOLID_LOW); 520 if (i == fFocusedRamp) { 521 target->StrokeEllipse(center, 522 kSelectorSize / 2, kSelectorSize / 2, B_SOLID_LOW); 523 } 524 } 525 526 target->SetPenSize(1.0f); 527 } 528 } 529 530 531 void 532 BColorControl::_DrawColorRamp(BRect rect, BView* target, 533 rgb_color baseColor, rgb_color compColor, int16 flag, bool focused, 534 BRect updateRect) 535 { 536 float width = rect.Width() + 1; 537 rgb_color color = ValueAsColor(); 538 color.alpha = 255; 539 540 updateRect = updateRect & rect; 541 542 if (updateRect.IsValid() && updateRect.Width() >= 0) { 543 target->BeginLineArray((int32)updateRect.Width() + 1); 544 545 for (float i = (updateRect.left - rect.left); 546 i <= (updateRect.right - rect.left) + 1; i++) { 547 if (baseColor.red == 255) 548 color.red = (uint8)(i * 255 / width) + compColor.red; 549 if (baseColor.green == 255) 550 color.green = (uint8)(i * 255 / width) + compColor.green; 551 if (baseColor.blue == 255) 552 color.blue = (uint8)(i * 255 / width) + compColor.blue; 553 554 target->AddLine(BPoint(rect.left + i, rect.top), 555 BPoint(rect.left + i, rect.bottom - 1), color); 556 } 557 558 target->EndLineArray(); 559 } 560 } 561 562 563 BPoint 564 BColorControl::_SelectorPosition(const BRect& rampRect, uint8 shade) const 565 { 566 float radius = kSelectorSize / 2 + kSelectorPenSize / 2; 567 568 return BPoint(rampRect.left + kSelectorHSpacing + radius + 569 shade * (rampRect.Width() - 2 * (kSelectorHSpacing + radius)) / 255, 570 rampRect.top + rampRect.Height() / 2); 571 } 572 573 574 BRect 575 BColorControl::_PaletteFrame() const 576 { 577 return fPaletteFrame.InsetByCopy(-kBevelSpacing, -kBevelSpacing); 578 } 579 580 581 BRect 582 BColorControl::_RampFrame(uint8 rampIndex) const 583 { 584 float rampHeight = (float)(fRows * fCellSize / kRampCount); 585 586 return BRect(fPaletteFrame.left, 587 fPaletteFrame.top + float(rampIndex) * rampHeight, 588 fPaletteFrame.right, 589 fPaletteFrame.top + float(rampIndex + 1) * rampHeight); 590 } 591 592 593 void 594 BColorControl::_SetCellSize(float size) 595 { 596 BFont font; 597 GetFont(&font); 598 fCellSize = std::max(kMinCellSize, 599 ceilf(size * font.Size() / kDefaultFontSize)); 600 } 601 602 603 float 604 BColorControl::_TextRectOffset() 605 { 606 return std::max(fRedText->Bounds().Height(), 607 ceilf(_PaletteFrame().Height() / 3)); 608 } 609 610 611 BRect 612 BColorControl::_PaletteSelectorFrame(uint8 colorIndex) const 613 { 614 uint32 row = colorIndex / fColumns; 615 uint32 column = colorIndex % fColumns; 616 float x = fPaletteFrame.left + column * fCellSize; 617 float y = fPaletteFrame.top + row * fCellSize; 618 return BRect(x, y, x + fCellSize, y + fCellSize); 619 } 620 621 622 void 623 BColorControl::_InitOffscreen() 624 { 625 if (fOffscreenBitmap->Lock()) { 626 BView* offscreenView = fOffscreenBitmap->ChildAt((int32)0); 627 if (offscreenView != NULL) { 628 _DrawColorArea(offscreenView, _PaletteFrame()); 629 offscreenView->Sync(); 630 } 631 fOffscreenBitmap->Unlock(); 632 } 633 } 634 635 636 void 637 BColorControl::_InvalidateSelector(int16 ramp, rgb_color color, bool focused) 638 { 639 if (fPaletteMode) 640 return; 641 642 if (ramp < 1 || ramp > 3) 643 return; 644 645 float invalidateRadius = focused 646 ? kSelectorSize + kSelectorPenSize / 2 647 : kSelectorSize / 2 + kSelectorPenSize; 648 649 uint8 colorValue = ramp == 1 ? color.red : ramp == 2 ? color.green 650 : color.blue; 651 652 BPoint pos = _SelectorPosition(_RampFrame(ramp), colorValue); 653 Invalidate(BRect(pos.x - invalidateRadius, pos.y - invalidateRadius, 654 pos.x + invalidateRadius, pos.y + invalidateRadius)); 655 } 656 657 658 void 659 BColorControl::SetCellSize(float size) 660 { 661 _SetCellSize(size); 662 ResizeToPreferred(); 663 } 664 665 666 float 667 BColorControl::CellSize() const 668 { 669 return fCellSize; 670 } 671 672 673 void 674 BColorControl::SetLayout(color_control_layout layout) 675 { 676 switch (layout) { 677 case B_CELLS_4x64: 678 fColumns = 4; 679 fRows = 64; 680 break; 681 682 case B_CELLS_8x32: 683 fColumns = 8; 684 fRows = 32; 685 break; 686 687 case B_CELLS_16x16: 688 fColumns = 16; 689 fRows = 16; 690 break; 691 692 case B_CELLS_32x8: 693 fColumns = 32; 694 fRows = 8; 695 break; 696 697 case B_CELLS_64x4: 698 fColumns = 64; 699 fRows = 4; 700 break; 701 } 702 703 ResizeToPreferred(); 704 Invalidate(); 705 } 706 707 708 color_control_layout 709 BColorControl::Layout() const 710 { 711 if (fColumns == 4 && fRows == 64) 712 return B_CELLS_4x64; 713 714 if (fColumns == 8 && fRows == 32) 715 return B_CELLS_8x32; 716 717 if (fColumns == 16 && fRows == 16) 718 return B_CELLS_16x16; 719 720 if (fColumns == 32 && fRows == 8) 721 return B_CELLS_32x8; 722 723 if (fColumns == 64 && fRows == 4) 724 return B_CELLS_64x4; 725 726 return B_CELLS_32x8; 727 } 728 729 730 void 731 BColorControl::WindowActivated(bool state) 732 { 733 BControl::WindowActivated(state); 734 } 735 736 737 void 738 BColorControl::KeyDown(const char* bytes, int32 numBytes) 739 { 740 if (IsFocus() && !fPaletteMode && numBytes == 1) { 741 rgb_color color = ValueAsColor(); 742 743 switch (bytes[0]) { 744 case B_UP_ARROW: 745 { 746 int16 oldFocus = fFocusedRamp; 747 fFocusedRamp--; 748 if (fFocusedRamp < 1) 749 fFocusedRamp = 3; 750 751 _InvalidateSelector(oldFocus, color, true); 752 _InvalidateSelector(fFocusedRamp, color, true); 753 break; 754 } 755 756 case B_DOWN_ARROW: 757 { 758 int16 oldFocus = fFocusedRamp; 759 fFocusedRamp++; 760 if (fFocusedRamp > 3) 761 fFocusedRamp = 1; 762 763 _InvalidateSelector(oldFocus, color, true); 764 _InvalidateSelector(fFocusedRamp, color, true); 765 break; 766 } 767 768 case B_LEFT_ARROW: 769 { 770 bool goFaster = false; 771 if (Window() != NULL) { 772 BMessage* message = Window()->CurrentMessage(); 773 if (message != NULL && message->what == B_KEY_DOWN) { 774 int32 repeats = 0; 775 if (message->FindInt32("be:key_repeat", &repeats) 776 == B_OK && repeats > 4) { 777 goFaster = true; 778 } 779 } 780 } 781 782 if (fFocusedRamp == 1) { 783 if (goFaster && color.red >= 5) 784 color.red -= 5; 785 else if (color.red > 0) 786 color.red--; 787 } else if (fFocusedRamp == 2) { 788 if (goFaster && color.green >= 5) 789 color.green -= 5; 790 else if (color.green > 0) 791 color.green--; 792 } else if (fFocusedRamp == 3) { 793 if (goFaster && color.blue >= 5) 794 color.blue -= 5; 795 else if (color.blue > 0) 796 color.blue--; 797 } 798 799 SetValue(color); 800 Invoke(); 801 break; 802 } 803 804 case B_RIGHT_ARROW: 805 { 806 bool goFaster = false; 807 if (Window() != NULL) { 808 BMessage* message = Window()->CurrentMessage(); 809 if (message != NULL && message->what == B_KEY_DOWN) { 810 int32 repeats = 0; 811 if (message->FindInt32("be:key_repeat", &repeats) 812 == B_OK && repeats > 4) { 813 goFaster = true; 814 } 815 } 816 } 817 818 if (fFocusedRamp == 1) { 819 if (goFaster && color.red <= 250) 820 color.red += 5; 821 else if (color.red < 255) 822 color.red++; 823 } else if (fFocusedRamp == 2) { 824 if (goFaster && color.green <= 250) 825 color.green += 5; 826 else if (color.green < 255) 827 color.green++; 828 } else if (fFocusedRamp == 3) { 829 if (goFaster && color.blue <= 250) 830 color.blue += 5; 831 else if (color.blue < 255) 832 color.blue++; 833 } 834 835 SetValue(color); 836 Invoke(); 837 break; 838 } 839 } 840 } 841 842 BControl::KeyDown(bytes, numBytes); 843 } 844 845 846 void 847 BColorControl::MouseUp(BPoint point) 848 { 849 fClickedRamp = -1; 850 SetTracking(false); 851 } 852 853 854 void 855 BColorControl::MouseDown(BPoint point) 856 { 857 if (!IsEnabled()) 858 return; 859 if (!fPaletteFrame.Contains(point)) 860 return; 861 862 if (fPaletteMode) { 863 int col = (int)((point.x - fPaletteFrame.left) / fCellSize); 864 int row = (int)((point.y - fPaletteFrame.top) / fCellSize); 865 int colorIndex = row * fColumns + col; 866 if (colorIndex >= 0 && colorIndex < 256) { 867 fSelectedPaletteColorIndex = colorIndex; 868 SetValue(system_colors()->color_list[colorIndex]); 869 } 870 } else { 871 rgb_color color = ValueAsColor(); 872 873 uint8 shade = (unsigned char)max_c(0, 874 min_c((point.x - _RampFrame(0).left) * 255 875 / _RampFrame(0).Width(), 255)); 876 877 if (_RampFrame(0).Contains(point)) { 878 color.red = color.green = color.blue = shade; 879 fClickedRamp = 0; 880 } else if (_RampFrame(1).Contains(point)) { 881 color.red = shade; 882 fClickedRamp = 1; 883 } else if (_RampFrame(2).Contains(point)) { 884 color.green = shade; 885 fClickedRamp = 2; 886 } else if (_RampFrame(3).Contains(point)) { 887 color.blue = shade; 888 fClickedRamp = 3; 889 } 890 891 SetValue(color); 892 } 893 894 Invoke(); 895 896 SetTracking(true); 897 SetMouseEventMask(B_POINTER_EVENTS, 898 B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS); 899 } 900 901 902 void 903 BColorControl::MouseMoved(BPoint point, uint32 transit, 904 const BMessage* message) 905 { 906 if (!IsTracking()) 907 return; 908 909 if (fPaletteMode && fPaletteFrame.Contains(point)) { 910 int col = (int)((point.x - fPaletteFrame.left) / fCellSize); 911 int row = (int)((point.y - fPaletteFrame.top) / fCellSize); 912 int colorIndex = row * fColumns + col; 913 if (colorIndex >= 0 && colorIndex < 256) { 914 fSelectedPaletteColorIndex = colorIndex; 915 SetValue(system_colors()->color_list[colorIndex]); 916 } 917 } else { 918 if (fClickedRamp < 0 || fClickedRamp > 3) 919 return; 920 921 rgb_color color = ValueAsColor(); 922 923 uint8 shade = (unsigned char)max_c(0, 924 min_c((point.x - _RampFrame(0).left) * 255 925 / _RampFrame(0).Width(), 255)); 926 927 if (fClickedRamp == 0) 928 color.red = color.green = color.blue = shade; 929 else if (fClickedRamp == 1) 930 color.red = shade; 931 else if (fClickedRamp == 2) 932 color.green = shade; 933 else if (fClickedRamp == 3) 934 color.blue = shade; 935 936 SetValue(color); 937 } 938 939 Invoke(); 940 } 941 942 943 void 944 BColorControl::DetachedFromWindow() 945 { 946 BControl::DetachedFromWindow(); 947 } 948 949 950 void 951 BColorControl::GetPreferredSize(float* _width, float* _height) 952 { 953 BRect rect = _PaletteFrame(); 954 955 if (rect.Height() < fBlueText->Frame().bottom) { 956 // adjust the height to fit 957 rect.bottom = fBlueText->Frame().bottom; 958 } 959 960 if (_width) { 961 *_width = rect.Width() + kTextFieldsHSpacing 962 + fRedText->Bounds().Width(); 963 } 964 965 if (_height) 966 *_height = rect.Height(); 967 } 968 969 970 void 971 BColorControl::ResizeToPreferred() 972 { 973 _LayoutView(); 974 BControl::ResizeToPreferred(); 975 } 976 977 978 status_t 979 BColorControl::Invoke(BMessage* message) 980 { 981 return BControl::Invoke(message); 982 } 983 984 985 void 986 BColorControl::FrameMoved(BPoint newPosition) 987 { 988 BControl::FrameMoved(newPosition); 989 } 990 991 992 void 993 BColorControl::FrameResized(float newWidth, float newHeight) 994 { 995 BControl::FrameResized(newWidth, newHeight); 996 } 997 998 999 BHandler* 1000 BColorControl::ResolveSpecifier(BMessage* message, int32 index, 1001 BMessage* specifier, int32 form, const char* property) 1002 { 1003 return BControl::ResolveSpecifier(message, index, specifier, form, 1004 property); 1005 } 1006 1007 1008 status_t 1009 BColorControl::GetSupportedSuites(BMessage* data) 1010 { 1011 return BControl::GetSupportedSuites(data); 1012 } 1013 1014 1015 void 1016 BColorControl::MakeFocus(bool focused) 1017 { 1018 fFocusedRamp = !fPaletteMode && focused ? 1 : -1; 1019 BControl::MakeFocus(focused); 1020 } 1021 1022 1023 void 1024 BColorControl::AllAttached() 1025 { 1026 BControl::AllAttached(); 1027 } 1028 1029 1030 void 1031 BColorControl::AllDetached() 1032 { 1033 BControl::AllDetached(); 1034 } 1035 1036 1037 status_t 1038 BColorControl::SetIcon(const BBitmap* icon, uint32 flags) 1039 { 1040 return BControl::SetIcon(icon, flags); 1041 } 1042 1043 1044 status_t 1045 BColorControl::Perform(perform_code code, void* _data) 1046 { 1047 switch (code) { 1048 case PERFORM_CODE_MIN_SIZE: 1049 ((perform_data_min_size*)_data)->return_value 1050 = BColorControl::MinSize(); 1051 return B_OK; 1052 1053 case PERFORM_CODE_MAX_SIZE: 1054 ((perform_data_max_size*)_data)->return_value 1055 = BColorControl::MaxSize(); 1056 return B_OK; 1057 1058 case PERFORM_CODE_PREFERRED_SIZE: 1059 ((perform_data_preferred_size*)_data)->return_value 1060 = BColorControl::PreferredSize(); 1061 return B_OK; 1062 1063 case PERFORM_CODE_LAYOUT_ALIGNMENT: 1064 ((perform_data_layout_alignment*)_data)->return_value 1065 = BColorControl::LayoutAlignment(); 1066 return B_OK; 1067 1068 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 1069 ((perform_data_has_height_for_width*)_data)->return_value 1070 = BColorControl::HasHeightForWidth(); 1071 return B_OK; 1072 1073 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 1074 { 1075 perform_data_get_height_for_width* data 1076 = (perform_data_get_height_for_width*)_data; 1077 BColorControl::GetHeightForWidth(data->width, &data->min, 1078 &data->max, &data->preferred); 1079 return B_OK; 1080 } 1081 1082 case PERFORM_CODE_SET_LAYOUT: 1083 { 1084 perform_data_set_layout* data = (perform_data_set_layout*)_data; 1085 BColorControl::SetLayout(data->layout); 1086 return B_OK; 1087 } 1088 1089 case PERFORM_CODE_LAYOUT_INVALIDATED: 1090 { 1091 perform_data_layout_invalidated* data 1092 = (perform_data_layout_invalidated*)_data; 1093 BColorControl::LayoutInvalidated(data->descendants); 1094 return B_OK; 1095 } 1096 1097 case PERFORM_CODE_DO_LAYOUT: 1098 { 1099 BColorControl::DoLayout(); 1100 return B_OK; 1101 } 1102 1103 case PERFORM_CODE_SET_ICON: 1104 { 1105 perform_data_set_icon* data = (perform_data_set_icon*)_data; 1106 return BColorControl::SetIcon(data->icon, data->flags); 1107 } 1108 } 1109 1110 return BControl::Perform(code, _data); 1111 } 1112 1113 1114 void BColorControl::_ReservedColorControl1() {} 1115 void BColorControl::_ReservedColorControl2() {} 1116 void BColorControl::_ReservedColorControl3() {} 1117 void BColorControl::_ReservedColorControl4() {} 1118 1119 1120 BColorControl & 1121 BColorControl::operator=(const BColorControl &) 1122 { 1123 return *this; 1124 } 1125