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