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