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 bufferedDrawing) 51 : 52 BControl(BRect(leftTop, leftTop), name, NULL, message, 53 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE) 54 { 55 _InitData(layout, cellSize, bufferedDrawing, NULL); 56 } 57 58 59 BColorControl::BColorControl(BMessage* archive) 60 : 61 BControl(archive) 62 { 63 int32 layout; 64 float cellSize; 65 bool useOffscreen; 66 67 archive->FindInt32("_layout", &layout); 68 archive->FindFloat("_csize", &cellSize); 69 archive->FindBool("_use_off", &useOffscreen); 70 71 _InitData((color_control_layout)layout, cellSize, useOffscreen, archive); 72 } 73 74 75 BColorControl::~BColorControl() 76 { 77 delete fBitmap; 78 } 79 80 81 void 82 BColorControl::_InitData(color_control_layout layout, float size, 83 bool useOffscreen, BMessage* archive) 84 { 85 fPaletteMode = BScreen(B_MAIN_SCREEN_ID).ColorSpace() == B_CMAP8; 86 //TODO: we don't support workspace and colorspace changing for now 87 // so we take the main_screen colorspace at startup 88 fColumns = layout; 89 fRows = 256 / fColumns; 90 91 _SetCellSize(size); 92 93 fSelectedPaletteColorIndex = -1; 94 fPreviousSelectedPaletteColorIndex = -1; 95 fFocusedRamp = !fPaletteMode && IsFocus() ? 1 : -1; 96 fClickedRamp = -1; 97 98 const char* red = B_TRANSLATE_MARK("Red:"); 99 const char* green = B_TRANSLATE_MARK("Green:"); 100 const char* blue = B_TRANSLATE_MARK("Blue:"); 101 red = gSystemCatalog.GetString(red, "ColorControl"); 102 green = gSystemCatalog.GetString(green, "ColorControl"); 103 blue = gSystemCatalog.GetString(blue, "ColorControl"); 104 105 if (archive != NULL) { 106 fRedText = (BTextControl*)FindView("_red"); 107 fGreenText = (BTextControl*)FindView("_green"); 108 fBlueText = (BTextControl*)FindView("_blue"); 109 110 int32 value = 0; 111 archive->FindInt32("_val", &value); 112 113 SetValue(value); 114 } else { 115 BRect textRect(0.0f, 0.0f, 0.0f, 0.0f); 116 float labelWidth = std::max(StringWidth(red), 117 std::max(StringWidth(green), StringWidth(blue))) 118 + kTextFieldsHSpacing; 119 textRect.right = labelWidth + StringWidth("999999"); 120 // enough room for 3 digits plus 3 digits of padding 121 font_height fontHeight; 122 GetFontHeight(&fontHeight); 123 float labelHeight = fontHeight.ascent + fontHeight.descent; 124 textRect.bottom = labelHeight; 125 126 // red 127 128 fRedText = new BTextControl(textRect, "_red", red, "0", 129 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 130 B_WILL_DRAW | B_NAVIGABLE); 131 fRedText->SetDivider(labelWidth); 132 133 for (int32 i = 0; i < 256; i++) 134 fRedText->TextView()->DisallowChar(i); 135 for (int32 i = '0'; i <= '9'; i++) 136 fRedText->TextView()->AllowChar(i); 137 fRedText->TextView()->SetMaxBytes(3); 138 139 // green 140 141 textRect.OffsetBy(0, _TextRectOffset()); 142 fGreenText = new BTextControl(textRect, "_green", green, "0", 143 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 144 B_WILL_DRAW | B_NAVIGABLE); 145 fGreenText->SetDivider(labelWidth); 146 147 for (int32 i = 0; i < 256; i++) 148 fGreenText->TextView()->DisallowChar(i); 149 for (int32 i = '0'; i <= '9'; i++) 150 fGreenText->TextView()->AllowChar(i); 151 fGreenText->TextView()->SetMaxBytes(3); 152 153 // blue 154 155 textRect.OffsetBy(0, _TextRectOffset()); 156 fBlueText = new BTextControl(textRect, "_blue", blue, "0", 157 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 158 B_WILL_DRAW | B_NAVIGABLE); 159 fBlueText->SetDivider(labelWidth); 160 161 for (int32 i = 0; i < 256; i++) 162 fBlueText->TextView()->DisallowChar(i); 163 for (int32 i = '0'; i <= '9'; i++) 164 fBlueText->TextView()->AllowChar(i); 165 fBlueText->TextView()->SetMaxBytes(3); 166 167 AddChild(fRedText); 168 AddChild(fGreenText); 169 AddChild(fBlueText); 170 } 171 172 ResizeToPreferred(); 173 174 if (useOffscreen) { 175 BRect bounds = _PaletteFrame(); 176 fBitmap = new BBitmap(bounds, B_RGB32, true, false); 177 fOffscreenView = new BView(bounds, "off_view", 0, 0); 178 179 fBitmap->Lock(); 180 fBitmap->AddChild(fOffscreenView); 181 fBitmap->Unlock(); 182 } else { 183 fBitmap = NULL; 184 fOffscreenView = NULL; 185 } 186 } 187 188 189 void 190 BColorControl::_LayoutView() 191 { 192 fPaletteFrame.Set(0, 0, fColumns * fCellSize, fRows * fCellSize); 193 fPaletteFrame.OffsetBy(kBevelSpacing, kBevelSpacing); 194 if (!fPaletteMode) { 195 // Reduce the inner space by 1 pixel so that the frame 196 // is exactly rows * cellsize pixels in height 197 fPaletteFrame.bottom -= 1; 198 } 199 200 float rampHeight = (float)(fRows * fCellSize / kRampCount); 201 float offset = _TextRectOffset(); 202 float y = 0; 203 if (rampHeight > fRedText->Frame().Height()) { 204 // there is enough room to fit kRampCount labels, 205 // shift text controls down by one ramp 206 offset = rampHeight; 207 y = floorf(offset + (offset - fRedText->Frame().Height()) / 2); 208 } 209 210 BRect rect = _PaletteFrame(); 211 fRedText->MoveTo(rect.right + kTextFieldsHSpacing, y); 212 213 y += offset; 214 fGreenText->MoveTo(rect.right + kTextFieldsHSpacing, y); 215 216 y += offset; 217 fBlueText->MoveTo(rect.right + kTextFieldsHSpacing, y); 218 } 219 220 221 BArchivable* 222 BColorControl::Instantiate(BMessage* archive) 223 { 224 if (validate_instantiation(archive, "BColorControl")) 225 return new BColorControl(archive); 226 227 return NULL; 228 } 229 230 231 status_t 232 BColorControl::Archive(BMessage* archive, bool deep) const 233 { 234 status_t status = BControl::Archive(archive, deep); 235 236 if (status == B_OK) 237 status = archive->AddInt32("_layout", Layout()); 238 if (status == B_OK) 239 status = archive->AddFloat("_csize", fCellSize); 240 if (status == B_OK) 241 status = archive->AddBool("_use_off", fOffscreenView != NULL); 242 243 return status; 244 } 245 246 247 void 248 BColorControl::SetLayout(BLayout* layout) 249 { 250 // We need to implement this method, since we have another SetLayout() 251 // method and C++ has this special method hiding "feature". 252 BControl::SetLayout(layout); 253 } 254 255 256 void 257 BColorControl::SetValue(int32 value) 258 { 259 rgb_color c1 = ValueAsColor(); 260 rgb_color c2; 261 c2.red = (value & 0xFF000000) >> 24; 262 c2.green = (value & 0x00FF0000) >> 16; 263 c2.blue = (value & 0x0000FF00) >> 8; 264 c2.alpha = 255; 265 266 if (fPaletteMode) { 267 //workaround when two indexes have the same color 268 rgb_color c = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex); 269 c.alpha = 255; 270 if (fSelectedPaletteColorIndex == -1 || c != c2) { 271 //here SetValue hasn't been called by mouse tracking 272 fSelectedPaletteColorIndex = BScreen(Window()).IndexForColor(c2); 273 } 274 275 c2 = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex); 276 277 Invalidate(_PaletteSelectorFrame(fPreviousSelectedPaletteColorIndex)); 278 Invalidate(_PaletteSelectorFrame(fSelectedPaletteColorIndex)); 279 280 fPreviousSelectedPaletteColorIndex = fSelectedPaletteColorIndex; 281 } else { 282 if (c1.red != c2.red) { 283 _InvalidateSelector(1, c1, IsFocus() && fFocusedRamp == 1); 284 _InvalidateSelector(1, c2, IsFocus() && fFocusedRamp == 1); 285 } 286 if (c1.green != c2.green) { 287 _InvalidateSelector(2, c1, IsFocus() && fFocusedRamp == 2); 288 _InvalidateSelector(2, c2, IsFocus() && fFocusedRamp == 2); 289 } 290 if (c1.blue != c2.blue) { 291 _InvalidateSelector(3, c1, IsFocus() && fFocusedRamp == 3); 292 _InvalidateSelector(3, c2, IsFocus() && fFocusedRamp == 3); 293 } 294 } 295 296 // Set the value here, since BTextControl will trigger 297 // Window()->UpdateIfNeeded() which will cause us to draw the indicators 298 // at the old offset. 299 if (Value() != value) 300 BControl::SetValueNoUpdate(value); 301 302 // the textcontrols have to be updated even when the color 303 // hasn't changed since the value is clamped upstream 304 // and the textcontrols would still show the unclamped value 305 char string[4]; 306 sprintf(string, "%d", c2.red); 307 fRedText->SetText(string); 308 sprintf(string, "%d", c2.green); 309 fGreenText->SetText(string); 310 sprintf(string, "%d", c2.blue); 311 fBlueText->SetText(string); 312 } 313 314 315 rgb_color 316 BColorControl::ValueAsColor() 317 { 318 int32 value = Value(); 319 rgb_color color; 320 321 color.red = (value & 0xFF000000) >> 24; 322 color.green = (value & 0x00FF0000) >> 16; 323 color.blue = (value & 0x0000FF00) >> 8; 324 color.alpha = 255; 325 326 return color; 327 } 328 329 330 void 331 BColorControl::SetEnabled(bool enabled) 332 { 333 BControl::SetEnabled(enabled); 334 335 fRedText->SetEnabled(enabled); 336 fGreenText->SetEnabled(enabled); 337 fBlueText->SetEnabled(enabled); 338 } 339 340 341 void 342 BColorControl::AttachedToWindow() 343 { 344 if (Parent()) 345 SetViewColor(Parent()->ViewColor()); 346 else 347 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 348 349 BControl::AttachedToWindow(); 350 351 fRedText->SetTarget(this); 352 fGreenText->SetTarget(this); 353 fBlueText->SetTarget(this); 354 355 if (fBitmap) 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 default: 377 BControl::MessageReceived(message); 378 } 379 } 380 381 382 void 383 BColorControl::Draw(BRect updateRect) 384 { 385 if (fBitmap != NULL) 386 DrawBitmap(fBitmap, B_ORIGIN); 387 else 388 _DrawColorArea(this, updateRect); 389 390 _DrawSelectors(this); 391 } 392 393 394 void 395 BColorControl::_DrawColorArea(BView* target, BRect updateRect) 396 { 397 BRect rect = _PaletteFrame(); 398 bool enabled = IsEnabled(); 399 400 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 401 rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT); 402 403 if (be_control_look != NULL) { 404 uint32 flags = be_control_look->Flags(this); 405 be_control_look->DrawTextControlBorder(target, rect, updateRect, 406 base, flags); 407 } else { 408 // first bevel 409 rgb_color lighten1 = tint_color(base, B_LIGHTEN_1_TINT); 410 rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT); 411 target->SetHighColor(enabled ? darken1 : base); 412 413 target->StrokeLine(rect.LeftBottom(), rect.LeftTop()); 414 target->StrokeLine(rect.LeftTop(), rect.RightTop()); 415 target->SetHighColor(enabled ? lightenmax : lighten1); 416 417 target->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), 418 rect.RightBottom()); 419 target->StrokeLine(rect.RightBottom(), 420 BPoint(rect.right, rect.top + 1.0f)); 421 422 rect.InsetBy(1.0f, 1.0f); 423 424 // second bevel 425 rgb_color darken2 = tint_color(base, B_DARKEN_2_TINT); 426 rgb_color darken4 = tint_color(base, B_DARKEN_4_TINT); 427 target->SetHighColor(enabled ? darken4 : darken2); 428 429 target->StrokeLine(rect.LeftBottom(), rect.LeftTop()); 430 target->StrokeLine(rect.LeftTop(), rect.RightTop()); 431 target->SetHighColor(base); 432 target->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), 433 rect.RightBottom()); 434 target->StrokeLine(rect.RightBottom(), 435 BPoint(rect.right, rect.top + 1.0f)); 436 } 437 438 if (fPaletteMode) { 439 int colBegin = max_c(0, -1 + int(updateRect.left) / int(fCellSize)); 440 int colEnd = min_c(fColumns, 441 2 + int(updateRect.right) / int(fCellSize)); 442 int rowBegin = max_c(0, -1 + int(updateRect.top) / int(fCellSize)); 443 int rowEnd = min_c(fRows, 2 + int(updateRect.bottom) 444 / int(fCellSize)); 445 446 // grid 447 target->SetHighColor(enabled ? darken1 : base); 448 449 for (int xi = 0; xi < fColumns + 1; xi++) { 450 float x = fPaletteFrame.left + float(xi) * fCellSize; 451 target->StrokeLine(BPoint(x, fPaletteFrame.top), 452 BPoint(x, fPaletteFrame.bottom)); 453 } 454 for (int yi = 0; yi < fRows + 1; yi++) { 455 float y = fPaletteFrame.top + float(yi) * fCellSize; 456 target->StrokeLine(BPoint(fPaletteFrame.left, y), 457 BPoint(fPaletteFrame.right, y)); 458 } 459 460 // colors 461 for (int col = colBegin; col < colEnd; col++) { 462 for (int row = rowBegin; row < rowEnd; row++) { 463 uint8 colorIndex = row * fColumns + col; 464 float x = fPaletteFrame.left + col * fCellSize; 465 float y = fPaletteFrame.top + row * fCellSize; 466 467 target->SetHighColor(system_colors()->color_list[colorIndex]); 468 target->FillRect(BRect(x + 1, y + 1, 469 x + fCellSize - 1, y + fCellSize - 1)); 470 } 471 } 472 } else { 473 rgb_color white = { 255, 255, 255, 255 }; 474 rgb_color red = { 255, 0, 0, 255 }; 475 rgb_color green = { 0, 255, 0, 255 }; 476 rgb_color blue = { 0, 0, 255, 255 }; 477 478 rgb_color compColor = { 0, 0, 0, 255 }; 479 if (!enabled) { 480 compColor.red = compColor.green = compColor.blue = 156; 481 red.red = green.green = blue.blue = 70; 482 white.red = white.green = white.blue = 70; 483 } 484 _DrawColorRamp(_RampFrame(0), target, white, compColor, 0, false, 485 updateRect); 486 _DrawColorRamp(_RampFrame(1), target, red, compColor, 0, false, 487 updateRect); 488 _DrawColorRamp(_RampFrame(2), target, green, compColor, 0, false, 489 updateRect); 490 _DrawColorRamp(_RampFrame(3), target, blue, compColor, 0, false, 491 updateRect); 492 } 493 } 494 495 496 void 497 BColorControl::_DrawSelectors(BView* target) 498 { 499 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 500 rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT); 501 502 if (fPaletteMode) { 503 if (fSelectedPaletteColorIndex != -1) { 504 target->SetHighColor(lightenmax); 505 target->StrokeRect(_PaletteSelectorFrame(fSelectedPaletteColorIndex)); 506 } 507 } else { 508 rgb_color color = ValueAsColor(); 509 target->SetHighColor(255, 255, 255); 510 511 BPoint center = _SelectorPosition(_RampFrame(1), color.red); 512 if (fFocusedRamp == 1) { 513 target->SetPenSize(kSelectorPenSize / 2); 514 target->StrokeEllipse(center, kSelectorSize, kSelectorSize); 515 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 516 } else { 517 target->SetPenSize(kSelectorPenSize); 518 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 519 } 520 521 center = _SelectorPosition(_RampFrame(2), color.green); 522 if (fFocusedRamp == 2) { 523 target->SetPenSize(kSelectorPenSize / 2); 524 target->StrokeEllipse(center, kSelectorSize, kSelectorSize); 525 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 526 } else { 527 target->SetPenSize(kSelectorPenSize); 528 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 529 } 530 531 532 center = _SelectorPosition(_RampFrame(3), color.blue); 533 if (fFocusedRamp == 3) { 534 target->SetPenSize(kSelectorPenSize / 2); 535 target->StrokeEllipse(center, kSelectorSize, kSelectorSize); 536 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 537 } else { 538 target->SetPenSize(kSelectorPenSize); 539 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2); 540 } 541 542 target->SetPenSize(1.0f); 543 } 544 } 545 546 547 void 548 BColorControl::_DrawColorRamp(BRect rect, BView* target, 549 rgb_color baseColor, rgb_color compColor, int16 flag, bool focused, 550 BRect updateRect) 551 { 552 float width = rect.Width() + 1; 553 rgb_color color; 554 color.alpha = 255; 555 556 updateRect = updateRect & rect; 557 558 if (updateRect.IsValid() && updateRect.Width() >= 0) { 559 target->BeginLineArray((int32)updateRect.Width() + 1); 560 561 for (float i = (updateRect.left - rect.left); 562 i <= (updateRect.right - rect.left) + 1; i++) { 563 color.red = (uint8)(i * baseColor.red / width) + compColor.red; 564 color.green = (uint8)(i * baseColor.green / width) 565 + compColor.green; 566 color.blue = (uint8)(i * baseColor.blue / width) + compColor.blue; 567 target->AddLine(BPoint(rect.left + i, rect.top), 568 BPoint(rect.left + i, rect.bottom - 1), color); 569 } 570 571 target->EndLineArray(); 572 } 573 } 574 575 576 BPoint 577 BColorControl::_SelectorPosition(const BRect& rampRect, uint8 shade) const 578 { 579 float radius = kSelectorSize / 2 + kSelectorPenSize / 2; 580 581 return BPoint(rampRect.left + kSelectorHSpacing + radius + 582 shade * (rampRect.Width() - 2 * (kSelectorHSpacing + radius)) / 255, 583 rampRect.top + rampRect.Height() / 2); 584 } 585 586 587 BRect 588 BColorControl::_PaletteFrame() const 589 { 590 return fPaletteFrame.InsetByCopy(-kBevelSpacing, -kBevelSpacing); 591 } 592 593 594 BRect 595 BColorControl::_RampFrame(uint8 rampIndex) const 596 { 597 float rampHeight = (float)(fRows * fCellSize / kRampCount); 598 599 return BRect(fPaletteFrame.left, 600 fPaletteFrame.top + float(rampIndex) * rampHeight, 601 fPaletteFrame.right, 602 fPaletteFrame.top + float(rampIndex + 1) * rampHeight); 603 } 604 605 606 void 607 BColorControl::_SetCellSize(float size) 608 { 609 BFont font; 610 GetFont(&font); 611 fCellSize = std::max(kMinCellSize, 612 ceilf(size * font.Size() / kDefaultFontSize)); 613 } 614 615 616 float 617 BColorControl::_TextRectOffset() 618 { 619 return std::max(fRedText->Bounds().Height(), 620 ceilf(_PaletteFrame().Height() / 3)); 621 } 622 623 624 BRect 625 BColorControl::_PaletteSelectorFrame(uint8 colorIndex) const 626 { 627 uint32 row = colorIndex / fColumns; 628 uint32 column = colorIndex % fColumns; 629 float x = fPaletteFrame.left + column * fCellSize; 630 float y = fPaletteFrame.top + row * fCellSize; 631 return BRect(x, y, x + fCellSize, y + fCellSize); 632 } 633 634 635 void 636 BColorControl::_InitOffscreen() 637 { 638 if (fBitmap->Lock()) { 639 _DrawColorArea(fOffscreenView, _PaletteFrame()); 640 fOffscreenView->Sync(); 641 fBitmap->Unlock(); 642 } 643 } 644 645 646 void 647 BColorControl::_InvalidateSelector(int16 ramp, rgb_color color, bool focused) 648 { 649 if (fPaletteMode) 650 return; 651 652 if (ramp < 1 || ramp > 3) 653 return; 654 655 float invalidateRadius = focused 656 ? kSelectorSize + kSelectorPenSize / 2 657 : kSelectorSize / 2 + kSelectorPenSize; 658 659 uint8 colorValue = ramp == 1 ? color.red : ramp == 2 ? color.green 660 : color.blue; 661 662 BPoint pos = _SelectorPosition(_RampFrame(ramp), colorValue); 663 Invalidate(BRect(pos.x - invalidateRadius, pos.y - invalidateRadius, 664 pos.x + invalidateRadius, pos.y + invalidateRadius)); 665 } 666 667 668 void 669 BColorControl::SetCellSize(float size) 670 { 671 _SetCellSize(size); 672 ResizeToPreferred(); 673 } 674 675 676 float 677 BColorControl::CellSize() const 678 { 679 return fCellSize; 680 } 681 682 683 void 684 BColorControl::SetLayout(color_control_layout layout) 685 { 686 switch (layout) { 687 case B_CELLS_4x64: 688 fColumns = 4; 689 fRows = 64; 690 break; 691 case B_CELLS_8x32: 692 fColumns = 8; 693 fRows = 32; 694 break; 695 case B_CELLS_16x16: 696 fColumns = 16; 697 fRows = 16; 698 break; 699 case B_CELLS_32x8: 700 fColumns = 32; 701 fRows = 8; 702 break; 703 case B_CELLS_64x4: 704 fColumns = 64; 705 fRows = 4; 706 break; 707 } 708 709 ResizeToPreferred(); 710 Invalidate(); 711 } 712 713 714 color_control_layout 715 BColorControl::Layout() const 716 { 717 if (fColumns == 4 && fRows == 64) 718 return B_CELLS_4x64; 719 if (fColumns == 8 && fRows == 32) 720 return B_CELLS_8x32; 721 if (fColumns == 16 && fRows == 16) 722 return B_CELLS_16x16; 723 if (fColumns == 32 && fRows == 8) 724 return B_CELLS_32x8; 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 new_position) 989 { 990 BControl::FrameMoved(new_position); 991 } 992 993 994 void 995 BColorControl::FrameResized(float new_width, float new_height) 996 { 997 BControl::FrameResized(new_width, new_height); 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 case PERFORM_CODE_MAX_SIZE: 1055 ((perform_data_max_size*)_data)->return_value 1056 = BColorControl::MaxSize(); 1057 return B_OK; 1058 case PERFORM_CODE_PREFERRED_SIZE: 1059 ((perform_data_preferred_size*)_data)->return_value 1060 = BColorControl::PreferredSize(); 1061 return B_OK; 1062 case PERFORM_CODE_LAYOUT_ALIGNMENT: 1063 ((perform_data_layout_alignment*)_data)->return_value 1064 = BColorControl::LayoutAlignment(); 1065 return B_OK; 1066 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 1067 ((perform_data_has_height_for_width*)_data)->return_value 1068 = BColorControl::HasHeightForWidth(); 1069 return B_OK; 1070 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 1071 { 1072 perform_data_get_height_for_width* data 1073 = (perform_data_get_height_for_width*)_data; 1074 BColorControl::GetHeightForWidth(data->width, &data->min, 1075 &data->max, &data->preferred); 1076 return B_OK; 1077 } 1078 case PERFORM_CODE_SET_LAYOUT: 1079 { 1080 perform_data_set_layout* data = (perform_data_set_layout*)_data; 1081 BColorControl::SetLayout(data->layout); 1082 return B_OK; 1083 } 1084 case PERFORM_CODE_LAYOUT_INVALIDATED: 1085 { 1086 perform_data_layout_invalidated* data 1087 = (perform_data_layout_invalidated*)_data; 1088 BColorControl::LayoutInvalidated(data->descendants); 1089 return B_OK; 1090 } 1091 case PERFORM_CODE_DO_LAYOUT: 1092 { 1093 BColorControl::DoLayout(); 1094 return B_OK; 1095 } 1096 case PERFORM_CODE_SET_ICON: 1097 { 1098 perform_data_set_icon* data = (perform_data_set_icon*)_data; 1099 return BColorControl::SetIcon(data->icon, data->flags); 1100 } 1101 } 1102 1103 return BControl::Perform(code, _data); 1104 } 1105 1106 1107 void BColorControl::_ReservedColorControl1() {} 1108 void BColorControl::_ReservedColorControl2() {} 1109 void BColorControl::_ReservedColorControl3() {} 1110 void BColorControl::_ReservedColorControl4() {} 1111 1112 1113 BColorControl & 1114 BColorControl::operator=(const BColorControl &) 1115 { 1116 return *this; 1117 } 1118