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