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