vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / ColorControl.cpp
blobae1795734fc2dcf1679211aed3358187bb13e2a1
1 /*
2 * Copyright 2001-2013 Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
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
13 /** BColorControl displays a palette of selectable colors. */
15 #include <ColorControl.h>
17 #include <algorithm>
19 #include <stdio.h>
20 #include <stdlib.h>
22 #include <iostream>
24 #include <ControlLook.h>
25 #include <Bitmap.h>
26 #include <TextControl.h>
27 #include <Region.h>
28 #include <Screen.h>
29 #include <SystemCatalog.h>
30 #include <Window.h>
32 using BPrivate::gSystemCatalog;
34 #include <binary_compatibility/Interface.h>
37 #undef B_TRANSLATION_CONTEXT
38 #define B_TRANSLATION_CONTEXT "ColorControl"
40 static const uint32 kMsgColorEntered = 'ccol';
41 static const float kMinCellSize = 6.0f;
42 static const float kSelectorPenSize = 2.0f;
43 static const float kSelectorSize = 4.0f;
44 static const float kSelectorHSpacing = 2.0f;
45 static const float kTextFieldsHSpacing = 6.0f;
46 static const float kDefaultFontSize = 12.0f;
47 static const float kBevelSpacing = 2.0f;
48 static const uint32 kRampCount = 4;
51 BColorControl::BColorControl(BPoint leftTop, color_control_layout layout,
52 float cellSize, const char* name, BMessage* message, bool useOffscreen)
54 BControl(BRect(leftTop, leftTop), name, NULL, message,
55 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE),
56 fRedText(NULL),
57 fGreenText(NULL),
58 fBlueText(NULL),
59 fOffscreenBitmap(NULL)
61 _InitData(layout, cellSize, useOffscreen, NULL);
65 BColorControl::BColorControl(BMessage* data)
67 BControl(data),
68 fRedText(NULL),
69 fGreenText(NULL),
70 fBlueText(NULL),
71 fOffscreenBitmap(NULL)
73 int32 layout;
74 float cellSize;
75 bool useOffscreen;
77 data->FindInt32("_layout", &layout);
78 data->FindFloat("_csize", &cellSize);
79 data->FindBool("_use_off", &useOffscreen);
81 _InitData((color_control_layout)layout, cellSize, useOffscreen, data);
85 BColorControl::~BColorControl()
87 delete fOffscreenBitmap;
91 void
92 BColorControl::_InitData(color_control_layout layout, float size,
93 bool useOffscreen, BMessage* data)
95 fPaletteMode = BScreen(B_MAIN_SCREEN_ID).ColorSpace() == B_CMAP8;
96 //TODO: we don't support workspace and colorspace changing for now
97 // so we take the main_screen colorspace at startup
98 fColumns = layout;
99 fRows = 256 / fColumns;
101 _SetCellSize(size);
103 fSelectedPaletteColorIndex = -1;
104 fPreviousSelectedPaletteColorIndex = -1;
105 fFocusedRamp = !fPaletteMode && IsFocus() ? 1 : -1;
106 fClickedRamp = -1;
108 const char* red = B_TRANSLATE_MARK("Red:");
109 const char* green = B_TRANSLATE_MARK("Green:");
110 const char* blue = B_TRANSLATE_MARK("Blue:");
111 red = gSystemCatalog.GetString(red, "ColorControl");
112 green = gSystemCatalog.GetString(green, "ColorControl");
113 blue = gSystemCatalog.GetString(blue, "ColorControl");
115 if (data != NULL) {
116 fRedText = (BTextControl*)FindView("_red");
117 fGreenText = (BTextControl*)FindView("_green");
118 fBlueText = (BTextControl*)FindView("_blue");
120 int32 value = 0;
121 data->FindInt32("_val", &value);
123 SetValue(value);
124 } else {
125 BRect textRect(0.0f, 0.0f, 0.0f, 0.0f);
126 float labelWidth = std::max(StringWidth(red),
127 std::max(StringWidth(green), StringWidth(blue)))
128 + kTextFieldsHSpacing;
129 textRect.right = labelWidth + StringWidth("999999");
130 // enough room for 3 digits plus 3 digits of padding
131 font_height fontHeight;
132 GetFontHeight(&fontHeight);
133 float labelHeight = fontHeight.ascent + fontHeight.descent;
134 textRect.bottom = labelHeight;
136 // red
138 fRedText = new BTextControl(textRect, "_red", red, "0",
139 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP,
140 B_WILL_DRAW | B_NAVIGABLE);
141 fRedText->SetDivider(labelWidth);
143 for (int32 i = 0; i < 256; i++)
144 fRedText->TextView()->DisallowChar(i);
145 for (int32 i = '0'; i <= '9'; i++)
146 fRedText->TextView()->AllowChar(i);
147 fRedText->TextView()->SetMaxBytes(3);
149 // green
151 textRect.OffsetBy(0, _TextRectOffset());
152 fGreenText = new BTextControl(textRect, "_green", green, "0",
153 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP,
154 B_WILL_DRAW | B_NAVIGABLE);
155 fGreenText->SetDivider(labelWidth);
157 for (int32 i = 0; i < 256; i++)
158 fGreenText->TextView()->DisallowChar(i);
159 for (int32 i = '0'; i <= '9'; i++)
160 fGreenText->TextView()->AllowChar(i);
161 fGreenText->TextView()->SetMaxBytes(3);
163 // blue
165 textRect.OffsetBy(0, _TextRectOffset());
166 fBlueText = new BTextControl(textRect, "_blue", blue, "0",
167 new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP,
168 B_WILL_DRAW | B_NAVIGABLE);
169 fBlueText->SetDivider(labelWidth);
171 for (int32 i = 0; i < 256; i++)
172 fBlueText->TextView()->DisallowChar(i);
173 for (int32 i = '0'; i <= '9'; i++)
174 fBlueText->TextView()->AllowChar(i);
175 fBlueText->TextView()->SetMaxBytes(3);
177 AddChild(fRedText);
178 AddChild(fGreenText);
179 AddChild(fBlueText);
182 ResizeToPreferred();
184 if (useOffscreen) {
185 if (fOffscreenBitmap != NULL) {
186 BRect bounds = _PaletteFrame();
187 fOffscreenBitmap = new BBitmap(bounds, B_RGB32, true, false);
188 BView* offscreenView = new BView(bounds, "off_view", 0, 0);
190 fOffscreenBitmap->Lock();
191 fOffscreenBitmap->AddChild(offscreenView);
192 fOffscreenBitmap->Unlock();
194 } else {
195 delete fOffscreenBitmap;
196 fOffscreenBitmap = NULL;
201 void
202 BColorControl::_LayoutView()
204 fPaletteFrame.Set(0, 0, fColumns * fCellSize, fRows * fCellSize);
205 fPaletteFrame.OffsetBy(kBevelSpacing, kBevelSpacing);
206 if (!fPaletteMode) {
207 // Reduce the inner space by 1 pixel so that the frame
208 // is exactly rows * cellsize pixels in height
209 fPaletteFrame.bottom -= 1;
212 float rampHeight = (float)(fRows * fCellSize / kRampCount);
213 float offset = _TextRectOffset();
214 float y = 0;
215 if (rampHeight > fRedText->Frame().Height()) {
216 // there is enough room to fit kRampCount labels,
217 // shift text controls down by one ramp
218 offset = rampHeight;
219 y = floorf(offset + (offset - fRedText->Frame().Height()) / 2);
222 BRect rect = _PaletteFrame();
223 fRedText->MoveTo(rect.right + kTextFieldsHSpacing, y);
225 y += offset;
226 fGreenText->MoveTo(rect.right + kTextFieldsHSpacing, y);
228 y += offset;
229 fBlueText->MoveTo(rect.right + kTextFieldsHSpacing, y);
233 BArchivable*
234 BColorControl::Instantiate(BMessage* data)
236 if (validate_instantiation(data, "BColorControl"))
237 return new BColorControl(data);
239 return NULL;
243 status_t
244 BColorControl::Archive(BMessage* data, bool deep) const
246 status_t status = BControl::Archive(data, deep);
248 if (status == B_OK)
249 status = data->AddInt32("_layout", Layout());
251 if (status == B_OK)
252 status = data->AddFloat("_csize", fCellSize);
254 if (status == B_OK)
255 status = data->AddBool("_use_off", fOffscreenBitmap != NULL);
257 return status;
261 void
262 BColorControl::SetLayout(BLayout* layout)
264 // We need to implement this method, since we have another SetLayout()
265 // method and C++ has this special method hiding "feature".
266 BControl::SetLayout(layout);
270 void
271 BColorControl::SetValue(int32 value)
273 rgb_color c1 = ValueAsColor();
274 rgb_color c2;
275 c2.red = (value & 0xFF000000) >> 24;
276 c2.green = (value & 0x00FF0000) >> 16;
277 c2.blue = (value & 0x0000FF00) >> 8;
278 c2.alpha = 255;
280 if (fPaletteMode) {
281 //workaround when two indexes have the same color
282 rgb_color c
283 = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex);
284 c.alpha = 255;
285 if (fSelectedPaletteColorIndex == -1 || c != c2) {
286 //here SetValue hasn't been called by mouse tracking
287 fSelectedPaletteColorIndex = BScreen(Window()).IndexForColor(c2);
290 c2 = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex);
292 Invalidate(_PaletteSelectorFrame(fPreviousSelectedPaletteColorIndex));
293 Invalidate(_PaletteSelectorFrame(fSelectedPaletteColorIndex));
295 fPreviousSelectedPaletteColorIndex = fSelectedPaletteColorIndex;
296 } else if (c1 != c2)
297 Invalidate();
299 // Set the value here, since BTextControl will trigger
300 // Window()->UpdateIfNeeded() which will cause us to draw the indicators
301 // at the old offset.
302 if (Value() != value)
303 BControl::SetValueNoUpdate(value);
305 // the textcontrols have to be updated even when the color
306 // hasn't changed since the value is clamped upstream
307 // and the textcontrols would still show the unclamped value
308 char string[4];
309 sprintf(string, "%d", c2.red);
310 fRedText->SetText(string);
311 sprintf(string, "%d", c2.green);
312 fGreenText->SetText(string);
313 sprintf(string, "%d", c2.blue);
314 fBlueText->SetText(string);
318 rgb_color
319 BColorControl::ValueAsColor()
321 int32 value = Value();
322 rgb_color color;
324 color.red = (value & 0xFF000000) >> 24;
325 color.green = (value & 0x00FF0000) >> 16;
326 color.blue = (value & 0x0000FF00) >> 8;
327 color.alpha = 255;
329 return color;
333 void
334 BColorControl::SetEnabled(bool enabled)
336 BControl::SetEnabled(enabled);
338 fRedText->SetEnabled(enabled);
339 fGreenText->SetEnabled(enabled);
340 fBlueText->SetEnabled(enabled);
344 void
345 BColorControl::AttachedToWindow()
347 BControl::AttachedToWindow();
349 AdoptParentColors();
351 fRedText->SetTarget(this);
352 fGreenText->SetTarget(this);
353 fBlueText->SetTarget(this);
355 if (fOffscreenBitmap != NULL)
356 _InitOffscreen();
360 void
361 BColorControl::MessageReceived(BMessage* message)
363 switch (message->what) {
364 case kMsgColorEntered:
366 rgb_color color;
367 color.red = min_c(strtol(fRedText->Text(), NULL, 10), 255);
368 color.green = min_c(strtol(fGreenText->Text(), NULL, 10), 255);
369 color.blue = min_c(strtol(fBlueText->Text(), NULL, 10), 255);
370 color.alpha = 255;
372 SetValue(color);
373 Invoke();
374 break;
377 case B_SCREEN_CHANGED:
379 BRect frame;
380 uint32 mode;
381 if (message->FindRect("frame", &frame) == B_OK
382 && message->FindInt32("mode", (int32*)&mode) == B_OK) {
383 if ((fPaletteMode && mode == B_CMAP8)
384 || (!fPaletteMode && mode != B_CMAP8)) {
385 // not switching to or from B_CMAP8, break
386 break;
389 // fake an archive message (so we don't rebuild views)
390 BMessage* data = new BMessage();
391 data->AddInt32("_val", Value());
393 // reinititialize
394 bool useOffscreen = fOffscreenBitmap != NULL;
395 _InitData((color_control_layout)fColumns, fCellSize,
396 useOffscreen, data);
397 if (useOffscreen)
398 _InitOffscreen();
400 // cleanup
401 delete data;
403 break;
406 default:
407 BControl::MessageReceived(message);
412 void
413 BColorControl::Draw(BRect updateRect)
415 if (fOffscreenBitmap != NULL)
416 DrawBitmap(fOffscreenBitmap, B_ORIGIN);
417 else
418 _DrawColorArea(this, updateRect);
420 _DrawSelectors(this);
424 void
425 BColorControl::_DrawColorArea(BView* target, BRect updateRect)
427 BRect rect = _PaletteFrame();
428 bool enabled = IsEnabled();
430 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
431 rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT);
433 uint32 flags = be_control_look->Flags(this);
434 be_control_look->DrawTextControlBorder(target, rect, updateRect,
435 base, flags);
437 if (fPaletteMode) {
438 int colBegin = max_c(0, -1 + int(updateRect.left) / int(fCellSize));
439 int colEnd = min_c(fColumns,
440 2 + int(updateRect.right) / int(fCellSize));
441 int rowBegin = max_c(0, -1 + int(updateRect.top) / int(fCellSize));
442 int rowEnd = min_c(fRows, 2 + int(updateRect.bottom)
443 / int(fCellSize));
445 // grid
446 target->SetHighColor(enabled ? darken1 : base);
448 for (int xi = 0; xi < fColumns + 1; xi++) {
449 float x = fPaletteFrame.left + float(xi) * fCellSize;
450 target->StrokeLine(BPoint(x, fPaletteFrame.top),
451 BPoint(x, fPaletteFrame.bottom));
453 for (int yi = 0; yi < fRows + 1; yi++) {
454 float y = fPaletteFrame.top + float(yi) * fCellSize;
455 target->StrokeLine(BPoint(fPaletteFrame.left, y),
456 BPoint(fPaletteFrame.right, y));
459 // colors
460 for (int col = colBegin; col < colEnd; col++) {
461 for (int row = rowBegin; row < rowEnd; row++) {
462 uint8 colorIndex = row * fColumns + col;
463 float x = fPaletteFrame.left + col * fCellSize;
464 float y = fPaletteFrame.top + row * fCellSize;
466 target->SetHighColor(system_colors()->color_list[colorIndex]);
467 target->FillRect(BRect(x + 1, y + 1,
468 x + fCellSize - 1, y + fCellSize - 1));
471 } else {
472 rgb_color white = { 255, 255, 255, 255 };
473 rgb_color red = { 255, 0, 0, 255 };
474 rgb_color green = { 0, 255, 0, 255 };
475 rgb_color blue = { 0, 0, 255, 255 };
477 rgb_color compColor = { 0, 0, 0, 255 };
478 if (!enabled) {
479 compColor.red = compColor.green = compColor.blue = 156;
480 red.red = green.green = blue.blue = 70;
481 white.red = white.green = white.blue = 70;
483 _DrawColorRamp(_RampFrame(0), target, white, compColor, 0, false,
484 updateRect);
485 _DrawColorRamp(_RampFrame(1), target, red, compColor, 0, false,
486 updateRect);
487 _DrawColorRamp(_RampFrame(2), target, green, compColor, 0, false,
488 updateRect);
489 _DrawColorRamp(_RampFrame(3), target, blue, compColor, 0, false,
490 updateRect);
495 void
496 BColorControl::_DrawSelectors(BView* target)
498 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
499 rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
501 if (fPaletteMode) {
502 if (fSelectedPaletteColorIndex != -1) {
503 target->SetHighColor(lightenmax);
504 target->StrokeRect(
505 _PaletteSelectorFrame(fSelectedPaletteColorIndex));
507 } else {
508 rgb_color color = ValueAsColor();
509 target->SetHighColor(255, 255, 255);
510 target->SetLowColor(0, 0, 0);
512 int components[4] = { color.alpha, color.red, color.green, color.blue };
514 for (int i = 1; i < 4; i++) {
515 BPoint center = _SelectorPosition(_RampFrame(i), components[i]);
517 target->SetPenSize(kSelectorPenSize);
518 target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2);
519 target->SetPenSize(kSelectorPenSize / 2);
520 target->StrokeEllipse(center, kSelectorSize, kSelectorSize,
521 B_SOLID_LOW);
522 if (i == fFocusedRamp) {
523 target->StrokeEllipse(center,
524 kSelectorSize / 2, kSelectorSize / 2, B_SOLID_LOW);
528 target->SetPenSize(1.0f);
533 void
534 BColorControl::_DrawColorRamp(BRect rect, BView* target,
535 rgb_color baseColor, rgb_color compColor, int16 flag, bool focused,
536 BRect updateRect)
538 float width = rect.Width() + 1;
539 rgb_color color = ValueAsColor();
540 color.alpha = 255;
542 updateRect = updateRect & rect;
544 if (updateRect.IsValid() && updateRect.Width() >= 0) {
545 target->BeginLineArray((int32)updateRect.Width() + 1);
547 for (float i = (updateRect.left - rect.left);
548 i <= (updateRect.right - rect.left) + 1; i++) {
549 if (baseColor.red == 255)
550 color.red = (uint8)(i * 255 / width) + compColor.red;
551 if (baseColor.green == 255)
552 color.green = (uint8)(i * 255 / width) + compColor.green;
553 if (baseColor.blue == 255)
554 color.blue = (uint8)(i * 255 / width) + compColor.blue;
556 target->AddLine(BPoint(rect.left + i, rect.top),
557 BPoint(rect.left + i, rect.bottom - 1), color);
560 target->EndLineArray();
565 BPoint
566 BColorControl::_SelectorPosition(const BRect& rampRect, uint8 shade) const
568 float radius = kSelectorSize / 2 + kSelectorPenSize / 2;
570 return BPoint(rampRect.left + kSelectorHSpacing + radius +
571 shade * (rampRect.Width() - 2 * (kSelectorHSpacing + radius)) / 255,
572 rampRect.top + rampRect.Height() / 2);
576 BRect
577 BColorControl::_PaletteFrame() const
579 return fPaletteFrame.InsetByCopy(-kBevelSpacing, -kBevelSpacing);
583 BRect
584 BColorControl::_RampFrame(uint8 rampIndex) const
586 float rampHeight = (float)(fRows * fCellSize / kRampCount);
588 return BRect(fPaletteFrame.left,
589 fPaletteFrame.top + float(rampIndex) * rampHeight,
590 fPaletteFrame.right,
591 fPaletteFrame.top + float(rampIndex + 1) * rampHeight);
595 void
596 BColorControl::_SetCellSize(float size)
598 BFont font;
599 GetFont(&font);
600 fCellSize = std::max(kMinCellSize,
601 ceilf(size * font.Size() / kDefaultFontSize));
605 float
606 BColorControl::_TextRectOffset()
608 return std::max(fRedText->Bounds().Height(),
609 ceilf(_PaletteFrame().Height() / 3));
613 BRect
614 BColorControl::_PaletteSelectorFrame(uint8 colorIndex) const
616 uint32 row = colorIndex / fColumns;
617 uint32 column = colorIndex % fColumns;
618 float x = fPaletteFrame.left + column * fCellSize;
619 float y = fPaletteFrame.top + row * fCellSize;
620 return BRect(x, y, x + fCellSize, y + fCellSize);
624 void
625 BColorControl::_InitOffscreen()
627 if (fOffscreenBitmap->Lock()) {
628 BView* offscreenView = fOffscreenBitmap->ChildAt((int32)0);
629 if (offscreenView != NULL) {
630 _DrawColorArea(offscreenView, _PaletteFrame());
631 offscreenView->Sync();
633 fOffscreenBitmap->Unlock();
638 void
639 BColorControl::_InvalidateSelector(int16 ramp, rgb_color color, bool focused)
641 if (fPaletteMode)
642 return;
644 if (ramp < 1 || ramp > 3)
645 return;
647 float invalidateRadius = focused
648 ? kSelectorSize + kSelectorPenSize / 2
649 : kSelectorSize / 2 + kSelectorPenSize;
651 uint8 colorValue = ramp == 1 ? color.red : ramp == 2 ? color.green
652 : color.blue;
654 BPoint pos = _SelectorPosition(_RampFrame(ramp), colorValue);
655 Invalidate(BRect(pos.x - invalidateRadius, pos.y - invalidateRadius,
656 pos.x + invalidateRadius, pos.y + invalidateRadius));
660 void
661 BColorControl::SetCellSize(float size)
663 _SetCellSize(size);
664 ResizeToPreferred();
668 float
669 BColorControl::CellSize() const
671 return fCellSize;
675 void
676 BColorControl::SetLayout(color_control_layout layout)
678 switch (layout) {
679 case B_CELLS_4x64:
680 fColumns = 4;
681 fRows = 64;
682 break;
684 case B_CELLS_8x32:
685 fColumns = 8;
686 fRows = 32;
687 break;
689 case B_CELLS_16x16:
690 fColumns = 16;
691 fRows = 16;
692 break;
694 case B_CELLS_32x8:
695 fColumns = 32;
696 fRows = 8;
697 break;
699 case B_CELLS_64x4:
700 fColumns = 64;
701 fRows = 4;
702 break;
705 ResizeToPreferred();
706 Invalidate();
710 color_control_layout
711 BColorControl::Layout() const
713 if (fColumns == 4 && fRows == 64)
714 return B_CELLS_4x64;
716 if (fColumns == 8 && fRows == 32)
717 return B_CELLS_8x32;
719 if (fColumns == 16 && fRows == 16)
720 return B_CELLS_16x16;
722 if (fColumns == 32 && fRows == 8)
723 return B_CELLS_32x8;
725 if (fColumns == 64 && fRows == 4)
726 return B_CELLS_64x4;
728 return B_CELLS_32x8;
732 void
733 BColorControl::WindowActivated(bool state)
735 BControl::WindowActivated(state);
739 void
740 BColorControl::KeyDown(const char* bytes, int32 numBytes)
742 if (IsFocus() && !fPaletteMode && numBytes == 1) {
743 rgb_color color = ValueAsColor();
745 switch (bytes[0]) {
746 case B_UP_ARROW:
748 int16 oldFocus = fFocusedRamp;
749 fFocusedRamp--;
750 if (fFocusedRamp < 1)
751 fFocusedRamp = 3;
753 _InvalidateSelector(oldFocus, color, true);
754 _InvalidateSelector(fFocusedRamp, color, true);
755 break;
758 case B_DOWN_ARROW:
760 int16 oldFocus = fFocusedRamp;
761 fFocusedRamp++;
762 if (fFocusedRamp > 3)
763 fFocusedRamp = 1;
765 _InvalidateSelector(oldFocus, color, true);
766 _InvalidateSelector(fFocusedRamp, color, true);
767 break;
770 case B_LEFT_ARROW:
772 bool goFaster = false;
773 if (Window() != NULL) {
774 BMessage* message = Window()->CurrentMessage();
775 if (message != NULL && message->what == B_KEY_DOWN) {
776 int32 repeats = 0;
777 if (message->FindInt32("be:key_repeat", &repeats)
778 == B_OK && repeats > 4) {
779 goFaster = true;
784 if (fFocusedRamp == 1) {
785 if (goFaster && color.red >= 5)
786 color.red -= 5;
787 else if (color.red > 0)
788 color.red--;
789 } else if (fFocusedRamp == 2) {
790 if (goFaster && color.green >= 5)
791 color.green -= 5;
792 else if (color.green > 0)
793 color.green--;
794 } else if (fFocusedRamp == 3) {
795 if (goFaster && color.blue >= 5)
796 color.blue -= 5;
797 else if (color.blue > 0)
798 color.blue--;
801 SetValue(color);
802 Invoke();
803 break;
806 case B_RIGHT_ARROW:
808 bool goFaster = false;
809 if (Window() != NULL) {
810 BMessage* message = Window()->CurrentMessage();
811 if (message != NULL && message->what == B_KEY_DOWN) {
812 int32 repeats = 0;
813 if (message->FindInt32("be:key_repeat", &repeats)
814 == B_OK && repeats > 4) {
815 goFaster = true;
820 if (fFocusedRamp == 1) {
821 if (goFaster && color.red <= 250)
822 color.red += 5;
823 else if (color.red < 255)
824 color.red++;
825 } else if (fFocusedRamp == 2) {
826 if (goFaster && color.green <= 250)
827 color.green += 5;
828 else if (color.green < 255)
829 color.green++;
830 } else if (fFocusedRamp == 3) {
831 if (goFaster && color.blue <= 250)
832 color.blue += 5;
833 else if (color.blue < 255)
834 color.blue++;
837 SetValue(color);
838 Invoke();
839 break;
844 BControl::KeyDown(bytes, numBytes);
848 void
849 BColorControl::MouseUp(BPoint point)
851 fClickedRamp = -1;
852 SetTracking(false);
856 void
857 BColorControl::MouseDown(BPoint point)
859 if (!IsEnabled())
860 return;
861 if (!fPaletteFrame.Contains(point))
862 return;
864 if (fPaletteMode) {
865 int col = (int)((point.x - fPaletteFrame.left) / fCellSize);
866 int row = (int)((point.y - fPaletteFrame.top) / fCellSize);
867 int colorIndex = row * fColumns + col;
868 if (colorIndex >= 0 && colorIndex < 256) {
869 fSelectedPaletteColorIndex = colorIndex;
870 SetValue(system_colors()->color_list[colorIndex]);
872 } else {
873 rgb_color color = ValueAsColor();
875 uint8 shade = (unsigned char)max_c(0,
876 min_c((point.x - _RampFrame(0).left) * 255
877 / _RampFrame(0).Width(), 255));
879 if (_RampFrame(0).Contains(point)) {
880 color.red = color.green = color.blue = shade;
881 fClickedRamp = 0;
882 } else if (_RampFrame(1).Contains(point)) {
883 color.red = shade;
884 fClickedRamp = 1;
885 } else if (_RampFrame(2).Contains(point)) {
886 color.green = shade;
887 fClickedRamp = 2;
888 } else if (_RampFrame(3).Contains(point)) {
889 color.blue = shade;
890 fClickedRamp = 3;
893 SetValue(color);
896 Invoke();
898 SetTracking(true);
899 SetMouseEventMask(B_POINTER_EVENTS,
900 B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS);
904 void
905 BColorControl::MouseMoved(BPoint point, uint32 transit,
906 const BMessage* message)
908 if (!IsTracking())
909 return;
911 if (fPaletteMode && fPaletteFrame.Contains(point)) {
912 int col = (int)((point.x - fPaletteFrame.left) / fCellSize);
913 int row = (int)((point.y - fPaletteFrame.top) / fCellSize);
914 int colorIndex = row * fColumns + col;
915 if (colorIndex >= 0 && colorIndex < 256) {
916 fSelectedPaletteColorIndex = colorIndex;
917 SetValue(system_colors()->color_list[colorIndex]);
919 } else {
920 if (fClickedRamp < 0 || fClickedRamp > 3)
921 return;
923 rgb_color color = ValueAsColor();
925 uint8 shade = (unsigned char)max_c(0,
926 min_c((point.x - _RampFrame(0).left) * 255
927 / _RampFrame(0).Width(), 255));
929 if (fClickedRamp == 0)
930 color.red = color.green = color.blue = shade;
931 else if (fClickedRamp == 1)
932 color.red = shade;
933 else if (fClickedRamp == 2)
934 color.green = shade;
935 else if (fClickedRamp == 3)
936 color.blue = shade;
938 SetValue(color);
941 Invoke();
945 void
946 BColorControl::DetachedFromWindow()
948 BControl::DetachedFromWindow();
952 void
953 BColorControl::GetPreferredSize(float* _width, float* _height)
955 BRect rect = _PaletteFrame();
957 if (rect.Height() < fBlueText->Frame().bottom) {
958 // adjust the height to fit
959 rect.bottom = fBlueText->Frame().bottom;
962 if (_width) {
963 *_width = rect.Width() + kTextFieldsHSpacing
964 + fRedText->Bounds().Width();
967 if (_height)
968 *_height = rect.Height();
972 void
973 BColorControl::ResizeToPreferred()
975 _LayoutView();
976 BControl::ResizeToPreferred();
980 status_t
981 BColorControl::Invoke(BMessage* message)
983 return BControl::Invoke(message);
987 void
988 BColorControl::FrameMoved(BPoint newPosition)
990 BControl::FrameMoved(newPosition);
994 void
995 BColorControl::FrameResized(float newWidth, float newHeight)
997 BControl::FrameResized(newWidth, newHeight);
1001 BHandler*
1002 BColorControl::ResolveSpecifier(BMessage* message, int32 index,
1003 BMessage* specifier, int32 form, const char* property)
1005 return BControl::ResolveSpecifier(message, index, specifier, form,
1006 property);
1010 status_t
1011 BColorControl::GetSupportedSuites(BMessage* data)
1013 return BControl::GetSupportedSuites(data);
1017 void
1018 BColorControl::MakeFocus(bool focused)
1020 fFocusedRamp = !fPaletteMode && focused ? 1 : -1;
1021 BControl::MakeFocus(focused);
1025 void
1026 BColorControl::AllAttached()
1028 BControl::AllAttached();
1032 void
1033 BColorControl::AllDetached()
1035 BControl::AllDetached();
1039 status_t
1040 BColorControl::SetIcon(const BBitmap* icon, uint32 flags)
1042 return BControl::SetIcon(icon, flags);
1046 status_t
1047 BColorControl::Perform(perform_code code, void* _data)
1049 switch (code) {
1050 case PERFORM_CODE_MIN_SIZE:
1051 ((perform_data_min_size*)_data)->return_value
1052 = BColorControl::MinSize();
1053 return B_OK;
1055 case PERFORM_CODE_MAX_SIZE:
1056 ((perform_data_max_size*)_data)->return_value
1057 = BColorControl::MaxSize();
1058 return B_OK;
1060 case PERFORM_CODE_PREFERRED_SIZE:
1061 ((perform_data_preferred_size*)_data)->return_value
1062 = BColorControl::PreferredSize();
1063 return B_OK;
1065 case PERFORM_CODE_LAYOUT_ALIGNMENT:
1066 ((perform_data_layout_alignment*)_data)->return_value
1067 = BColorControl::LayoutAlignment();
1068 return B_OK;
1070 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
1071 ((perform_data_has_height_for_width*)_data)->return_value
1072 = BColorControl::HasHeightForWidth();
1073 return B_OK;
1075 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
1077 perform_data_get_height_for_width* data
1078 = (perform_data_get_height_for_width*)_data;
1079 BColorControl::GetHeightForWidth(data->width, &data->min,
1080 &data->max, &data->preferred);
1081 return B_OK;
1084 case PERFORM_CODE_SET_LAYOUT:
1086 perform_data_set_layout* data = (perform_data_set_layout*)_data;
1087 BColorControl::SetLayout(data->layout);
1088 return B_OK;
1091 case PERFORM_CODE_LAYOUT_INVALIDATED:
1093 perform_data_layout_invalidated* data
1094 = (perform_data_layout_invalidated*)_data;
1095 BColorControl::LayoutInvalidated(data->descendants);
1096 return B_OK;
1099 case PERFORM_CODE_DO_LAYOUT:
1101 BColorControl::DoLayout();
1102 return B_OK;
1105 case PERFORM_CODE_SET_ICON:
1107 perform_data_set_icon* data = (perform_data_set_icon*)_data;
1108 return BColorControl::SetIcon(data->icon, data->flags);
1112 return BControl::Perform(code, _data);
1116 void BColorControl::_ReservedColorControl1() {}
1117 void BColorControl::_ReservedColorControl2() {}
1118 void BColorControl::_ReservedColorControl3() {}
1119 void BColorControl::_ReservedColorControl4() {}
1122 BColorControl &
1123 BColorControl::operator=(const BColorControl &)
1125 return *this;