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 if (Parent()) 337 SetViewColor(Parent()->ViewColor()); 338 else 339 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 340 341 BControl::AttachedToWindow(); 342 343 fRedText->SetTarget(this); 344 fGreenText->SetTarget(this); 345 fBlueText->SetTarget(this); 346 347 if (fBitmap) 348 _InitOffscreen(); 349 } 350 351 352 void 353 BColorControl::MessageReceived(BMessage* message) 354 { 355 switch (message->what) { 356 case kMsgColorEntered: 357 { 358 rgb_color color; 359 color.red = min_c(strtol(fRedText->Text(), NULL, 10), 255); 360 color.green = min_c(strtol(fGreenText->Text(), NULL, 10), 255); 361 color.blue = min_c(strtol(fBlueText->Text(), NULL, 10), 255); 362 color.alpha = 255; 363 364 SetValue(color); 365 Invoke(); 366 break; 367 } 368 default: 369 BControl::MessageReceived(message); 370 } 371 } 372 373 374 void 375 BColorControl::Draw(BRect updateRect) 376 { 377 if (fBitmap != NULL) 378 DrawBitmap(fBitmap, B_ORIGIN); 379 else 380 _DrawColorArea(this, updateRect); 381 382 _DrawSelectors(this); 383 } 384 385 386 void 387 BColorControl::_DrawColorArea(BView* target, BRect updateRect) 388 { 389 BRect rect = _PaletteFrame(); 390 bool enabled = IsEnabled(); 391 392 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 393 rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT); 394 395 if (be_control_look != NULL) { 396 uint32 flags = be_control_look->Flags(this); 397 be_control_look->DrawTextControlBorder(target, rect, updateRect, 398 base, flags); 399 } else { 400 // first bevel 401 rgb_color lighten1 = tint_color(base, B_LIGHTEN_1_TINT); 402 rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT); 403 target->SetHighColor(enabled ? darken1 : base); 404 405 target->StrokeLine(rect.LeftBottom(), rect.LeftTop()); 406 target->StrokeLine(rect.LeftTop(), rect.RightTop()); 407 target->SetHighColor(enabled ? lightenmax : lighten1); 408 409 target->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), 410 rect.RightBottom()); 411 target->StrokeLine(rect.RightBottom(), 412 BPoint(rect.right, rect.top + 1.0f)); 413 414 rect.InsetBy(1.0f, 1.0f); 415 416 // second bevel 417 rgb_color darken2 = tint_color(base, B_DARKEN_2_TINT); 418 rgb_color darken4 = tint_color(base, B_DARKEN_4_TINT); 419 target->SetHighColor(enabled ? darken4 : darken2); 420 421 target->StrokeLine(rect.LeftBottom(), rect.LeftTop()); 422 target->StrokeLine(rect.LeftTop(), rect.RightTop()); 423 target->SetHighColor(base); 424 target->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), 425 rect.RightBottom()); 426 target->StrokeLine(rect.RightBottom(), 427 BPoint(rect.right, rect.top + 1.0f)); 428 } 429 430 if (fPaletteMode) { 431 int colBegin = max_c(0, -1 + int(updateRect.left) / int(fCellSize)); 432 int colEnd = min_c(fColumns, 433 2 + int(updateRect.right) / int(fCellSize)); 434 int rowBegin = max_c(0, -1 + int(updateRect.top) / int(fCellSize)); 435 int rowEnd = min_c(fRows, 2 + int(updateRect.bottom) 436 / int(fCellSize)); 437 438 // grid 439 target->SetHighColor(enabled ? darken1 : base); 440 441 for (int xi = 0; xi < fColumns + 1; xi++) { 442 float x = fPaletteFrame.left + float(xi) * fCellSize; 443 target->StrokeLine(BPoint(x, fPaletteFrame.top), 444 BPoint(x, fPaletteFrame.bottom)); 445 } 446 for (int yi = 0; yi < fRows + 1; yi++) { 447 float y = fPaletteFrame.top + float(yi) * fCellSize; 448 target->StrokeLine(BPoint(fPaletteFrame.left, y), 449 BPoint(fPaletteFrame.right, y)); 450 } 451 452 // colors 453 for (int col = colBegin; col < colEnd; col++) { 454 for (int row = rowBegin; row < rowEnd; row++) { 455 uint8 colorIndex = row * fColumns + col; 456 float x = fPaletteFrame.left + col * fCellSize; 457 float y = fPaletteFrame.top + row * fCellSize; 458 459 target->SetHighColor(system_colors()->color_list[colorIndex]); 460 target->FillRect(BRect(x + 1, y + 1, 461 x + fCellSize - 1, y + fCellSize - 1)); 462 } 463 } 464 } else { 465 rgb_color white = { 255, 255, 255, 255 }; 466 rgb_color red = { 255, 0, 0, 255 }; 467 rgb_color green = { 0, 255, 0, 255 }; 468 rgb_color blue = { 0, 0, 255, 255 }; 469 470 rgb_color compColor = { 0, 0, 0, 255 }; 471 if (!enabled) { 472 compColor.red = compColor.green = compColor.blue = 156; 473 red.red = green.green = blue.blue = 70; 474 white.red = white.green = white.blue = 70; 475 } 476 _DrawColorRamp(_RampFrame(0), target, white, compColor, 0, false, 477 updateRect); 478 _DrawColorRamp(_RampFrame(1), target, red, compColor, 0, false, 479 updateRect); 480 _DrawColorRamp(_RampFrame(2), target, green, compColor, 0, false, 481 updateRect); 482 _DrawColorRamp(_RampFrame(3), target, blue, compColor, 0, false, 483 updateRect); 484 } 485 } 486 487 488 void 489 BColorControl::_DrawSelectors(BView* target) 490 { 491 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 492 rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT); 493 494 if (fPaletteMode) { 495 if (fSelectedPaletteColorIndex != -1) { 496 target->SetHighColor(lightenmax); 497 target->StrokeRect(_PaletteSelectorFrame(fSelectedPaletteColorIndex)); 498 } 499 } else { 500 rgb_color color = ValueAsColor(); 501 target->SetHighColor(255, 255, 255); 502 target->SetLowColor(0, 0, 0); 503 504 int components[4] = { color.alpha, color.red, color.green, color.blue }; 505 506 for (int i = 1; i < 4; i++) { 507 BPoint center = _SelectorPosition(_RampFrame(i), components[i]); 508 509 target->SetPenSize(kSelectorPenSize); 510 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 511 target->SetPenSize(kSelectorPenSize / 2); 512 target->StrokeEllipse(center, kSelectorSize, kSelectorSize, 513 B_SOLID_LOW); 514 if (i == fFocusedRamp) { 515 target->StrokeEllipse(center, 516 kSelectorSize / 2, kSelectorSize / 2, B_SOLID_LOW); 517 } 518 } 519 520 target->SetPenSize(1.0f); 521 } 522 } 523 524 525 void 526 BColorControl::_DrawColorRamp(BRect rect, BView* target, 527 rgb_color baseColor, rgb_color compColor, int16 flag, bool focused, 528 BRect updateRect) 529 { 530 float width = rect.Width() + 1; 531 rgb_color color = ValueAsColor(); 532 color.alpha = 255; 533 534 updateRect = updateRect & rect; 535 536 if (updateRect.IsValid() && updateRect.Width() >= 0) { 537 target->BeginLineArray((int32)updateRect.Width() + 1); 538 539 for (float i = (updateRect.left - rect.left); 540 i <= (updateRect.right - rect.left) + 1; i++) { 541 if (baseColor.red == 255) 542 color.red = (uint8)(i * 255 / width) + compColor.red; 543 if (baseColor.green == 255) 544 color.green = (uint8)(i * 255 / width) + compColor.green; 545 if (baseColor.blue == 255) 546 color.blue = (uint8)(i * 255 / width) + compColor.blue; 547 548 target->AddLine(BPoint(rect.left + i, rect.top), 549 BPoint(rect.left + i, rect.bottom - 1), color); 550 } 551 552 target->EndLineArray(); 553 } 554 } 555 556 557 BPoint 558 BColorControl::_SelectorPosition(const BRect& rampRect, uint8 shade) const 559 { 560 float radius = kSelectorSize / 2 + kSelectorPenSize / 2; 561 562 return BPoint(rampRect.left + kSelectorHSpacing + radius + 563 shade * (rampRect.Width() - 2 * (kSelectorHSpacing + radius)) / 255, 564 rampRect.top + rampRect.Height() / 2); 565 } 566 567 568 BRect 569 BColorControl::_PaletteFrame() const 570 { 571 return fPaletteFrame.InsetByCopy(-kBevelSpacing, -kBevelSpacing); 572 } 573 574 575 BRect 576 BColorControl::_RampFrame(uint8 rampIndex) const 577 { 578 float rampHeight = (float)(fRows * fCellSize / kRampCount); 579 580 return BRect(fPaletteFrame.left, 581 fPaletteFrame.top + float(rampIndex) * rampHeight, 582 fPaletteFrame.right, 583 fPaletteFrame.top + float(rampIndex + 1) * rampHeight); 584 } 585 586 587 void 588 BColorControl::_SetCellSize(float size) 589 { 590 BFont font; 591 GetFont(&font); 592 fCellSize = std::max(kMinCellSize, 593 ceilf(size * font.Size() / kDefaultFontSize)); 594 } 595 596 597 float 598 BColorControl::_TextRectOffset() 599 { 600 return std::max(fRedText->Bounds().Height(), 601 ceilf(_PaletteFrame().Height() / 3)); 602 } 603 604 605 BRect 606 BColorControl::_PaletteSelectorFrame(uint8 colorIndex) const 607 { 608 uint32 row = colorIndex / fColumns; 609 uint32 column = colorIndex % fColumns; 610 float x = fPaletteFrame.left + column * fCellSize; 611 float y = fPaletteFrame.top + row * fCellSize; 612 return BRect(x, y, x + fCellSize, y + fCellSize); 613 } 614 615 616 void 617 BColorControl::_InitOffscreen() 618 { 619 if (fBitmap->Lock()) { 620 _DrawColorArea(fOffscreenView, _PaletteFrame()); 621 fOffscreenView->Sync(); 622 fBitmap->Unlock(); 623 } 624 } 625 626 627 void 628 BColorControl::_InvalidateSelector(int16 ramp, rgb_color color, bool focused) 629 { 630 if (fPaletteMode) 631 return; 632 633 if (ramp < 1 || ramp > 3) 634 return; 635 636 float invalidateRadius = focused 637 ? kSelectorSize + kSelectorPenSize / 2 638 : kSelectorSize / 2 + kSelectorPenSize; 639 640 uint8 colorValue = ramp == 1 ? color.red : ramp == 2 ? color.green 641 : color.blue; 642 643 BPoint pos = _SelectorPosition(_RampFrame(ramp), colorValue); 644 Invalidate(BRect(pos.x - invalidateRadius, pos.y - invalidateRadius, 645 pos.x + invalidateRadius, pos.y + invalidateRadius)); 646 } 647 648 649 void 650 BColorControl::SetCellSize(float size) 651 { 652 _SetCellSize(size); 653 ResizeToPreferred(); 654 } 655 656 657 float 658 BColorControl::CellSize() const 659 { 660 return fCellSize; 661 } 662 663 664 void 665 BColorControl::SetLayout(color_control_layout layout) 666 { 667 switch (layout) { 668 case B_CELLS_4x64: 669 fColumns = 4; 670 fRows = 64; 671 break; 672 case B_CELLS_8x32: 673 fColumns = 8; 674 fRows = 32; 675 break; 676 case B_CELLS_16x16: 677 fColumns = 16; 678 fRows = 16; 679 break; 680 case B_CELLS_32x8: 681 fColumns = 32; 682 fRows = 8; 683 break; 684 case B_CELLS_64x4: 685 fColumns = 64; 686 fRows = 4; 687 break; 688 } 689 690 ResizeToPreferred(); 691 Invalidate(); 692 } 693 694 695 color_control_layout 696 BColorControl::Layout() const 697 { 698 if (fColumns == 4 && fRows == 64) 699 return B_CELLS_4x64; 700 if (fColumns == 8 && fRows == 32) 701 return B_CELLS_8x32; 702 if (fColumns == 16 && fRows == 16) 703 return B_CELLS_16x16; 704 if (fColumns == 32 && fRows == 8) 705 return B_CELLS_32x8; 706 if (fColumns == 64 && fRows == 4) 707 return B_CELLS_64x4; 708 709 return B_CELLS_32x8; 710 } 711 712 713 void 714 BColorControl::WindowActivated(bool state) 715 { 716 BControl::WindowActivated(state); 717 } 718 719 720 void 721 BColorControl::KeyDown(const char* bytes, int32 numBytes) 722 { 723 if (IsFocus() && !fPaletteMode && numBytes == 1) { 724 rgb_color color = ValueAsColor(); 725 726 switch (bytes[0]) { 727 case B_UP_ARROW: 728 { 729 int16 oldFocus = fFocusedRamp; 730 fFocusedRamp--; 731 if (fFocusedRamp < 1) 732 fFocusedRamp = 3; 733 734 _InvalidateSelector(oldFocus, color, true); 735 _InvalidateSelector(fFocusedRamp, color, true); 736 break; 737 } 738 739 case B_DOWN_ARROW: 740 { 741 int16 oldFocus = fFocusedRamp; 742 fFocusedRamp++; 743 if (fFocusedRamp > 3) 744 fFocusedRamp = 1; 745 746 _InvalidateSelector(oldFocus, color, true); 747 _InvalidateSelector(fFocusedRamp, color, true); 748 break; 749 } 750 751 case B_LEFT_ARROW: 752 { 753 bool goFaster = false; 754 if (Window() != NULL) { 755 BMessage* message = Window()->CurrentMessage(); 756 if (message != NULL && message->what == B_KEY_DOWN) { 757 int32 repeats = 0; 758 if (message->FindInt32("be:key_repeat", &repeats) 759 == B_OK && repeats > 4) { 760 goFaster = true; 761 } 762 } 763 } 764 765 if (fFocusedRamp == 1) { 766 if (goFaster && color.red >= 5) 767 color.red -= 5; 768 else if (color.red > 0) 769 color.red--; 770 } else if (fFocusedRamp == 2) { 771 if (goFaster && color.green >= 5) 772 color.green -= 5; 773 else if (color.green > 0) 774 color.green--; 775 } else if (fFocusedRamp == 3) { 776 if (goFaster && color.blue >= 5) 777 color.blue -= 5; 778 else if (color.blue > 0) 779 color.blue--; 780 } 781 782 SetValue(color); 783 Invoke(); 784 break; 785 } 786 787 case B_RIGHT_ARROW: 788 { 789 bool goFaster = false; 790 if (Window() != NULL) { 791 BMessage* message = Window()->CurrentMessage(); 792 if (message != NULL && message->what == B_KEY_DOWN) { 793 int32 repeats = 0; 794 if (message->FindInt32("be:key_repeat", &repeats) 795 == B_OK && repeats > 4) { 796 goFaster = true; 797 } 798 } 799 } 800 801 if (fFocusedRamp == 1) { 802 if (goFaster && color.red <= 250) 803 color.red += 5; 804 else if (color.red < 255) 805 color.red++; 806 } else if (fFocusedRamp == 2) { 807 if (goFaster && color.green <= 250) 808 color.green += 5; 809 else if (color.green < 255) 810 color.green++; 811 } else if (fFocusedRamp == 3) { 812 if (goFaster && color.blue <= 250) 813 color.blue += 5; 814 else if (color.blue < 255) 815 color.blue++; 816 } 817 818 SetValue(color); 819 Invoke(); 820 break; 821 } 822 } 823 } 824 825 BControl::KeyDown(bytes, numBytes); 826 } 827 828 829 void 830 BColorControl::MouseUp(BPoint point) 831 { 832 fClickedRamp = -1; 833 SetTracking(false); 834 } 835 836 837 void 838 BColorControl::MouseDown(BPoint point) 839 { 840 if (!IsEnabled()) 841 return; 842 if (!fPaletteFrame.Contains(point)) 843 return; 844 845 if (fPaletteMode) { 846 int col = (int)((point.x - fPaletteFrame.left) / fCellSize); 847 int row = (int)((point.y - fPaletteFrame.top) / fCellSize); 848 int colorIndex = row * fColumns + col; 849 if (colorIndex >= 0 && colorIndex < 256) { 850 fSelectedPaletteColorIndex = colorIndex; 851 SetValue(system_colors()->color_list[colorIndex]); 852 } 853 } else { 854 rgb_color color = ValueAsColor(); 855 856 uint8 shade = (unsigned char)max_c(0, 857 min_c((point.x - _RampFrame(0).left) * 255 858 / _RampFrame(0).Width(), 255)); 859 860 if (_RampFrame(0).Contains(point)) { 861 color.red = color.green = color.blue = shade; 862 fClickedRamp = 0; 863 } else if (_RampFrame(1).Contains(point)) { 864 color.red = shade; 865 fClickedRamp = 1; 866 } else if (_RampFrame(2).Contains(point)) { 867 color.green = shade; 868 fClickedRamp = 2; 869 } else if (_RampFrame(3).Contains(point)) { 870 color.blue = shade; 871 fClickedRamp = 3; 872 } 873 874 SetValue(color); 875 } 876 877 Invoke(); 878 879 SetTracking(true); 880 SetMouseEventMask(B_POINTER_EVENTS, 881 B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS); 882 } 883 884 885 void 886 BColorControl::MouseMoved(BPoint point, uint32 transit, 887 const BMessage* message) 888 { 889 if (!IsTracking()) 890 return; 891 892 if (fPaletteMode && fPaletteFrame.Contains(point)) { 893 int col = (int)((point.x - fPaletteFrame.left) / fCellSize); 894 int row = (int)((point.y - fPaletteFrame.top) / fCellSize); 895 int colorIndex = row * fColumns + col; 896 if (colorIndex >= 0 && colorIndex < 256) { 897 fSelectedPaletteColorIndex = colorIndex; 898 SetValue(system_colors()->color_list[colorIndex]); 899 } 900 } else { 901 if (fClickedRamp < 0 || fClickedRamp > 3) 902 return; 903 904 rgb_color color = ValueAsColor(); 905 906 uint8 shade = (unsigned char)max_c(0, 907 min_c((point.x - _RampFrame(0).left) * 255 908 / _RampFrame(0).Width(), 255)); 909 910 if (fClickedRamp == 0) 911 color.red = color.green = color.blue = shade; 912 else if (fClickedRamp == 1) 913 color.red = shade; 914 else if (fClickedRamp == 2) 915 color.green = shade; 916 else if (fClickedRamp == 3) 917 color.blue = shade; 918 919 SetValue(color); 920 } 921 922 Invoke(); 923 } 924 925 926 void 927 BColorControl::DetachedFromWindow() 928 { 929 BControl::DetachedFromWindow(); 930 } 931 932 933 void 934 BColorControl::GetPreferredSize(float* _width, float* _height) 935 { 936 BRect rect = _PaletteFrame(); 937 938 if (rect.Height() < fBlueText->Frame().bottom) { 939 // adjust the height to fit 940 rect.bottom = fBlueText->Frame().bottom; 941 } 942 943 if (_width) { 944 *_width = rect.Width() + kTextFieldsHSpacing 945 + fRedText->Bounds().Width(); 946 } 947 948 if (_height) 949 *_height = rect.Height(); 950 } 951 952 953 void 954 BColorControl::ResizeToPreferred() 955 { 956 _LayoutView(); 957 BControl::ResizeToPreferred(); 958 } 959 960 961 status_t 962 BColorControl::Invoke(BMessage* message) 963 { 964 return BControl::Invoke(message); 965 } 966 967 968 void 969 BColorControl::FrameMoved(BPoint newPosition) 970 { 971 BControl::FrameMoved(newPosition); 972 } 973 974 975 void 976 BColorControl::FrameResized(float newWidth, float newHeight) 977 { 978 BControl::FrameResized(newWidth, newHeight); 979 } 980 981 982 BHandler* 983 BColorControl::ResolveSpecifier(BMessage* message, int32 index, 984 BMessage* specifier, int32 form, const char* property) 985 { 986 return BControl::ResolveSpecifier(message, index, specifier, form, 987 property); 988 } 989 990 991 status_t 992 BColorControl::GetSupportedSuites(BMessage* data) 993 { 994 return BControl::GetSupportedSuites(data); 995 } 996 997 998 void 999 BColorControl::MakeFocus(bool focused) 1000 { 1001 fFocusedRamp = !fPaletteMode && focused ? 1 : -1; 1002 BControl::MakeFocus(focused); 1003 } 1004 1005 1006 void 1007 BColorControl::AllAttached() 1008 { 1009 BControl::AllAttached(); 1010 } 1011 1012 1013 void 1014 BColorControl::AllDetached() 1015 { 1016 BControl::AllDetached(); 1017 } 1018 1019 1020 status_t 1021 BColorControl::SetIcon(const BBitmap* icon, uint32 flags) 1022 { 1023 return BControl::SetIcon(icon, flags); 1024 } 1025 1026 1027 status_t 1028 BColorControl::Perform(perform_code code, void* _data) 1029 { 1030 switch (code) { 1031 case PERFORM_CODE_MIN_SIZE: 1032 ((perform_data_min_size*)_data)->return_value 1033 = BColorControl::MinSize(); 1034 return B_OK; 1035 case PERFORM_CODE_MAX_SIZE: 1036 ((perform_data_max_size*)_data)->return_value 1037 = BColorControl::MaxSize(); 1038 return B_OK; 1039 case PERFORM_CODE_PREFERRED_SIZE: 1040 ((perform_data_preferred_size*)_data)->return_value 1041 = BColorControl::PreferredSize(); 1042 return B_OK; 1043 case PERFORM_CODE_LAYOUT_ALIGNMENT: 1044 ((perform_data_layout_alignment*)_data)->return_value 1045 = BColorControl::LayoutAlignment(); 1046 return B_OK; 1047 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 1048 ((perform_data_has_height_for_width*)_data)->return_value 1049 = BColorControl::HasHeightForWidth(); 1050 return B_OK; 1051 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 1052 { 1053 perform_data_get_height_for_width* data 1054 = (perform_data_get_height_for_width*)_data; 1055 BColorControl::GetHeightForWidth(data->width, &data->min, 1056 &data->max, &data->preferred); 1057 return B_OK; 1058 } 1059 case PERFORM_CODE_SET_LAYOUT: 1060 { 1061 perform_data_set_layout* data = (perform_data_set_layout*)_data; 1062 BColorControl::SetLayout(data->layout); 1063 return B_OK; 1064 } 1065 case PERFORM_CODE_LAYOUT_INVALIDATED: 1066 { 1067 perform_data_layout_invalidated* data 1068 = (perform_data_layout_invalidated*)_data; 1069 BColorControl::LayoutInvalidated(data->descendants); 1070 return B_OK; 1071 } 1072 case PERFORM_CODE_DO_LAYOUT: 1073 { 1074 BColorControl::DoLayout(); 1075 return B_OK; 1076 } 1077 case PERFORM_CODE_SET_ICON: 1078 { 1079 perform_data_set_icon* data = (perform_data_set_icon*)_data; 1080 return BColorControl::SetIcon(data->icon, data->flags); 1081 } 1082 } 1083 1084 return BControl::Perform(code, _data); 1085 } 1086 1087 1088 void BColorControl::_ReservedColorControl1() {} 1089 void BColorControl::_ReservedColorControl2() {} 1090 void BColorControl::_ReservedColorControl3() {} 1091 void BColorControl::_ReservedColorControl4() {} 1092 1093 1094 BColorControl & 1095 BColorControl::operator=(const BColorControl &) 1096 { 1097 return *this; 1098 } 1099