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 <stdio.h> 17 #include <stdlib.h> 18 19 #include <ControlLook.h> 20 #include <Bitmap.h> 21 #include <TextControl.h> 22 #include <Region.h> 23 #include <Screen.h> 24 #include <Window.h> 25 26 #include <binary_compatibility/Interface.h> 27 28 29 static const uint32 kMsgColorEntered = 'ccol'; 30 static const uint32 kMinCellSize = 6; 31 static const float kSelectorPenSize = 2.0f; 32 static const float kSelectorSize = 4.0f; 33 static const float kSelectorHSpacing = 2.0f; 34 static const float kTextFieldsHSpacing = 6.0f; 35 36 BColorControl::BColorControl(BPoint leftTop, color_control_layout layout, 37 float cellSize, const char *name, BMessage *message, 38 bool bufferedDrawing) 39 : BControl(BRect(leftTop, leftTop), name, NULL, message, 40 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE) 41 { 42 _InitData(layout, cellSize, bufferedDrawing, NULL); 43 } 44 45 46 BColorControl::BColorControl(BMessage* archive) 47 : BControl(archive) 48 { 49 int32 layout; 50 float cellSize; 51 bool useOffscreen; 52 53 archive->FindInt32("_layout", &layout); 54 archive->FindFloat("_csize", &cellSize); 55 archive->FindBool("_use_off", &useOffscreen); 56 57 _InitData((color_control_layout)layout, cellSize, useOffscreen, archive); 58 } 59 60 61 BColorControl::~BColorControl() 62 { 63 delete fBitmap; 64 } 65 66 67 void 68 BColorControl::_InitData(color_control_layout layout, float size, 69 bool useOffscreen, BMessage* archive) 70 { 71 fPaletteMode = BScreen(B_MAIN_SCREEN_ID).ColorSpace() == B_CMAP8; 72 //TODO: we don't support workspace and colorspace changing for now 73 // so we take the main_screen colorspace at startup 74 fColumns = layout; 75 fRows = 256 / fColumns; 76 fCellSize = ceil(max_c(kMinCellSize, size)); 77 78 fSelectedPaletteColorIndex = -1; 79 fPreviousSelectedPaletteColorIndex = -1; 80 fFocusedComponent = 0; 81 82 if (archive) { 83 fRedText = (BTextControl*)FindView("_red"); 84 fGreenText = (BTextControl*)FindView("_green"); 85 fBlueText = (BTextControl*)FindView("_blue"); 86 87 int32 value = 0; 88 archive->FindInt32("_val", &value); 89 90 SetValue(value); 91 } else { 92 BRect rect(0.0f, 0.0f, 70.0f, 15.0f); 93 float labelWidth = StringWidth("Green:") + 5; 94 rect.right = labelWidth + StringWidth("999") + 20; 95 96 // red 97 98 fRedText = new BTextControl(rect, "_red", "Red:", "0", 99 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 100 B_WILL_DRAW | B_NAVIGABLE); 101 fRedText->SetDivider(labelWidth); 102 103 float offset = fRedText->Bounds().Height() + 2; 104 105 for (int32 i = 0; i < 256; i++) 106 fRedText->TextView()->DisallowChar(i); 107 for (int32 i = '0'; i <= '9'; i++) 108 fRedText->TextView()->AllowChar(i); 109 fRedText->TextView()->SetMaxBytes(3); 110 111 // green 112 113 rect.OffsetBy(0.0f, offset); 114 fGreenText = new BTextControl(rect, "_green", "Green:", "0", 115 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 116 B_WILL_DRAW | B_NAVIGABLE); 117 fGreenText->SetDivider(labelWidth); 118 119 for (int32 i = 0; i < 256; i++) 120 fGreenText->TextView()->DisallowChar(i); 121 for (int32 i = '0'; i <= '9'; i++) 122 fGreenText->TextView()->AllowChar(i); 123 fGreenText->TextView()->SetMaxBytes(3); 124 125 // blue 126 127 rect.OffsetBy(0.0f, offset); 128 fBlueText = new BTextControl(rect, "_blue", "Blue:", "0", 129 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP, 130 B_WILL_DRAW | B_NAVIGABLE); 131 fBlueText->SetDivider(labelWidth); 132 133 for (int32 i = 0; i < 256; i++) 134 fBlueText->TextView()->DisallowChar(i); 135 for (int32 i = '0'; i <= '9'; i++) 136 fBlueText->TextView()->AllowChar(i); 137 fBlueText->TextView()->SetMaxBytes(3); 138 139 AddChild(fRedText); 140 AddChild(fGreenText); 141 AddChild(fBlueText); 142 } 143 144 _LayoutView(); 145 146 if (useOffscreen) { 147 BRect bounds = fPaletteFrame; 148 bounds.InsetBy(-2.0f, -2.0f); 149 150 fBitmap = new BBitmap(bounds, B_RGB32, true, false); 151 fOffscreenView = new BView(bounds, "off_view", 0, 0); 152 153 fBitmap->Lock(); 154 fBitmap->AddChild(fOffscreenView); 155 fBitmap->Unlock(); 156 } else { 157 fBitmap = NULL; 158 fOffscreenView = NULL; 159 } 160 } 161 162 163 void 164 BColorControl::_LayoutView() 165 { 166 if (fPaletteMode){ 167 fPaletteFrame.Set(2.0f, 2.0f, 168 float(fColumns) * fCellSize + 2.0, 169 float(fRows) * fCellSize + 2.0); 170 } else { 171 fPaletteFrame.Set(2.0f, 2.0f, 172 float(fColumns) * fCellSize + 2.0, 173 float(fRows) * fCellSize + 2.0 - 1.0); 174 //1 pixel adjust so that the inner space 175 //has exactly rows*cellsize pixels in height 176 } 177 178 BRect rect = fPaletteFrame.InsetByCopy(-2.0,-2.0); //bevel 179 180 if (rect.Height() < fBlueText->Frame().bottom) { 181 // adjust the height to fit 182 rect.bottom = fBlueText->Frame().bottom; 183 } 184 185 float offset = floor(rect.bottom / 4); 186 float y = offset; 187 if (offset < fRedText->Bounds().Height() + 2) { 188 offset = fRedText->Bounds().Height() + 2; 189 y = 0; 190 } 191 192 fRedText->MoveTo(rect.right + kTextFieldsHSpacing, y); 193 194 y += offset; 195 fGreenText->MoveTo(rect.right + kTextFieldsHSpacing, y); 196 197 y += offset; 198 fBlueText->MoveTo(rect.right + kTextFieldsHSpacing, y); 199 200 ResizeTo(rect.Width() + kTextFieldsHSpacing + fRedText->Bounds().Width(), rect.Height()); 201 202 } 203 204 205 BArchivable * 206 BColorControl::Instantiate(BMessage *archive) 207 { 208 if (validate_instantiation(archive, "BColorControl")) 209 return new BColorControl(archive); 210 211 return NULL; 212 } 213 214 215 status_t 216 BColorControl::Archive(BMessage *archive, bool deep) const 217 { 218 status_t status = BControl::Archive(archive, deep); 219 220 if (status == B_OK) 221 status = archive->AddInt32("_layout", Layout()); 222 if (status == B_OK) 223 status = archive->AddFloat("_csize", fCellSize); 224 if (status == B_OK) 225 status = archive->AddBool("_use_off", fOffscreenView != NULL); 226 227 return status; 228 } 229 230 231 void 232 BColorControl::SetLayout(BLayout* layout) 233 { 234 // We need to implement this method, since we have another SetLayout() 235 // method and C++ has this special method hiding "feature". 236 BControl::SetLayout(layout); 237 } 238 239 240 void 241 BColorControl::SetValue(int32 value) 242 { 243 rgb_color c1 = ValueAsColor(); 244 rgb_color c2; 245 c2.red = (value & 0xFF000000) >> 24; 246 c2.green = (value & 0x00FF0000) >> 16; 247 c2.blue = (value & 0x0000FF00) >> 8; 248 c2.alpha = 255; 249 char string[4]; 250 251 if (fPaletteMode) { 252 //workaround when two indexes have the same color 253 rgb_color c = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex); 254 c.alpha = 255; 255 if (fSelectedPaletteColorIndex == -1 || c != c2) { 256 //here SetValue hasn't been called by mouse tracking 257 fSelectedPaletteColorIndex = BScreen(Window()).IndexForColor(c2); 258 } 259 260 c2 = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex); 261 262 Invalidate(_PaletteSelectorFrame(fPreviousSelectedPaletteColorIndex)); 263 Invalidate(_PaletteSelectorFrame(fSelectedPaletteColorIndex)); 264 265 fPreviousSelectedPaletteColorIndex = fSelectedPaletteColorIndex; 266 } else { 267 float invalidateRadius = kSelectorSize/2 + kSelectorPenSize; 268 BPoint p; 269 270 if (c1.red != c2.red) { 271 p = _SelectorPosition(_RampFrame(1), c1.red); 272 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 273 p.x + invalidateRadius, p.y + invalidateRadius)); 274 275 p = _SelectorPosition(_RampFrame(1), c2.red); 276 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 277 p.x + invalidateRadius, p.y + invalidateRadius)); 278 } 279 if (c1.green != c2.green) { 280 p = _SelectorPosition(_RampFrame(2), c1.green); 281 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 282 p.x + invalidateRadius, p.y + invalidateRadius)); 283 284 p = _SelectorPosition(_RampFrame(2), c2.green); 285 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 286 p.x + invalidateRadius, p.y + invalidateRadius)); 287 } 288 if (c1.blue != c2.blue) { 289 p = _SelectorPosition(_RampFrame(3), c1.blue); 290 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 291 p.x + invalidateRadius, p.y + invalidateRadius)); 292 293 p = _SelectorPosition(_RampFrame(3), c2.blue); 294 Invalidate(BRect(p.x - invalidateRadius, p.y - invalidateRadius, 295 p.x + invalidateRadius, p.y + invalidateRadius)); 296 } 297 } 298 299 // the textcontrols have to be updated even when the color 300 // hasn't changed since the value is clamped upstream 301 // and the textcontrols would still show the unclamped value 302 sprintf(string, "%d", c2.red); 303 fRedText->SetText(string); 304 sprintf(string, "%d", c2.green); 305 fGreenText->SetText(string); 306 sprintf(string, "%d", c2.blue); 307 fBlueText->SetText(string); 308 309 if (Value() == value) 310 return; 311 312 BControl::SetValueNoUpdate(value); 313 314 if (LockLooper()) { 315 Window()->UpdateIfNeeded(); 316 UnlockLooper(); 317 } 318 } 319 320 321 rgb_color 322 BColorControl::ValueAsColor() 323 { 324 int32 value = Value(); 325 rgb_color color; 326 327 color.red = (value & 0xFF000000) >> 24; 328 color.green = (value & 0x00FF0000) >> 16; 329 color.blue = (value & 0x0000FF00) >> 8; 330 color.alpha = 255; 331 332 return color; 333 } 334 335 336 void 337 BColorControl::SetEnabled(bool enabled) 338 { 339 BControl::SetEnabled(enabled); 340 341 fRedText->SetEnabled(enabled); 342 fGreenText->SetEnabled(enabled); 343 fBlueText->SetEnabled(enabled); 344 } 345 346 347 void 348 BColorControl::AttachedToWindow() 349 { 350 if (Parent()) 351 SetViewColor(Parent()->ViewColor()); 352 else 353 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 354 355 BControl::AttachedToWindow(); 356 357 fRedText->SetTarget(this); 358 fGreenText->SetTarget(this); 359 fBlueText->SetTarget(this); 360 361 if (fBitmap) 362 _InitOffscreen(); 363 } 364 365 366 void 367 BColorControl::MessageReceived(BMessage *message) 368 { 369 switch (message->what) { 370 case kMsgColorEntered: 371 { 372 rgb_color color; 373 color.red = min_c(strtol(fRedText->Text(), NULL, 10), 255); 374 color.green = min_c(strtol(fGreenText->Text(), NULL, 10), 255); 375 color.blue = min_c(strtol(fBlueText->Text(), NULL, 10), 255); 376 color.alpha = 255; 377 378 SetValue(color); 379 Invoke(); 380 break; 381 } 382 default: 383 BControl::MessageReceived(message); 384 } 385 } 386 387 388 void 389 BColorControl::Draw(BRect updateRect) 390 { 391 if (fBitmap) { 392 if (!fBitmap->Lock()) 393 return; 394 395 if (fOffscreenView->Bounds().Intersects(updateRect)) 396 DrawBitmap(fBitmap, B_ORIGIN); 397 398 fBitmap->Unlock(); 399 _DrawSelectors(this); 400 401 } else { 402 _DrawColorArea(this, updateRect); 403 _DrawSelectors(this); 404 } 405 } 406 407 408 void 409 BColorControl::_DrawColorArea(BView* target, BRect update) 410 { 411 BRegion region(update); 412 target->ConstrainClippingRegion(®ion); 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 target->ConstrainClippingRegion(NULL); 514 } 515 516 517 void 518 BColorControl::_DrawSelectors(BView* target) 519 { 520 rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR); 521 rgb_color lightenmax = tint_color(noTint, B_LIGHTEN_MAX_TINT); 522 523 if (fPaletteMode) { 524 if (fSelectedPaletteColorIndex != -1) { 525 target->SetHighColor(lightenmax); 526 target->StrokeRect(_PaletteSelectorFrame(fSelectedPaletteColorIndex)); 527 } 528 } else { 529 rgb_color color = ValueAsColor(); 530 target->SetPenSize(kSelectorPenSize); 531 target->SetHighColor(255, 255, 255); 532 533 target->StrokeEllipse(_SelectorPosition(_RampFrame(1), color.red), 534 kSelectorSize / 2, kSelectorSize / 2); 535 target->StrokeEllipse(_SelectorPosition(_RampFrame(2), color.green), 536 kSelectorSize / 2, kSelectorSize / 2); 537 target->StrokeEllipse(_SelectorPosition(_RampFrame(3), color.blue), 538 kSelectorSize / 2, kSelectorSize / 2); 539 540 target->SetPenSize(1.0f); 541 } 542 } 543 544 545 void 546 BColorControl::_ColorRamp(BRect rect, BView* target, 547 rgb_color baseColor, rgb_color compColor, int16 flag, bool focused, BRect update) 548 { 549 float width = rect.Width() + 1; 550 rgb_color color; 551 color.alpha = 255; 552 553 update = update & rect; 554 555 if (update.IsValid() && update.Width() >= 0){ 556 target->BeginLineArray((int32)update.Width() + 1); 557 558 for (float i = (update.left - rect.left); i <= (update.right - rect.left) + 1; i++) { 559 color.red = (uint8)(i * baseColor.red / width) + compColor.red; 560 color.green = (uint8)(i * baseColor.green / width) + compColor.green; 561 color.blue = (uint8)(i * baseColor.blue / width) + compColor.blue; 562 target->AddLine(BPoint(rect.left + i, rect.top), 563 BPoint(rect.left + i, rect.bottom - 1), color); 564 } 565 566 target->EndLineArray(); 567 } 568 } 569 570 571 BPoint 572 BColorControl::_SelectorPosition(const BRect& rampRect, uint8 shade) const 573 { 574 float radius = kSelectorSize / 2 + kSelectorPenSize / 2; 575 576 return BPoint(rampRect.left + kSelectorHSpacing + radius + 577 shade * (rampRect.Width() - 2 * (kSelectorHSpacing + radius)) / 255, 578 rampRect.top + rampRect.Height() / 2); 579 } 580 581 582 BRect 583 BColorControl::_RampFrame(uint8 rampIndex) const 584 { 585 float rampHeight = float(fRows) * fCellSize / 4.0f; 586 587 return BRect( fPaletteFrame.left, 588 fPaletteFrame.top + float(rampIndex) * rampHeight, 589 fPaletteFrame.right, 590 fPaletteFrame.top + float(rampIndex + 1) * rampHeight); 591 } 592 593 594 BRect 595 BColorControl::_PaletteSelectorFrame(uint8 colorIndex) const 596 { 597 uint32 row = colorIndex / fColumns; 598 uint32 column = colorIndex % fColumns; 599 float x = fPaletteFrame.left + column * fCellSize; 600 float y = fPaletteFrame.top + row * fCellSize; 601 return BRect(x, y, x + fCellSize, y + fCellSize); 602 } 603 604 605 void 606 BColorControl::_InitOffscreen() 607 { 608 if (fBitmap->Lock()) { 609 _DrawColorArea(fOffscreenView, fPaletteFrame.InsetByCopy(-2.0f,-2.0f)); 610 fOffscreenView->Sync(); 611 fBitmap->Unlock(); 612 } 613 } 614 615 616 void 617 BColorControl::SetCellSize(float cellSide) 618 { 619 fCellSize = ceil(max_c(kMinCellSize, cellSide)); 620 _LayoutView(); 621 ResizeToPreferred(); 622 } 623 624 625 float 626 BColorControl::CellSize() const 627 { 628 return fCellSize; 629 } 630 631 632 void 633 BColorControl::SetLayout(color_control_layout layout) 634 { 635 switch (layout) { 636 case B_CELLS_4x64: 637 fColumns = 4; 638 fRows = 64; 639 break; 640 case B_CELLS_8x32: 641 fColumns = 8; 642 fRows = 32; 643 break; 644 case B_CELLS_16x16: 645 fColumns = 16; 646 fRows = 16; 647 break; 648 case B_CELLS_32x8: 649 fColumns = 32; 650 fRows = 8; 651 break; 652 case B_CELLS_64x4: 653 fColumns = 64; 654 fRows = 4; 655 break; 656 } 657 658 _LayoutView(); 659 660 ResizeToPreferred(); 661 Invalidate(); 662 } 663 664 665 color_control_layout 666 BColorControl::Layout() const 667 { 668 if (fColumns == 4 && fRows == 64) 669 return B_CELLS_4x64; 670 if (fColumns == 8 && fRows == 32) 671 return B_CELLS_8x32; 672 if (fColumns == 16 && fRows == 16) 673 return B_CELLS_16x16; 674 if (fColumns == 32 && fRows == 8) 675 return B_CELLS_32x8; 676 if (fColumns == 64 && fRows == 4) 677 return B_CELLS_64x4; 678 679 return B_CELLS_32x8; 680 } 681 682 683 void 684 BColorControl::WindowActivated(bool state) 685 { 686 BControl::WindowActivated(state); 687 } 688 689 690 void 691 BColorControl::KeyDown(const char* bytes, int32 numBytes) 692 { 693 // TODO: make this keyboard navigable! 694 BControl::KeyDown(bytes, numBytes); 695 } 696 697 698 void 699 BColorControl::MouseUp(BPoint point) 700 { 701 fFocusedComponent = 0; 702 SetTracking(false); 703 } 704 705 706 void 707 BColorControl::MouseDown(BPoint point) 708 { 709 if (!IsEnabled()) 710 return; 711 if (!fPaletteFrame.Contains(point)) 712 return; 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(), 255)); 727 728 if (_RampFrame(0).Contains(point)) { 729 color.red = color.green = color.blue = shade; 730 fFocusedComponent = 1; 731 } else if (_RampFrame(1).Contains(point)) { 732 color.red = shade; 733 fFocusedComponent = 2; 734 } else if (_RampFrame(2).Contains(point)) { 735 color.green = shade; 736 fFocusedComponent = 3; 737 } else if (_RampFrame(3).Contains(point)){ 738 color.blue = shade; 739 fFocusedComponent = 4; 740 } 741 742 SetValue(color); 743 744 } 745 746 Invoke(); 747 748 SetTracking(true); 749 MakeFocus(); 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_INVALIDATE_LAYOUT: 932 { 933 perform_data_invalidate_layout* data 934 = (perform_data_invalidate_layout*)_data; 935 BColorControl::InvalidateLayout(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