1 /* 2 * Copyright 2001-2008, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Axel Dörfler, axeld@pinc-software.de 8 * Alexandre Deckner, alex@zappotek.com 9 * Jérôme Duval 10 */ 11 12 /** BColorControl displays a palette of selectable colors. */ 13 14 #include <ColorControl.h> 15 16 #include <algorithm> 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 21 #include <ControlLook.h> 22 #include <Bitmap.h> 23 #include <TextControl.h> 24 #include <Region.h> 25 #include <Screen.h> 26 #include <SystemCatalog.h> 27 #include <Window.h> 28 29 using BPrivate::gSystemCatalog; 30 31 #include <binary_compatibility/Interface.h> 32 33 34 #undef B_TRANSLATION_CONTEXT 35 #define B_TRANSLATION_CONTEXT "ColorControl" 36 37 static const uint32 kMsgColorEntered = 'ccol'; 38 static const uint32 kMinCellSize = 6; 39 static const float kSelectorPenSize = 2.0f; 40 static const float kSelectorSize = 4.0f; 41 static const float kSelectorHSpacing = 2.0f; 42 static const float kTextFieldsHSpacing = 6.0f; 43 44 BColorControl::BColorControl(BPoint leftTop, color_control_layout layout, 45 float cellSize, const char *name, BMessage *message, 46 bool bufferedDrawing) 47 : BControl(BRect(leftTop, leftTop), name, NULL, message, 48 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE) 49 { 50 _InitData(layout, cellSize, bufferedDrawing, NULL); 51 } 52 53 54 BColorControl::BColorControl(BMessage* archive) 55 : BControl(archive) 56 { 57 int32 layout; 58 float cellSize; 59 bool useOffscreen; 60 61 archive->FindInt32("_layout", &layout); 62 archive->FindFloat("_csize", &cellSize); 63 archive->FindBool("_use_off", &useOffscreen); 64 65 _InitData((color_control_layout)layout, cellSize, useOffscreen, archive); 66 } 67 68 69 BColorControl::~BColorControl() 70 { 71 delete fBitmap; 72 } 73 74 75 void 76 BColorControl::_InitData(color_control_layout layout, float size, 77 bool useOffscreen, BMessage* archive) 78 { 79 fPaletteMode = BScreen(B_MAIN_SCREEN_ID).ColorSpace() == B_CMAP8; 80 //TODO: we don't support workspace and colorspace changing for now 81 // so we take the main_screen colorspace at startup 82 fColumns = layout; 83 fRows = 256 / fColumns; 84 fCellSize = ceil(max_c(kMinCellSize, size)); 85 86 fSelectedPaletteColorIndex = -1; 87 fPreviousSelectedPaletteColorIndex = -1; 88 fFocusedComponent = 0; 89 90 const char* red = B_TRANSLATE_MARK("Red:"); 91 const char* green = B_TRANSLATE_MARK("Green:"); 92 const char* blue = B_TRANSLATE_MARK("Blue:"); 93 red = gSystemCatalog.GetString(red, "ColorControl"); 94 green = gSystemCatalog.GetString(green, "ColorControl"); 95 blue = gSystemCatalog.GetString(blue, "ColorControl"); 96 97 if (archive) { 98 fRedText = (BTextControl*)FindView("_red"); 99 fGreenText = (BTextControl*)FindView("_green"); 100 fBlueText = (BTextControl*)FindView("_blue"); 101 102 int32 value = 0; 103 archive->FindInt32("_val", &value); 104 105 SetValue(value); 106 } else { 107 BRect rect(0.0f, 0.0f, 70.0f, 15.0f); 108 float labelWidth = std::max(StringWidth(red), 109 std::max(StringWidth(green), StringWidth(blue))) + 5; 110 rect.right = labelWidth + StringWidth("999") + 20; 111 112 // red 113 114 fRedText = new BTextControl(rect, "_red", red, "0", 115 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 116 B_WILL_DRAW | B_NAVIGABLE); 117 fRedText->SetDivider(labelWidth); 118 119 float offset = fRedText->Bounds().Height() + 2; 120 121 for (int32 i = 0; i < 256; i++) 122 fRedText->TextView()->DisallowChar(i); 123 for (int32 i = '0'; i <= '9'; i++) 124 fRedText->TextView()->AllowChar(i); 125 fRedText->TextView()->SetMaxBytes(3); 126 127 // green 128 129 rect.OffsetBy(0.0f, offset); 130 fGreenText = new BTextControl(rect, "_green", green, "0", 131 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 132 B_WILL_DRAW | B_NAVIGABLE); 133 fGreenText->SetDivider(labelWidth); 134 135 for (int32 i = 0; i < 256; i++) 136 fGreenText->TextView()->DisallowChar(i); 137 for (int32 i = '0'; i <= '9'; i++) 138 fGreenText->TextView()->AllowChar(i); 139 fGreenText->TextView()->SetMaxBytes(3); 140 141 // blue 142 143 rect.OffsetBy(0.0f, offset); 144 fBlueText = new BTextControl(rect, "_blue", blue, "0", 145 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 146 B_WILL_DRAW | B_NAVIGABLE); 147 fBlueText->SetDivider(labelWidth); 148 149 for (int32 i = 0; i < 256; i++) 150 fBlueText->TextView()->DisallowChar(i); 151 for (int32 i = '0'; i <= '9'; i++) 152 fBlueText->TextView()->AllowChar(i); 153 fBlueText->TextView()->SetMaxBytes(3); 154 155 AddChild(fRedText); 156 AddChild(fGreenText); 157 AddChild(fBlueText); 158 } 159 160 _LayoutView(); 161 162 if (useOffscreen) { 163 BRect bounds = fPaletteFrame; 164 bounds.InsetBy(-2.0f, -2.0f); 165 166 fBitmap = new BBitmap(bounds, B_RGB32, true, false); 167 fOffscreenView = new BView(bounds, "off_view", 0, 0); 168 169 fBitmap->Lock(); 170 fBitmap->AddChild(fOffscreenView); 171 fBitmap->Unlock(); 172 } else { 173 fBitmap = NULL; 174 fOffscreenView = NULL; 175 } 176 } 177 178 179 void 180 BColorControl::_LayoutView() 181 { 182 if (fPaletteMode){ 183 fPaletteFrame.Set(2.0f, 2.0f, 184 float(fColumns) * fCellSize + 2.0, 185 float(fRows) * fCellSize + 2.0); 186 } else { 187 fPaletteFrame.Set(2.0f, 2.0f, 188 float(fColumns) * fCellSize + 2.0, 189 float(fRows) * fCellSize + 2.0 - 1.0); 190 //1 pixel adjust so that the inner space 191 //has exactly rows*cellsize pixels in height 192 } 193 194 BRect rect = fPaletteFrame.InsetByCopy(-2.0,-2.0); //bevel 195 196 if (rect.Height() < fBlueText->Frame().bottom) { 197 // adjust the height to fit 198 rect.bottom = fBlueText->Frame().bottom; 199 } 200 201 float offset = floor(rect.bottom / 4); 202 float y = offset; 203 if (offset < fRedText->Bounds().Height() + 2) { 204 offset = fRedText->Bounds().Height() + 2; 205 y = 0; 206 } 207 208 fRedText->MoveTo(rect.right + kTextFieldsHSpacing, y); 209 210 y += offset; 211 fGreenText->MoveTo(rect.right + kTextFieldsHSpacing, y); 212 213 y += offset; 214 fBlueText->MoveTo(rect.right + kTextFieldsHSpacing, y); 215 216 ResizeTo(rect.Width() + kTextFieldsHSpacing + fRedText->Bounds().Width(), rect.Height()); 217 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 float invalidateRadius = kSelectorSize / 2 + kSelectorPenSize; 283 BPoint p; 284 285 if (c1.red != c2.red) { 286 p = _SelectorPosition(_RampFrame(1), c1.red); 287 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 288 p.x + invalidateRadius, p.y + invalidateRadius)); 289 290 p = _SelectorPosition(_RampFrame(1), c2.red); 291 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 292 p.x + invalidateRadius, p.y + invalidateRadius)); 293 } 294 if (c1.green != c2.green) { 295 p = _SelectorPosition(_RampFrame(2), c1.green); 296 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 297 p.x + invalidateRadius, p.y + invalidateRadius)); 298 299 p = _SelectorPosition(_RampFrame(2), c2.green); 300 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 301 p.x + invalidateRadius, p.y + invalidateRadius)); 302 } 303 if (c1.blue != c2.blue) { 304 p = _SelectorPosition(_RampFrame(3), c1.blue); 305 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 306 p.x + invalidateRadius, p.y + invalidateRadius)); 307 308 p = _SelectorPosition(_RampFrame(3), c2.blue); 309 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 310 p.x + invalidateRadius, p.y + invalidateRadius)); 311 } 312 } 313 314 // Set the value here, since BTextControl will trigger 315 // Window()->UpdateIfNeeded() which will cause us to draw the indicators 316 // at the old offset. 317 if (Value() != value) 318 BControl::SetValueNoUpdate(value); 319 320 // the textcontrols have to be updated even when the color 321 // hasn't changed since the value is clamped upstream 322 // and the textcontrols would still show the unclamped value 323 char string[4]; 324 sprintf(string, "%d", c2.red); 325 fRedText->SetText(string); 326 sprintf(string, "%d", c2.green); 327 fGreenText->SetText(string); 328 sprintf(string, "%d", c2.blue); 329 fBlueText->SetText(string); 330 } 331 332 333 rgb_color 334 BColorControl::ValueAsColor() 335 { 336 int32 value = Value(); 337 rgb_color color; 338 339 color.red = (value & 0xFF000000) >> 24; 340 color.green = (value & 0x00FF0000) >> 16; 341 color.blue = (value & 0x0000FF00) >> 8; 342 color.alpha = 255; 343 344 return color; 345 } 346 347 348 void 349 BColorControl::SetEnabled(bool enabled) 350 { 351 BControl::SetEnabled(enabled); 352 353 fRedText->SetEnabled(enabled); 354 fGreenText->SetEnabled(enabled); 355 fBlueText->SetEnabled(enabled); 356 } 357 358 359 void 360 BColorControl::AttachedToWindow() 361 { 362 if (Parent()) 363 SetViewColor(Parent()->ViewColor()); 364 else 365 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 366 367 BControl::AttachedToWindow(); 368 369 fRedText->SetTarget(this); 370 fGreenText->SetTarget(this); 371 fBlueText->SetTarget(this); 372 373 if (fBitmap) 374 _InitOffscreen(); 375 } 376 377 378 void 379 BColorControl::MessageReceived(BMessage *message) 380 { 381 switch (message->what) { 382 case kMsgColorEntered: 383 { 384 rgb_color color; 385 color.red = min_c(strtol(fRedText->Text(), NULL, 10), 255); 386 color.green = min_c(strtol(fGreenText->Text(), NULL, 10), 255); 387 color.blue = min_c(strtol(fBlueText->Text(), NULL, 10), 255); 388 color.alpha = 255; 389 390 SetValue(color); 391 Invoke(); 392 break; 393 } 394 default: 395 BControl::MessageReceived(message); 396 } 397 } 398 399 400 void 401 BColorControl::Draw(BRect updateRect) 402 { 403 if (fBitmap) 404 DrawBitmap(fBitmap, B_ORIGIN); 405 else 406 _DrawColorArea(this, updateRect); 407 _DrawSelectors(this); 408 } 409 410 411 void 412 BColorControl::_DrawColorArea(BView* target, BRect update) 413 { 414 BRect bevelRect = fPaletteFrame.InsetByCopy(-2.0,-2.0); //bevel 415 bool enabled = IsEnabled(); 416 417 rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR); 418 rgb_color darken1 = tint_color(noTint, B_DARKEN_1_TINT); 419 420 if (be_control_look != NULL) { 421 uint32 flags = 0; 422 if (!enabled) 423 flags |= BControlLook::B_DISABLED; 424 be_control_look->DrawTextControlBorder(target, bevelRect, update, 425 noTint, flags); 426 } else { 427 rgb_color lighten1 = tint_color(noTint, B_LIGHTEN_1_TINT); 428 rgb_color lightenmax = tint_color(noTint, B_LIGHTEN_MAX_TINT); 429 rgb_color darken2 = tint_color(noTint, B_DARKEN_2_TINT); 430 rgb_color darken4 = tint_color(noTint, B_DARKEN_4_TINT); 431 432 // First bevel 433 if (enabled) 434 target->SetHighColor(darken1); 435 else 436 target->SetHighColor(noTint); 437 target->StrokeLine(bevelRect.LeftBottom(), bevelRect.LeftTop()); 438 target->StrokeLine(bevelRect.LeftTop(), bevelRect.RightTop()); 439 if (enabled) 440 target->SetHighColor(lightenmax); 441 else 442 target->SetHighColor(lighten1); 443 target->StrokeLine(BPoint(bevelRect.left + 1.0f, bevelRect.bottom), 444 bevelRect.RightBottom()); 445 target->StrokeLine(bevelRect.RightBottom(), 446 BPoint(bevelRect.right, bevelRect.top + 1.0f)); 447 448 bevelRect.InsetBy(1.0f, 1.0f); 449 450 // Second bevel 451 if (enabled) 452 target->SetHighColor(darken4); 453 else 454 target->SetHighColor(darken2); 455 target->StrokeLine(bevelRect.LeftBottom(), bevelRect.LeftTop()); 456 target->StrokeLine(bevelRect.LeftTop(), bevelRect.RightTop()); 457 target->SetHighColor(noTint); 458 target->StrokeLine(BPoint(bevelRect.left + 1.0f, bevelRect.bottom), 459 bevelRect.RightBottom()); 460 target->StrokeLine(bevelRect.RightBottom(), 461 BPoint(bevelRect.right, bevelRect.top + 1.0f)); 462 } 463 464 if (fPaletteMode) { 465 int colBegin = max_c(0, -1 + int(update.left) / int(fCellSize)); 466 int colEnd = min_c(fColumns, 2 + int(update.right) / int(fCellSize)); 467 int rowBegin = max_c(0, -1 + int(update.top) / int(fCellSize)); 468 int rowEnd = min_c(fRows, 2 + int(update.bottom) / int(fCellSize)); 469 470 //grid 471 if (enabled) 472 target->SetHighColor(darken1); 473 else 474 target->SetHighColor(noTint); 475 for (int xi = 0; xi < fColumns+1; xi++) { 476 float x = fPaletteFrame.left + float(xi) * fCellSize; 477 target->StrokeLine(BPoint(x, fPaletteFrame.top), BPoint(x, fPaletteFrame.bottom)); 478 } 479 for (int yi = 0; yi < fRows+1; yi++) { 480 float y = fPaletteFrame.top + float(yi) * fCellSize; 481 target->StrokeLine(BPoint(fPaletteFrame.left, y), BPoint(fPaletteFrame.right, y)); 482 } 483 484 //colors 485 for (int col = colBegin; col < colEnd; col++) { 486 for (int row = rowBegin; row < rowEnd; row++) { 487 uint8 colorIndex = row * fColumns + col; 488 float x = fPaletteFrame.left + col * fCellSize; 489 float y = fPaletteFrame.top + row * fCellSize; 490 491 target->SetHighColor(system_colors()->color_list[colorIndex]); 492 target->FillRect(BRect(x+1, y+1, x + fCellSize - 1, y + fCellSize - 1)); 493 } 494 } 495 } else { 496 rgb_color white = {255, 255, 255, 255}; 497 rgb_color red = {255, 0, 0, 255}; 498 rgb_color green = {0, 255, 0, 255}; 499 rgb_color blue = {0, 0, 255, 255}; 500 501 rgb_color compColor = {0, 0, 0, 255}; 502 if (!enabled) { 503 compColor.red = compColor.green = compColor.blue = 156; 504 red.red = green.green = blue.blue = 70; 505 white.red = white.green = white.blue = 70; 506 } 507 _ColorRamp(_RampFrame(0), target, white, compColor, 0, false, update); 508 _ColorRamp(_RampFrame(1), target, red, compColor, 0, false, update); 509 _ColorRamp(_RampFrame(2), target, green, compColor, 0, false, update); 510 _ColorRamp(_RampFrame(3), target, blue, compColor, 0, false, update); 511 } 512 } 513 514 515 void 516 BColorControl::_DrawSelectors(BView* target) 517 { 518 rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR); 519 rgb_color lightenmax = tint_color(noTint, B_LIGHTEN_MAX_TINT); 520 521 if (fPaletteMode) { 522 if (fSelectedPaletteColorIndex != -1) { 523 target->SetHighColor(lightenmax); 524 target->StrokeRect(_PaletteSelectorFrame(fSelectedPaletteColorIndex)); 525 } 526 } else { 527 rgb_color color = ValueAsColor(); 528 target->SetPenSize(kSelectorPenSize); 529 target->SetHighColor(255, 255, 255); 530 531 target->StrokeEllipse(_SelectorPosition(_RampFrame(1), color.red), 532 kSelectorSize / 2, kSelectorSize / 2); 533 target->StrokeEllipse(_SelectorPosition(_RampFrame(2), color.green), 534 kSelectorSize / 2, kSelectorSize / 2); 535 target->StrokeEllipse(_SelectorPosition(_RampFrame(3), color.blue), 536 kSelectorSize / 2, kSelectorSize / 2); 537 538 target->SetPenSize(1.0f); 539 } 540 } 541 542 543 void 544 BColorControl::_ColorRamp(BRect rect, BView* target, 545 rgb_color baseColor, rgb_color compColor, int16 flag, bool focused, BRect update) 546 { 547 float width = rect.Width() + 1; 548 rgb_color color; 549 color.alpha = 255; 550 551 update = update & rect; 552 553 if (update.IsValid() && update.Width() >= 0){ 554 target->BeginLineArray((int32)update.Width() + 1); 555 556 for (float i = (update.left - rect.left); i <= (update.right - rect.left) + 1; i++) { 557 color.red = (uint8)(i * baseColor.red / width) + compColor.red; 558 color.green = (uint8)(i * baseColor.green / width) + compColor.green; 559 color.blue = (uint8)(i * baseColor.blue / width) + compColor.blue; 560 target->AddLine(BPoint(rect.left + i, rect.top), 561 BPoint(rect.left + i, rect.bottom - 1), color); 562 } 563 564 target->EndLineArray(); 565 } 566 } 567 568 569 BPoint 570 BColorControl::_SelectorPosition(const BRect& rampRect, uint8 shade) const 571 { 572 float radius = kSelectorSize / 2 + kSelectorPenSize / 2; 573 574 return BPoint(rampRect.left + kSelectorHSpacing + radius + 575 shade * (rampRect.Width() - 2 * (kSelectorHSpacing + radius)) / 255, 576 rampRect.top + rampRect.Height() / 2); 577 } 578 579 580 BRect 581 BColorControl::_RampFrame(uint8 rampIndex) const 582 { 583 float rampHeight = float(fRows) * fCellSize / 4.0f; 584 585 return BRect( fPaletteFrame.left, 586 fPaletteFrame.top + float(rampIndex) * rampHeight, 587 fPaletteFrame.right, 588 fPaletteFrame.top + float(rampIndex + 1) * rampHeight); 589 } 590 591 592 BRect 593 BColorControl::_PaletteSelectorFrame(uint8 colorIndex) const 594 { 595 uint32 row = colorIndex / fColumns; 596 uint32 column = colorIndex % fColumns; 597 float x = fPaletteFrame.left + column * fCellSize; 598 float y = fPaletteFrame.top + row * fCellSize; 599 return BRect(x, y, x + fCellSize, y + fCellSize); 600 } 601 602 603 void 604 BColorControl::_InitOffscreen() 605 { 606 if (fBitmap->Lock()) { 607 _DrawColorArea(fOffscreenView, fPaletteFrame.InsetByCopy(-2.0f,-2.0f)); 608 fOffscreenView->Sync(); 609 fBitmap->Unlock(); 610 } 611 } 612 613 614 void 615 BColorControl::SetCellSize(float cellSide) 616 { 617 fCellSize = ceil(max_c(kMinCellSize, cellSide)); 618 _LayoutView(); 619 ResizeToPreferred(); 620 } 621 622 623 float 624 BColorControl::CellSize() const 625 { 626 return fCellSize; 627 } 628 629 630 void 631 BColorControl::SetLayout(color_control_layout layout) 632 { 633 switch (layout) { 634 case B_CELLS_4x64: 635 fColumns = 4; 636 fRows = 64; 637 break; 638 case B_CELLS_8x32: 639 fColumns = 8; 640 fRows = 32; 641 break; 642 case B_CELLS_16x16: 643 fColumns = 16; 644 fRows = 16; 645 break; 646 case B_CELLS_32x8: 647 fColumns = 32; 648 fRows = 8; 649 break; 650 case B_CELLS_64x4: 651 fColumns = 64; 652 fRows = 4; 653 break; 654 } 655 656 _LayoutView(); 657 658 ResizeToPreferred(); 659 Invalidate(); 660 } 661 662 663 color_control_layout 664 BColorControl::Layout() const 665 { 666 if (fColumns == 4 && fRows == 64) 667 return B_CELLS_4x64; 668 if (fColumns == 8 && fRows == 32) 669 return B_CELLS_8x32; 670 if (fColumns == 16 && fRows == 16) 671 return B_CELLS_16x16; 672 if (fColumns == 32 && fRows == 8) 673 return B_CELLS_32x8; 674 if (fColumns == 64 && fRows == 4) 675 return B_CELLS_64x4; 676 677 return B_CELLS_32x8; 678 } 679 680 681 void 682 BColorControl::WindowActivated(bool state) 683 { 684 BControl::WindowActivated(state); 685 } 686 687 688 void 689 BColorControl::KeyDown(const char* bytes, int32 numBytes) 690 { 691 // TODO: make this keyboard navigable! 692 BControl::KeyDown(bytes, numBytes); 693 } 694 695 696 void 697 BColorControl::MouseUp(BPoint point) 698 { 699 fFocusedComponent = 0; 700 SetTracking(false); 701 } 702 703 704 void 705 BColorControl::MouseDown(BPoint point) 706 { 707 if (!IsEnabled()) 708 return; 709 if (!fPaletteFrame.Contains(point)) 710 return; 711 712 MakeFocus(); 713 714 if (fPaletteMode) { 715 int column = (int) ( (point.x - fPaletteFrame.left) / fCellSize ); 716 int row = (int) ( (point.y - fPaletteFrame.top) / fCellSize ); 717 int colorIndex = row * fColumns + column; 718 if (colorIndex >= 0 && colorIndex < 256) { 719 fSelectedPaletteColorIndex = colorIndex; 720 SetValue(system_colors()->color_list[colorIndex]); 721 } 722 } else { 723 rgb_color color = ValueAsColor(); 724 725 uint8 shade = (unsigned char)max_c(0, 726 min_c((point.x - _RampFrame(0).left) * 255 / _RampFrame(0).Width(), 727 255)); 728 729 if (_RampFrame(0).Contains(point)) { 730 color.red = color.green = color.blue = shade; 731 fFocusedComponent = 1; 732 } else if (_RampFrame(1).Contains(point)) { 733 color.red = shade; 734 fFocusedComponent = 2; 735 } else if (_RampFrame(2).Contains(point)) { 736 color.green = shade; 737 fFocusedComponent = 3; 738 } else if (_RampFrame(3).Contains(point)){ 739 color.blue = shade; 740 fFocusedComponent = 4; 741 } 742 743 SetValue(color); 744 745 } 746 747 Invoke(); 748 749 SetTracking(true); 750 SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY|B_LOCK_WINDOW_FOCUS); 751 } 752 753 754 void 755 BColorControl::MouseMoved(BPoint point, uint32 transit, 756 const BMessage *message) 757 { 758 if (!IsTracking()) 759 return; 760 761 if (fPaletteMode && fPaletteFrame.Contains(point)) { 762 int column = (int) ( (point.x - fPaletteFrame.left) / fCellSize ); 763 int row = (int) ( (point.y - fPaletteFrame.top) / fCellSize ); 764 int colorIndex = row * fColumns + column; 765 if (colorIndex >= 0 && colorIndex < 256) { 766 fSelectedPaletteColorIndex = colorIndex; 767 SetValue(system_colors()->color_list[colorIndex]); 768 } 769 } else { 770 if (fFocusedComponent == 0) 771 return; 772 773 rgb_color color = ValueAsColor(); 774 775 uint8 shade = (unsigned char)max_c(0, 776 min_c((point.x - _RampFrame(0).left) * 255 / _RampFrame(0).Width(), 255)); 777 778 switch (fFocusedComponent) { 779 case 1: 780 color.red = color.green = color.blue = shade; 781 break; 782 case 2: 783 color.red = shade; 784 break; 785 case 3: 786 color.green = shade; 787 break; 788 case 4: 789 color.blue = shade; 790 break; 791 default: 792 break; 793 } 794 795 SetValue(color); 796 } 797 798 Invoke(); 799 } 800 801 802 void 803 BColorControl::DetachedFromWindow() 804 { 805 BControl::DetachedFromWindow(); 806 } 807 808 809 void 810 BColorControl::GetPreferredSize(float *_width, float *_height) 811 { 812 BRect rect = fPaletteFrame.InsetByCopy(-2.0,-2.0); //bevel 813 814 if (rect.Height() < fBlueText->Frame().bottom) { 815 // adjust the height to fit 816 rect.bottom = fBlueText->Frame().bottom; 817 } 818 819 if (_width) 820 *_width = rect.Width() + kTextFieldsHSpacing + fRedText->Bounds().Width(); 821 822 if (_height) 823 *_height = rect.Height(); 824 } 825 826 827 void 828 BColorControl::ResizeToPreferred() 829 { 830 BControl::ResizeToPreferred(); 831 832 _LayoutView(); 833 } 834 835 836 status_t 837 BColorControl::Invoke(BMessage *msg) 838 { 839 return BControl::Invoke(msg); 840 } 841 842 843 void 844 BColorControl::FrameMoved(BPoint new_position) 845 { 846 BControl::FrameMoved(new_position); 847 } 848 849 850 void 851 BColorControl::FrameResized(float new_width, float new_height) 852 { 853 BControl::FrameResized(new_width, new_height); 854 } 855 856 857 BHandler * 858 BColorControl::ResolveSpecifier(BMessage *msg, int32 index, 859 BMessage *specifier, int32 form, const char *property) 860 { 861 return BControl::ResolveSpecifier(msg, index, specifier, form, property); 862 } 863 864 865 status_t 866 BColorControl::GetSupportedSuites(BMessage *data) 867 { 868 return BControl::GetSupportedSuites(data); 869 } 870 871 872 void 873 BColorControl::MakeFocus(bool state) 874 { 875 BControl::MakeFocus(state); 876 } 877 878 879 void 880 BColorControl::AllAttached() 881 { 882 BControl::AllAttached(); 883 } 884 885 886 void 887 BColorControl::AllDetached() 888 { 889 BControl::AllDetached(); 890 } 891 892 893 status_t 894 BColorControl::Perform(perform_code code, void* _data) 895 { 896 switch (code) { 897 case PERFORM_CODE_MIN_SIZE: 898 ((perform_data_min_size*)_data)->return_value 899 = BColorControl::MinSize(); 900 return B_OK; 901 case PERFORM_CODE_MAX_SIZE: 902 ((perform_data_max_size*)_data)->return_value 903 = BColorControl::MaxSize(); 904 return B_OK; 905 case PERFORM_CODE_PREFERRED_SIZE: 906 ((perform_data_preferred_size*)_data)->return_value 907 = BColorControl::PreferredSize(); 908 return B_OK; 909 case PERFORM_CODE_LAYOUT_ALIGNMENT: 910 ((perform_data_layout_alignment*)_data)->return_value 911 = BColorControl::LayoutAlignment(); 912 return B_OK; 913 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 914 ((perform_data_has_height_for_width*)_data)->return_value 915 = BColorControl::HasHeightForWidth(); 916 return B_OK; 917 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 918 { 919 perform_data_get_height_for_width* data 920 = (perform_data_get_height_for_width*)_data; 921 BColorControl::GetHeightForWidth(data->width, &data->min, &data->max, 922 &data->preferred); 923 return B_OK; 924 } 925 case PERFORM_CODE_SET_LAYOUT: 926 { 927 perform_data_set_layout* data = (perform_data_set_layout*)_data; 928 BColorControl::SetLayout(data->layout); 929 return B_OK; 930 } 931 case PERFORM_CODE_LAYOUT_INVALIDATED: 932 { 933 perform_data_layout_invalidated* data 934 = (perform_data_layout_invalidated*)_data; 935 BColorControl::LayoutInvalidated(data->descendants); 936 return B_OK; 937 } 938 case PERFORM_CODE_DO_LAYOUT: 939 { 940 BColorControl::DoLayout(); 941 return B_OK; 942 } 943 } 944 945 return BControl::Perform(code, _data); 946 } 947 948 949 void BColorControl::_ReservedColorControl1() {} 950 void BColorControl::_ReservedColorControl2() {} 951 void BColorControl::_ReservedColorControl3() {} 952 void BColorControl::_ReservedColorControl4() {} 953 954 955 BColorControl & 956 BColorControl::operator=(const BColorControl &) 957 { 958 return *this; 959 } 960