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