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