1450f071dSAxel Dörfler/*
20289f920SJohn Scipione * Copyright 2001-2013 Haiku, Inc. All Rights Reserved.
3450f071dSAxel Dörfler * Distributed under the terms of the MIT License.
4450f071dSAxel Dörfler *
5450f071dSAxel Dörfler * Authors:
69c76ea4cSStefano Ceccherini *		Alexandre Deckner, alex@zappotek.com
70289f920SJohn Scipione *		Axel D��rfler, axeld@pinc-software.de
8d2184e65SJérôme Duval *		J��r��me Duval
90289f920SJohn Scipione *		Marc Flerackers, mflerackers@androme.be
100289f920SJohn Scipione *		John Scipione, jscipione@gmail.com
11450f071dSAxel Dörfler */
12450f071dSAxel Dörfler
13450f071dSAxel Dörfler/**	BColorControl displays a palette of selectable colors. */
14450f071dSAxel Dörfler
152f86ba45SStephan Aßmus#include <ColorControl.h>
16450f071dSAxel Dörfler
175608589fSAdrien Destugues#include <algorithm>
185608589fSAdrien Destugues
1953056ca5SMarc Flerackers#include <stdio.h>
2053056ca5SMarc Flerackers#include <stdlib.h>
2153056ca5SMarc Flerackers
2204f88428SAdrien Destugues#include <iostream>
2304f88428SAdrien Destugues
242f86ba45SStephan Aßmus#include <ControlLook.h>
2553056ca5SMarc Flerackers#include <Bitmap.h>
2653056ca5SMarc Flerackers#include <TextControl.h>
27545611c7SStefano Ceccherini#include <Region.h>
2853056ca5SMarc Flerackers#include <Screen.h>
2960f75e90SOliver Tappe#include <SystemCatalog.h>
3053056ca5SMarc Flerackers#include <Window.h>
3153056ca5SMarc Flerackers
3260f75e90SOliver Tappeusing BPrivate::gSystemCatalog;
334343960fSAdrien Destugues
3439fbf550SOliver Tappe#include <binary_compatibility/Interface.h>
3539fbf550SOliver Tappe
3653056ca5SMarc Flerackers
37546208a5SOliver Tappe#undef B_TRANSLATION_CONTEXT
38546208a5SOliver Tappe#define B_TRANSLATION_CONTEXT "ColorControl"
394343960fSAdrien Destugues
4068953d3aSAxel Dörflerstatic const uint32 kMsgColorEntered = 'ccol';
4162fec205SJohn Scipionestatic const float kMinCellSize = 6.0f;
429c76ea4cSStefano Ceccherinistatic const float kSelectorPenSize = 2.0f;
439c76ea4cSStefano Ceccherinistatic const float kSelectorSize = 4.0f;
449c76ea4cSStefano Ceccherinistatic const float kSelectorHSpacing = 2.0f;
459c76ea4cSStefano Ceccherinistatic const float kTextFieldsHSpacing = 6.0f;
4662fec205SJohn Scipionestatic const float kDefaultFontSize = 12.0f;
4762fec205SJohn Scipionestatic const float kBevelSpacing = 2.0f;
48da6c116dSJohn Scipionestatic const uint32 kRampCount = 4;
49450f071dSAxel Dörfler
500289f920SJohn Scipione
519a1d68e4SAxel DörflerBColorControl::BColorControl(BPoint leftTop, color_control_layout layout,
528db20d05SJohn Scipione	float cellSize, const char* name, BMessage* message, bool useOffscreen)
530289f920SJohn Scipione	:
540289f920SJohn Scipione	BControl(BRect(leftTop, leftTop), name, NULL, message,
5576b9d53bSJohn Scipione		B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE),
5676b9d53bSJohn Scipione	fRedText(NULL),
5776b9d53bSJohn Scipione	fGreenText(NULL),
5876b9d53bSJohn Scipione	fBlueText(NULL),
5953f75ce5SJohn Scipione	fOffscreenBitmap(NULL)
6053056ca5SMarc Flerackers{
618db20d05SJohn Scipione	_InitData(layout, cellSize, useOffscreen, NULL);
6253056ca5SMarc Flerackers}
6336c17cdeSAxel Dörfler
6436c17cdeSAxel Dörfler
651f424632SJohn ScipioneBColorControl::BColorControl(BMessage* data)
660289f920SJohn Scipione	:
6776b9d53bSJohn Scipione	BControl(data),
6876b9d53bSJohn Scipione	fRedText(NULL),
6976b9d53bSJohn Scipione	fGreenText(NULL),
7076b9d53bSJohn Scipione	fBlueText(NULL),
7153f75ce5SJohn Scipione	fOffscreenBitmap(NULL)
7253056ca5SMarc Flerackers{
7353056ca5SMarc Flerackers	int32 layout;
749a1d68e4SAxel Dörfler	float cellSize;
759a1d68e4SAxel Dörfler	bool useOffscreen;
7653056ca5SMarc Flerackers
771f424632SJohn Scipione	data->FindInt32("_layout", &layout);
781f424632SJohn Scipione	data->FindFloat("_csize", &cellSize);
791f424632SJohn Scipione	data->FindBool("_use_off", &useOffscreen);
8053056ca5SMarc Flerackers
811f424632SJohn Scipione	_InitData((color_control_layout)layout, cellSize, useOffscreen, data);
8253056ca5SMarc Flerackers}
8336c17cdeSAxel Dörfler
8436c17cdeSAxel Dörfler
8553056ca5SMarc FlerackersBColorControl::~BColorControl()
8653056ca5SMarc Flerackers{
8753f75ce5SJohn Scipione	delete fOffscreenBitmap;
8853056ca5SMarc Flerackers}
8936c17cdeSAxel Dörfler
9036c17cdeSAxel Dörfler
919a1d68e4SAxel Dörflervoid
929a1d68e4SAxel DörflerBColorControl::_InitData(color_control_layout layout, float size,
931f424632SJohn Scipione	bool useOffscreen, BMessage* data)
949a1d68e4SAxel Dörfler{
9568c0d50cSAlexandre Deckner	fPaletteMode = BScreen(B_MAIN_SCREEN_ID).ColorSpace() == B_CMAP8;
9675eb45a7SMatt Madia		//TODO: we don't support workspace and colorspace changing for now
9768c0d50cSAlexandre Deckner		//		so we take the main_screen colorspace at startup
989a1d68e4SAxel Dörfler	fColumns = layout;
999a1d68e4SAxel Dörfler	fRows = 256 / fColumns;
1001186916fSJohn Scipione
1011186916fSJohn Scipione	_SetCellSize(size);
10275eb45a7SMatt Madia
1039c76ea4cSStefano Ceccherini	fSelectedPaletteColorIndex = -1;
1049c76ea4cSStefano Ceccherini	fPreviousSelectedPaletteColorIndex = -1;
10574577830SJohn Scipione	fFocusedRamp = !fPaletteMode && IsFocus() ? 1 : -1;
10674577830SJohn Scipione	fClickedRamp = -1;
1074343960fSAdrien Destugues
10875eb45a7SMatt Madia	const char* red = B_TRANSLATE_MARK("Red:");
10975eb45a7SMatt Madia	const char* green = B_TRANSLATE_MARK("Green:");
11075eb45a7SMatt Madia	const char* blue = B_TRANSLATE_MARK("Blue:");
111eaa5e093SOliver Tappe	red = gSystemCatalog.GetString(red, "ColorControl");
112eaa5e093SOliver Tappe	green = gSystemCatalog.GetString(green, "ColorControl");
113eaa5e093SOliver Tappe	blue = gSystemCatalog.GetString(blue, "ColorControl");
11475eb45a7SMatt Madia
1151f424632SJohn Scipione	if (data != NULL) {
116d5b26be1SJérôme Duval		fRedText = (BTextControl*)FindView("_red");
117d5b26be1SJérôme Duval		fGreenText = (BTextControl*)FindView("_green");
118d5b26be1SJérôme Duval		fBlueText = (BTextControl*)FindView("_blue");
119d5b26be1SJérôme Duval
1209a1d68e4SAxel Dörfler		int32 value = 0;
1211f424632SJohn Scipione		data->FindInt32("_val", &value);
1229a1d68e4SAxel Dörfler
1239a1d68e4SAxel Dörfler		SetValue(value);
1249a1d68e4SAxel Dörfler	} else {
12562fec205SJohn Scipione		BRect textRect(0.0f, 0.0f, 0.0f, 0.0f);
1265608589fSAdrien Destugues		float labelWidth = std::max(StringWidth(red),
12762fec205SJohn Scipione			std::max(StringWidth(green), StringWidth(blue)))
12862fec205SJohn Scipione				+ kTextFieldsHSpacing;
12962fec205SJohn Scipione		textRect.right = labelWidth + StringWidth("999999");
13062fec205SJohn Scipione			// enough room for 3 digits plus 3 digits of padding
13162fec205SJohn Scipione		font_height fontHeight;
13262fec205SJohn Scipione		GetFontHeight(&fontHeight);
13362fec205SJohn Scipione		float labelHeight = fontHeight.ascent + fontHeight.descent;
13462fec205SJohn Scipione		textRect.bottom = labelHeight;
1359a1d68e4SAxel Dörfler
1369a1d68e4SAxel Dörfler		// red
1379a1d68e4SAxel Dörfler
13862fec205SJohn Scipione		fRedText = new BTextControl(textRect, "_red", red, "0",
13968953d3aSAxel Dörfler			new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP,
1409a1d68e4SAxel Dörfler			B_WILL_DRAW | B_NAVIGABLE);
1419a1d68e4SAxel Dörfler		fRedText->SetDivider(labelWidth);
1429a1d68e4SAxel Dörfler
1439a1d68e4SAxel Dörfler		for (int32 i = 0; i < 256; i++)
1449a1d68e4SAxel Dörfler			fRedText->TextView()->DisallowChar(i);
1459a1d68e4SAxel Dörfler		for (int32 i = '0'; i <= '9'; i++)
1469a1d68e4SAxel Dörfler			fRedText->TextView()->AllowChar(i);
1479a1d68e4SAxel Dörfler		fRedText->TextView()->SetMaxBytes(3);
1489a1d68e4SAxel Dörfler
1499a1d68e4SAxel Dörfler		// green
1509a1d68e4SAxel Dörfler
15162fec205SJohn Scipione		textRect.OffsetBy(0, _TextRectOffset());
15262fec205SJohn Scipione		fGreenText = new BTextControl(textRect, "_green", green, "0",
15368953d3aSAxel Dörfler			new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP,
1549a1d68e4SAxel Dörfler			B_WILL_DRAW | B_NAVIGABLE);
1559a1d68e4SAxel Dörfler		fGreenText->SetDivider(labelWidth);
1569a1d68e4SAxel Dörfler
1579a1d68e4SAxel Dörfler		for (int32 i = 0; i < 256; i++)
1589a1d68e4SAxel Dörfler			fGreenText->TextView()->DisallowChar(i);
1599a1d68e4SAxel Dörfler		for (int32 i = '0'; i <= '9'; i++)
1609a1d68e4SAxel Dörfler			fGreenText->TextView()->AllowChar(i);
1619a1d68e4SAxel Dörfler		fGreenText->TextView()->SetMaxBytes(3);
1629a1d68e4SAxel Dörfler
1639a1d68e4SAxel Dörfler		// blue
1649a1d68e4SAxel Dörfler
16562fec205SJohn Scipione		textRect.OffsetBy(0, _TextRectOffset());
16662fec205SJohn Scipione		fBlueText = new BTextControl(textRect, "_blue", blue, "0",
16768953d3aSAxel Dörfler			new BMessage(kMsgColorEntered), B_FOLLOW_LEFT | B_FOLLOW_TOP,
1689a1d68e4SAxel Dörfler			B_WILL_DRAW | B_NAVIGABLE);
1699a1d68e4SAxel Dörfler		fBlueText->SetDivider(labelWidth);
1709a1d68e4SAxel Dörfler
1719a1d68e4SAxel Dörfler		for (int32 i = 0; i < 256; i++)
1729a1d68e4SAxel Dörfler			fBlueText->TextView()->DisallowChar(i);
1739a1d68e4SAxel Dörfler		for (int32 i = '0'; i <= '9'; i++)
1749a1d68e4SAxel Dörfler			fBlueText->TextView()->AllowChar(i);
1759a1d68e4SAxel Dörfler		fBlueText->TextView()->SetMaxBytes(3);
17675eb45a7SMatt Madia
1779a1d68e4SAxel Dörfler		AddChild(fRedText);
1789a1d68e4SAxel Dörfler		AddChild(fGreenText);
1799a1d68e4SAxel Dörfler		AddChild(fBlueText);
1809a1d68e4SAxel Dörfler	}
181545611c7SStefano Ceccherini
182d5432ed6SJohn Scipione	ResizeToPreferred();
18375eb45a7SMatt Madia
184545611c7SStefano Ceccherini	if (useOffscreen) {
18553f75ce5SJohn Scipione		if (fOffscreenBitmap != NULL) {
18676b9d53bSJohn Scipione			BRect bounds = _PaletteFrame();
18753f75ce5SJohn Scipione			fOffscreenBitmap = new BBitmap(bounds, B_RGB32, true, false);
18853f75ce5SJohn Scipione			BView* offscreenView = new BView(bounds, "off_view", 0, 0);
18976b9d53bSJohn Scipione
19053f75ce5SJohn Scipione			fOffscreenBitmap->Lock();
19153f75ce5SJohn Scipione			fOffscreenBitmap->AddChild(offscreenView);
19253f75ce5SJohn Scipione			fOffscreenBitmap->Unlock();
19376b9d53bSJohn Scipione		}
194545611c7SStefano Ceccherini	} else {
19553f75ce5SJohn Scipione		delete fOffscreenBitmap;
19653f75ce5SJohn Scipione		fOffscreenBitmap = NULL;
197545611c7SStefano Ceccherini	}
1989a1d68e4SAxel Dörfler}
1999a1d68e4SAxel Dörfler
2009a1d68e4SAxel Dörfler
2019a1d68e4SAxel Dörflervoid
2029a1d68e4SAxel DörflerBColorControl::_LayoutView()
2039a1d68e4SAxel Dörfler{
20462fec205SJohn Scipione	fPaletteFrame.Set(0, 0, fColumns * fCellSize, fRows * fCellSize);
20562fec205SJohn Scipione	fPaletteFrame.OffsetBy(kBevelSpacing, kBevelSpacing);
20662fec205SJohn Scipione	if (!fPaletteMode) {
20762fec205SJohn Scipione		// Reduce the inner space by 1 pixel so that the frame
20862fec205SJohn Scipione		// is exactly rows * cellsize pixels in height
20962fec205SJohn Scipione		fPaletteFrame.bottom -= 1;
21068c0d50cSAlexandre Deckner	}
21175eb45a7SMatt Madia
2121f0b41baSJohn Scipione	float rampHeight = (float)(fRows * fCellSize / kRampCount);
2131f0b41baSJohn Scipione	float offset = _TextRectOffset();
2141f0b41baSJohn Scipione	float y = 0;
2151f0b41baSJohn Scipione	if (rampHeight > fRedText->Frame().Height()) {
2161f0b41baSJohn Scipione		// there is enough room to fit kRampCount labels,
2171f0b41baSJohn Scipione		// shift text controls down by one ramp
2181f0b41baSJohn Scipione		offset = rampHeight;
2191f0b41baSJohn Scipione		y = floorf(offset + (offset - fRedText->Frame().Height()) / 2);
22075eb45a7SMatt Madia	}
2219a1d68e4SAxel Dörfler
2221f0b41baSJohn Scipione	BRect rect = _PaletteFrame();
2239c76ea4cSStefano Ceccherini	fRedText->MoveTo(rect.right + kTextFieldsHSpacing, y);
2249a1d68e4SAxel Dörfler
2259a1d68e4SAxel Dörfler	y += offset;
2269c76ea4cSStefano Ceccherini	fGreenText->MoveTo(rect.right + kTextFieldsHSpacing, y);
2279a1d68e4SAxel Dörfler
2289a1d68e4SAxel Dörfler	y += offset;
2299c76ea4cSStefano Ceccherini	fBlueText->MoveTo(rect.right + kTextFieldsHSpacing, y);
2309a1d68e4SAxel Dörfler}
2319a1d68e4SAxel Dörfler
2329a1d68e4SAxel Dörfler
2330289f920SJohn ScipioneBArchivable*
2341f424632SJohn ScipioneBColorControl::Instantiate(BMessage* data)
23553056ca5SMarc Flerackers{
2361f424632SJohn Scipione	if (validate_instantiation(data, "BColorControl"))
2371f424632SJohn Scipione		return new BColorControl(data);
23836c17cdeSAxel Dörfler
23936c17cdeSAxel Dörfler	return NULL;
24053056ca5SMarc Flerackers}
24136c17cdeSAxel Dörfler
24236c17cdeSAxel Dörfler
24336c17cdeSAxel Dörflerstatus_t
2441f424632SJohn ScipioneBColorControl::Archive(BMessage* data, bool deep) const
24553056ca5SMarc Flerackers{
2461f424632SJohn Scipione	status_t status = BControl::Archive(data, deep);
24753056ca5SMarc Flerackers
248545611c7SStefano Ceccherini	if (status == B_OK)
2491f424632SJohn Scipione		status = data->AddInt32("_layout", Layout());
2501f424632SJohn Scipione
251545611c7SStefano Ceccherini	if (status == B_OK)
2521f424632SJohn Scipione		status = data->AddFloat("_csize", fCellSize);
2531f424632SJohn Scipione
254545611c7SStefano Ceccherini	if (status == B_OK)
25553f75ce5SJohn Scipione		status = data->AddBool("_use_off", fOffscreenBitmap != NULL);
25653056ca5SMarc Flerackers
257545611c7SStefano Ceccherini	return status;
25853056ca5SMarc Flerackers}
25936c17cdeSAxel Dörfler
26036c17cdeSAxel Dörfler
2619ecf9d1cSIngo Weinholdvoid
2629ecf9d1cSIngo WeinholdBColorControl::SetLayout(BLayout* layout)
2639ecf9d1cSIngo Weinhold{
2649ecf9d1cSIngo Weinhold	// We need to implement this method, since we have another SetLayout()
2659ecf9d1cSIngo Weinhold	// method and C++ has this special method hiding "feature".
2669ecf9d1cSIngo Weinhold	BControl::SetLayout(layout);
2679ecf9d1cSIngo Weinhold}
2689ecf9d1cSIngo Weinhold
2699ecf9d1cSIngo Weinhold
27036c17cdeSAxel Dörflervoid
27126476716SStefano CeccheriniBColorControl::SetValue(int32 value)
27253056ca5SMarc Flerackers{
27353056ca5SMarc Flerackers	rgb_color c1 = ValueAsColor();
27453056ca5SMarc Flerackers	rgb_color c2;
27526476716SStefano Ceccherini	c2.red = (value & 0xFF000000) >> 24;
27626476716SStefano Ceccherini	c2.green = (value & 0x00FF0000) >> 16;
27726476716SStefano Ceccherini	c2.blue = (value & 0x0000FF00) >> 8;
2789c76ea4cSStefano Ceccherini	c2.alpha = 255;
27953056ca5SMarc Flerackers
2809c76ea4cSStefano Ceccherini	if (fPaletteMode) {
2819c76ea4cSStefano Ceccherini		//workaround when two indexes have the same color
2820e3b3f92SJohn Scipione		rgb_color c
2830e3b3f92SJohn Scipione			= BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex);
2849c76ea4cSStefano Ceccherini		c.alpha = 255;
2859c76ea4cSStefano Ceccherini		if (fSelectedPaletteColorIndex == -1 || c != c2) {
2869c76ea4cSStefano Ceccherini				//here SetValue hasn't been called by mouse tracking
2879c76ea4cSStefano Ceccherini			fSelectedPaletteColorIndex = BScreen(Window()).IndexForColor(c2);
288d2184e65SJérôme Duval		}
28975eb45a7SMatt Madia
290d2184e65SJérôme Duval		c2 = BScreen(Window()).ColorForIndex(fSelectedPaletteColorIndex);
29175eb45a7SMatt Madia
2929c76ea4cSStefano Ceccherini		Invalidate(_PaletteSelectorFrame(fPreviousSelectedPaletteColorIndex));
293d2184e65SJérôme Duval		Invalidate(_PaletteSelectorFrame(fSelectedPaletteColorIndex));
29475eb45a7SMatt Madia
29575eb45a7SMatt Madia		fPreviousSelectedPaletteColorIndex = fSelectedPaletteColorIndex;
29604f88428SAdrien Destugues	} else if (c1 != c2)
29704f88428SAdrien Destugues		Invalidate();
2982627bad1SStephan Aßmus
2992627bad1SStephan Aßmus	// Set the value here, since BTextControl will trigger
3002627bad1SStephan Aßmus	// Window()->UpdateIfNeeded() which will cause us to draw the indicators
3012627bad1SStephan Aßmus	// at the old offset.
3022627bad1SStephan Aßmus	if (Value() != value)
3032627bad1SStephan Aßmus		BControl::SetValueNoUpdate(value);
3042627bad1SStephan Aßmus
305e8fa461aSAlexandre Deckner	// the textcontrols have to be updated even when the color
306e8fa461aSAlexandre Deckner	// hasn't changed since the value is clamped upstream
307e8fa461aSAlexandre Deckner	// and the textcontrols would still show the unclamped value
3082627bad1SStephan Aßmus	char string[4];
309e8fa461aSAlexandre Deckner	sprintf(string, "%d", c2.red);
310e8fa461aSAlexandre Deckner	fRedText->SetText(string);
311e8fa461aSAlexandre Deckner	sprintf(string, "%d", c2.green);
312e8fa461aSAlexandre Deckner	fGreenText->SetText(string);
313e8fa461aSAlexandre Deckner	sprintf(string, "%d", c2.blue);
314e8fa461aSAlexandre Deckner	fBlueText->SetText(string);
31553056ca5SMarc Flerackers}
31636c17cdeSAxel Dörfler
31736c17cdeSAxel Dörfler
31836c17cdeSAxel Dörflerrgb_color
31936c17cdeSAxel DörflerBColorControl::ValueAsColor()
32053056ca5SMarc Flerackers{
32153056ca5SMarc Flerackers	int32 value = Value();
32253056ca5SMarc Flerackers	rgb_color color;
32353056ca5SMarc Flerackers
32453056ca5SMarc Flerackers	color.red = (value & 0xFF000000) >> 24;
32553056ca5SMarc Flerackers	color.green = (value & 0x00FF0000) >> 16;
32653056ca5SMarc Flerackers	color.blue = (value & 0x0000FF00) >> 8;
32753056ca5SMarc Flerackers	color.alpha = 255;
32853056ca5SMarc Flerackers
32953056ca5SMarc Flerackers	return color;
33053056ca5SMarc Flerackers}
33136c17cdeSAxel Dörfler
33236c17cdeSAxel Dörfler
33336c17cdeSAxel Dörflervoid
33436c17cdeSAxel DörflerBColorControl::SetEnabled(bool enabled)
33553056ca5SMarc Flerackers{
33653056ca5SMarc Flerackers	BControl::SetEnabled(enabled);
33753056ca5SMarc Flerackers
33853056ca5SMarc Flerackers	fRedText->SetEnabled(enabled);
33953056ca5SMarc Flerackers	fGreenText->SetEnabled(enabled);
34053056ca5SMarc Flerackers	fBlueText->SetEnabled(enabled);
34153056ca5SMarc Flerackers}
34236c17cdeSAxel Dörfler
34336c17cdeSAxel Dörfler
34436c17cdeSAxel Dörflervoid
34536c17cdeSAxel DörflerBColorControl::AttachedToWindow()
34653056ca5SMarc Flerackers{
34753056ca5SMarc Flerackers	BControl::AttachedToWindow();
34853056ca5SMarc Flerackers
3497a96554cSlooncraz	AdoptParentColors();
3507a96554cSlooncraz
35153056ca5SMarc Flerackers	fRedText->SetTarget(this);
35253056ca5SMarc Flerackers	fGreenText->SetTarget(this);
35353056ca5SMarc Flerackers	fBlueText->SetTarget(this);
35475eb45a7SMatt Madia
35553f75ce5SJohn Scipione	if (fOffscreenBitmap != NULL)
35675eb45a7SMatt Madia		_InitOffscreen();
35753056ca5SMarc Flerackers}
35836c17cdeSAxel Dörfler
35936c17cdeSAxel Dörfler
36036c17cdeSAxel Dörflervoid
3610289f920SJohn ScipioneBColorControl::MessageReceived(BMessage* message)
36253056ca5SMarc Flerackers{
36336c17cdeSAxel Dörfler	switch (message->what) {
36468953d3aSAxel Dörfler		case kMsgColorEntered:
36553056ca5SMarc Flerackers		{
36653056ca5SMarc Flerackers			rgb_color color;
367e8fa461aSAlexandre Deckner			color.red = min_c(strtol(fRedText->Text(), NULL, 10), 255);
368e8fa461aSAlexandre Deckner			color.green = min_c(strtol(fGreenText->Text(), NULL, 10), 255);
369e8fa461aSAlexandre Deckner			color.blue = min_c(strtol(fBlueText->Text(), NULL, 10), 255);
370d2184e65SJérôme Duval			color.alpha = 255;
37175eb45a7SMatt Madia
37253056ca5SMarc Flerackers			SetValue(color);
37353056ca5SMarc Flerackers			Invoke();
37453056ca5SMarc Flerackers			break;
37553056ca5SMarc Flerackers		}
37676b9d53bSJohn Scipione
37776b9d53bSJohn Scipione		case B_SCREEN_CHANGED:
37876b9d53bSJohn Scipione		{
37976b9d53bSJohn Scipione			BRect frame;
38076b9d53bSJohn Scipione			uint32 mode;
38176b9d53bSJohn Scipione			if (message->FindRect("frame", &frame) == B_OK
38276b9d53bSJohn Scipione				&& message->FindInt32("mode", (int32*)&mode) == B_OK) {
38376b9d53bSJohn Scipione				if ((fPaletteMode && mode == B_CMAP8)
38476b9d53bSJohn Scipione					|| (!fPaletteMode && mode != B_CMAP8)) {
38576b9d53bSJohn Scipione					// not switching to or from B_CMAP8, break
38676b9d53bSJohn Scipione					break;
38776b9d53bSJohn Scipione				}
38876b9d53bSJohn Scipione
38976b9d53bSJohn Scipione				// fake an archive message (so we don't rebuild views)
39076b9d53bSJohn Scipione				BMessage* data = new BMessage();
39176b9d53bSJohn Scipione				data->AddInt32("_val", Value());
39276b9d53bSJohn Scipione
39376b9d53bSJohn Scipione				// reinititialize
39453f75ce5SJohn Scipione				bool useOffscreen = fOffscreenBitmap != NULL;
39576b9d53bSJohn Scipione				_InitData((color_control_layout)fColumns, fCellSize,
39676b9d53bSJohn Scipione					useOffscreen, data);
39776b9d53bSJohn Scipione				if (useOffscreen)
39876b9d53bSJohn Scipione					_InitOffscreen();
39976b9d53bSJohn Scipione
40076b9d53bSJohn Scipione				// cleanup
40176b9d53bSJohn Scipione				delete data;
40276b9d53bSJohn Scipione			}
40376b9d53bSJohn Scipione			break;
40476b9d53bSJohn Scipione		}
40576b9d53bSJohn Scipione
40653056ca5SMarc Flerackers		default:
40753056ca5SMarc Flerackers			BControl::MessageReceived(message);
40853056ca5SMarc Flerackers	}
40953056ca5SMarc Flerackers}
41036c17cdeSAxel Dörfler
41136c17cdeSAxel Dörfler
41236c17cdeSAxel Dörflervoid
41336c17cdeSAxel DörflerBColorControl::Draw(BRect updateRect)
41453056ca5SMarc Flerackers{
41553f75ce5SJohn Scipione	if (fOffscreenBitmap != NULL)
41653f75ce5SJohn Scipione		DrawBitmap(fOffscreenBitmap, B_ORIGIN);
4172627bad1SStephan Aßmus	else
4189a1d68e4SAxel Dörfler		_DrawColorArea(this, updateRect);
4190289f920SJohn Scipione
4202627bad1SStephan Aßmus	_DrawSelectors(this);
42153056ca5SMarc Flerackers}
42236c17cdeSAxel Dörfler
42336c17cdeSAxel Dörfler
42436c17cdeSAxel Dörflervoid
4250289f920SJohn ScipioneBColorControl::_DrawColorArea(BView* target, BRect updateRect)
42653056ca5SMarc Flerackers{
4278b3b14fdSJohn Scipione	BRect rect = _PaletteFrame();
428d2184e65SJérôme Duval	bool enabled = IsEnabled();
4299a1d68e4SAxel Dörfler
43074577830SJohn Scipione	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
43174577830SJohn Scipione	rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT);
4329a1d68e4SAxel Dörfler
433bfbb9655SAugustin Cavalier	uint32 flags = be_control_look->Flags(this);
434bfbb9655SAugustin Cavalier	be_control_look->DrawTextControlBorder(target, rect, updateRect,
435bfbb9655SAugustin Cavalier		base, flags);
43675eb45a7SMatt Madia
437d2184e65SJérôme Duval	if (fPaletteMode) {
4380289f920SJohn Scipione		int colBegin = max_c(0, -1 + int(updateRect.left) / int(fCellSize));
4390289f920SJohn Scipione		int colEnd = min_c(fColumns,
4400289f920SJohn Scipione			2 + int(updateRect.right) / int(fCellSize));
4410289f920SJohn Scipione		int rowBegin = max_c(0, -1 + int(updateRect.top) / int(fCellSize));
4420289f920SJohn Scipione		int rowEnd = min_c(fRows, 2 + int(updateRect.bottom)
4430289f920SJohn Scipione			/ int(fCellSize));
4440289f920SJohn Scipione
4450289f920SJohn Scipione		// grid
44674577830SJohn Scipione		target->SetHighColor(enabled ? darken1 : base);
4470289f920SJohn Scipione
448abbd44acSJohn Scipione		for (int xi = 0; xi < fColumns + 1; xi++) {
4499c76ea4cSStefano Ceccherini			float x = fPaletteFrame.left + float(xi) * fCellSize;
4500289f920SJohn Scipione			target->StrokeLine(BPoint(x, fPaletteFrame.top),
4510289f920SJohn Scipione				BPoint(x, fPaletteFrame.bottom));
4529c76ea4cSStefano Ceccherini		}
453abbd44acSJohn Scipione		for (int yi = 0; yi < fRows + 1; yi++) {
4549c76ea4cSStefano Ceccherini			float y = fPaletteFrame.top + float(yi) * fCellSize;
4550289f920SJohn Scipione			target->StrokeLine(BPoint(fPaletteFrame.left, y),
4560289f920SJohn Scipione				BPoint(fPaletteFrame.right, y));
457d2184e65SJérôme Duval		}
45875eb45a7SMatt Madia
4590289f920SJohn Scipione		// colors
460d2184e65SJérôme Duval		for (int col = colBegin; col < colEnd; col++) {
461d2184e65SJérôme Duval			for (int row = rowBegin; row < rowEnd; row++) {
462d2184e65SJérôme Duval				uint8 colorIndex = row * fColumns + col;
463d2184e65SJérôme Duval				float x = fPaletteFrame.left + col * fCellSize;
4649c76ea4cSStefano Ceccherini				float y = fPaletteFrame.top + row * fCellSize;
46575eb45a7SMatt Madia
466d2184e65SJérôme Duval				target->SetHighColor(system_colors()->color_list[colorIndex]);
4670289f920SJohn Scipione				target->FillRect(BRect(x + 1, y + 1,
4680289f920SJohn Scipione					x + fCellSize - 1, y + fCellSize - 1));
469d2184e65SJérôme Duval			}
470d2184e65SJérôme Duval		}
4719c76ea4cSStefano Ceccherini	} else {
4720289f920SJohn Scipione		rgb_color white = { 255, 255, 255, 255 };
4732ba93e7dSAdrien Destugues		rgb_color red   = { 255, 0, 0, 255 };
4742ba93e7dSAdrien Destugues		rgb_color green = { 0, 255, 0, 255 };
4752ba93e7dSAdrien Destugues		rgb_color blue  = { 0, 0, 255, 255 };
47675eb45a7SMatt Madia
4770289f920SJohn Scipione		rgb_color compColor = { 0, 0, 0, 255 };
478d2184e65SJérôme Duval		if (!enabled) {
479d2184e65SJérôme Duval			compColor.red = compColor.green = compColor.blue = 156;
480d2184e65SJérôme Duval			red.red = green.green = blue.blue = 70;
481d2184e65SJérôme Duval			white.red = white.green = white.blue = 70;
482d2184e65SJérôme Duval		}
4830289f920SJohn Scipione		_DrawColorRamp(_RampFrame(0), target, white, compColor, 0, false,
4840289f920SJohn Scipione			updateRect);
4850289f920SJohn Scipione		_DrawColorRamp(_RampFrame(1), target, red, compColor, 0, false,
4860289f920SJohn Scipione			updateRect);
4870289f920SJohn Scipione		_DrawColorRamp(_RampFrame(2), target, green, compColor, 0, false,
4880289f920SJohn Scipione			updateRect);
4890289f920SJohn Scipione		_DrawColorRamp(_RampFrame(3), target, blue, compColor, 0, false,
4900289f920SJohn Scipione			updateRect);
4919c76ea4cSStefano Ceccherini	}
4929c76ea4cSStefano Ceccherini}
4939a1d68e4SAxel Dörfler
4949a1d68e4SAxel Dörfler
4959c76ea4cSStefano Ceccherinivoid
4969c76ea4cSStefano CeccheriniBColorControl::_DrawSelectors(BView* target)
4979c76ea4cSStefano Ceccherini{
49874577830SJohn Scipione	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
49974577830SJohn Scipione	rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
50075eb45a7SMatt Madia
5019c76ea4cSStefano Ceccherini	if (fPaletteMode) {
502d2184e65SJérôme Duval		if (fSelectedPaletteColorIndex != -1) {
5030289f920SJohn Scipione			target->SetHighColor(lightenmax);
5040e3b3f92SJohn Scipione			target->StrokeRect(
5050e3b3f92SJohn Scipione				_PaletteSelectorFrame(fSelectedPaletteColorIndex));
506d2184e65SJérôme Duval		}
5079c76ea4cSStefano Ceccherini	} else {
508d2184e65SJérôme Duval		rgb_color color = ValueAsColor();
5099c76ea4cSStefano Ceccherini		target->SetHighColor(255, 255, 255);
5102ba93e7dSAdrien Destugues		target->SetLowColor(0, 0, 0);
51175eb45a7SMatt Madia
5122ba93e7dSAdrien Destugues		int components[4] = { color.alpha, color.red, color.green, color.blue };
51374577830SJohn Scipione
5142ba93e7dSAdrien Destugues		for (int i = 1; i < 4; i++) {
5152ba93e7dSAdrien Destugues			BPoint center = _SelectorPosition(_RampFrame(i), components[i]);
51674577830SJohn Scipione
51774577830SJohn Scipione			target->SetPenSize(kSelectorPenSize);
51874577830SJohn Scipione			target->StrokeEllipse(center, kSelectorSize / 2, kSelectorSize / 2);
5192ba93e7dSAdrien Destugues			target->SetPenSize(kSelectorPenSize / 2);
5202ba93e7dSAdrien Destugues			target->StrokeEllipse(center, kSelectorSize, kSelectorSize,
5212ba93e7dSAdrien Destugues				B_SOLID_LOW);
5222ba93e7dSAdrien Destugues			if (i == fFocusedRamp) {
5232ba93e7dSAdrien Destugues				target->StrokeEllipse(center,
5242ba93e7dSAdrien Destugues					kSelectorSize / 2, kSelectorSize / 2, B_SOLID_LOW);
5252ba93e7dSAdrien Destugues			}
52674577830SJohn Scipione		}
52775eb45a7SMatt Madia
52875eb45a7SMatt Madia		target->SetPenSize(1.0f);
5299c76ea4cSStefano Ceccherini	}
5309a1d68e4SAxel Dörfler}
5319a1d68e4SAxel Dörfler
5329a1d68e4SAxel Dörfler
5339a1d68e4SAxel Dörflervoid
5340289f920SJohn ScipioneBColorControl::_DrawColorRamp(BRect rect, BView* target,
5350289f920SJohn Scipione	rgb_color baseColor, rgb_color compColor, int16 flag, bool focused,
5360289f920SJohn Scipione	BRect updateRect)
5379a1d68e4SAxel Dörfler{
5389c76ea4cSStefano Ceccherini	float width = rect.Width() + 1;
5392ba93e7dSAdrien Destugues	rgb_color color = ValueAsColor();
540b0bc48fbSAxel Dörfler	color.alpha = 255;
54175eb45a7SMatt Madia
5420289f920SJohn Scipione	updateRect = updateRect & rect;
5439c76ea4cSStefano Ceccherini
5440289f920SJohn Scipione	if (updateRect.IsValid() && updateRect.Width() >= 0) {
5450289f920SJohn Scipione		target->BeginLineArray((int32)updateRect.Width() + 1);
54675eb45a7SMatt Madia
5470289f920SJohn Scipione		for (float i = (updateRect.left - rect.left);
5480289f920SJohn Scipione				i <= (updateRect.right - rect.left) + 1; i++) {
5492ba93e7dSAdrien Destugues			if (baseColor.red == 255)
5502ba93e7dSAdrien Destugues				color.red = (uint8)(i * 255 / width) + compColor.red;
5512ba93e7dSAdrien Destugues			if (baseColor.green == 255)
5522ba93e7dSAdrien Destugues				color.green = (uint8)(i * 255 / width) + compColor.green;
5532ba93e7dSAdrien Destugues			if (baseColor.blue == 255)
5542ba93e7dSAdrien Destugues				color.blue = (uint8)(i * 255 / width) + compColor.blue;
5552ba93e7dSAdrien Destugues
5569c76ea4cSStefano Ceccherini			target->AddLine(BPoint(rect.left + i, rect.top),
55775eb45a7SMatt Madia				BPoint(rect.left + i, rect.bottom - 1), color);
5589c76ea4cSStefano Ceccherini		}
55975eb45a7SMatt Madia
5609c76ea4cSStefano Ceccherini		target->EndLineArray();
5619c76ea4cSStefano Ceccherini	}
5629c76ea4cSStefano Ceccherini}
5639c76ea4cSStefano Ceccherini
5649a1d68e4SAxel Dörfler
5659c76ea4cSStefano CeccheriniBPoint
5669c76ea4cSStefano CeccheriniBColorControl::_SelectorPosition(const BRect& rampRect, uint8 shade) const
5679c76ea4cSStefano Ceccherini{
5689c76ea4cSStefano Ceccherini	float radius = kSelectorSize / 2 + kSelectorPenSize / 2;
56975eb45a7SMatt Madia
57075eb45a7SMatt Madia	return BPoint(rampRect.left + kSelectorHSpacing + radius +
5719c76ea4cSStefano Ceccherini		shade * (rampRect.Width() - 2 * (kSelectorHSpacing + radius)) / 255,
5729c76ea4cSStefano Ceccherini		rampRect.top + rampRect.Height() / 2);
5739c76ea4cSStefano Ceccherini}
5749a1d68e4SAxel Dörfler
5759a1d68e4SAxel Dörfler
5768b3b14fdSJohn ScipioneBRect
5778b3b14fdSJohn ScipioneBColorControl::_PaletteFrame() const
5788b3b14fdSJohn Scipione{
5798b3b14fdSJohn Scipione	return fPaletteFrame.InsetByCopy(-kBevelSpacing, -kBevelSpacing);
5808b3b14fdSJohn Scipione}
5818b3b14fdSJohn Scipione
5828b3b14fdSJohn Scipione
5839c76ea4cSStefano CeccheriniBRect
5849c76ea4cSStefano CeccheriniBColorControl::_RampFrame(uint8 rampIndex) const
5859c76ea4cSStefano Ceccherini{
586da6c116dSJohn Scipione	float rampHeight = (float)(fRows * fCellSize / kRampCount);
58775eb45a7SMatt Madia
5880289f920SJohn Scipione	return BRect(fPaletteFrame.left,
5899c76ea4cSStefano Ceccherini		fPaletteFrame.top + float(rampIndex) * rampHeight,
5909c76ea4cSStefano Ceccherini		fPaletteFrame.right,
5919c76ea4cSStefano Ceccherini		fPaletteFrame.top + float(rampIndex + 1) * rampHeight);
5929c76ea4cSStefano Ceccherini}
5939a1d68e4SAxel Dörfler
5949c76ea4cSStefano Ceccherini
5951186916fSJohn Scipionevoid
5961186916fSJohn ScipioneBColorControl::_SetCellSize(float size)
5971186916fSJohn Scipione{
59862fec205SJohn Scipione	BFont font;
59962fec205SJohn Scipione	GetFont(&font);
60062fec205SJohn Scipione	fCellSize = std::max(kMinCellSize,
60162fec205SJohn Scipione		ceilf(size * font.Size() / kDefaultFontSize));
60262fec205SJohn Scipione}
60362fec205SJohn Scipione
60462fec205SJohn Scipione
60562fec205SJohn Scipionefloat
60662fec205SJohn ScipioneBColorControl::_TextRectOffset()
60762fec205SJohn Scipione{
60862fec205SJohn Scipione	return std::max(fRedText->Bounds().Height(),
60962fec205SJohn Scipione		ceilf(_PaletteFrame().Height() / 3));
6101186916fSJohn Scipione}
6111186916fSJohn Scipione
6121186916fSJohn Scipione
6139c76ea4cSStefano CeccheriniBRect
6149c76ea4cSStefano CeccheriniBColorControl::_PaletteSelectorFrame(uint8 colorIndex) const
6159c76ea4cSStefano Ceccherini{
6169c76ea4cSStefano Ceccherini	uint32 row = colorIndex / fColumns;
6179c76ea4cSStefano Ceccherini	uint32 column = colorIndex % fColumns;
6189c76ea4cSStefano Ceccherini	float x = fPaletteFrame.left + column * fCellSize;
61975eb45a7SMatt Madia	float y = fPaletteFrame.top + row * fCellSize;
6209c76ea4cSStefano Ceccherini	return BRect(x, y, x + fCellSize, y + fCellSize);
62153056ca5SMarc Flerackers}
62236c17cdeSAxel Dörfler
62336c17cdeSAxel Dörfler
62436c17cdeSAxel Dörflervoid
6259c76ea4cSStefano CeccheriniBColorControl::_InitOffscreen()
62653056ca5SMarc Flerackers{
62753f75ce5SJohn Scipione	if (fOffscreenBitmap->Lock()) {
62853f75ce5SJohn Scipione		BView* offscreenView = fOffscreenBitmap->ChildAt((int32)0);
62953f75ce5SJohn Scipione		if (offscreenView != NULL) {
63053f75ce5SJohn Scipione			_DrawColorArea(offscreenView, _PaletteFrame());
63153f75ce5SJohn Scipione			offscreenView->Sync();
63253f75ce5SJohn Scipione		}
63353f75ce5SJohn Scipione		fOffscreenBitmap->Unlock();
6349a1d68e4SAxel Dörfler	}
63553056ca5SMarc Flerackers}
63636c17cdeSAxel Dörfler
63736c17cdeSAxel Dörfler
63874577830SJohn Scipionevoid
63974577830SJohn ScipioneBColorControl::_InvalidateSelector(int16 ramp, rgb_color color, bool focused)
64074577830SJohn Scipione{
64174577830SJohn Scipione	if (fPaletteMode)
64274577830SJohn Scipione		return;
64374577830SJohn Scipione
64474577830SJohn Scipione	if (ramp < 1 || ramp > 3)
64574577830SJohn Scipione		return;
64674577830SJohn Scipione
64774577830SJohn Scipione	float invalidateRadius = focused
64874577830SJohn Scipione		? kSelectorSize + kSelectorPenSize / 2
64974577830SJohn Scipione		: kSelectorSize / 2 + kSelectorPenSize;
65074577830SJohn Scipione
65174577830SJohn Scipione	uint8 colorValue = ramp == 1 ? color.red : ramp == 2 ? color.green
65274577830SJohn Scipione		: color.blue;
65374577830SJohn Scipione
65474577830SJohn Scipione	BPoint pos = _SelectorPosition(_RampFrame(ramp), colorValue);
65574577830SJohn Scipione	Invalidate(BRect(pos.x - invalidateRadius, pos.y - invalidateRadius,
65674577830SJohn Scipione		pos.x + invalidateRadius, pos.y + invalidateRadius));
65774577830SJohn Scipione}
65874577830SJohn Scipione
65974577830SJohn Scipione
66036c17cdeSAxel Dörflervoid
6611186916fSJohn ScipioneBColorControl::SetCellSize(float size)
66253056ca5SMarc Flerackers{
6631186916fSJohn Scipione	_SetCellSize(size);
6649a1d68e4SAxel Dörfler	ResizeToPreferred();
66553056ca5SMarc Flerackers}
66636c17cdeSAxel Dörfler
66736c17cdeSAxel Dörfler
66836c17cdeSAxel Dörflerfloat
66936c17cdeSAxel DörflerBColorControl::CellSize() const
67053056ca5SMarc Flerackers{
67153056ca5SMarc Flerackers	return fCellSize;
67253056ca5SMarc Flerackers}
67336c17cdeSAxel Dörfler
67436c17cdeSAxel Dörfler
67536c17cdeSAxel Dörflervoid
67636c17cdeSAxel DörflerBColorControl::SetLayout(color_control_layout layout)
67753056ca5SMarc Flerackers{
67836c17cdeSAxel Dörfler	switch (layout) {
67953056ca5SMarc Flerackers		case B_CELLS_4x64:
68053056ca5SMarc Flerackers			fColumns = 4;
68153056ca5SMarc Flerackers			fRows = 64;
68253056ca5SMarc Flerackers			break;
6830e3b3f92SJohn Scipione
68453056ca5SMarc Flerackers		case B_CELLS_8x32:
68553056ca5SMarc Flerackers			fColumns = 8;
68653056ca5SMarc Flerackers			fRows = 32;
68753056ca5SMarc Flerackers			break;
6880e3b3f92SJohn Scipione
68953056ca5SMarc Flerackers		case B_CELLS_16x16:
69053056ca5SMarc Flerackers			fColumns = 16;
69153056ca5SMarc Flerackers			fRows = 16;
69253056ca5SMarc Flerackers			break;
6930e3b3f92SJohn Scipione
69453056ca5SMarc Flerackers		case B_CELLS_32x8:
69553056ca5SMarc Flerackers			fColumns = 32;
69653056ca5SMarc Flerackers			fRows = 8;
69753056ca5SMarc Flerackers			break;
6980e3b3f92SJohn Scipione
69953056ca5SMarc Flerackers		case B_CELLS_64x4:
70053056ca5SMarc Flerackers			fColumns = 64;
70153056ca5SMarc Flerackers			fRows = 4;
70253056ca5SMarc Flerackers			break;
70353056ca5SMarc Flerackers	}
70475eb45a7SMatt Madia
7059a1d68e4SAxel Dörfler	ResizeToPreferred();
7069a1d68e4S