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