1/*
2 * Copyright 2006-2012, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan A��mus <superstippi@gmx.de>
7 */
8
9#include "SwatchGroup.h"
10
11#include <stdio.h>
12
13#include "support_ui.h"
14#include "ui_defines.h"
15#include "rgb_hsv.h"
16
17#include "AlphaSlider.h"
18#include "ColorField.h"
19#include "ColorPickerPanel.h"
20#include "ColorSlider.h"
21#include "CurrentColor.h"
22#include "Group.h"
23#include "SwatchView.h"
24
25
26enum {
27	MSG_SET_COLOR		= 'stcl',
28	MSG_COLOR_PICKER	= 'clpk',
29	MSG_ALPHA_SLIDER	= 'alps',
30};
31
32
33#define SWATCH_VIEW_WIDTH 20
34#define SWATCH_VIEW_HEIGHT 15
35
36
37SwatchGroup::SwatchGroup(BRect frame)
38	:
39	BView(frame, "style view", B_FOLLOW_NONE, 0),
40
41	fCurrentColor(NULL),
42	fIgnoreNotifications(false),
43
44	fColorPickerPanel(NULL),
45	fColorPickerMode(H_SELECTED),
46	fColorPickerFrame(100.0, 100.0, 200.0, 200.0)
47{
48	frame = BRect(0, 0, 100, 15);
49	fTopSwatchViews = new Group(frame, "top swatch group");
50	fBottomSwatchViews = new Group(frame, "bottom swatch group");
51
52	// create swatch views with rainbow default palette
53	float h = 0;
54	float s = 1.0;
55	float v = 1.0;
56	rgb_color color;
57	color.alpha = 255;
58	float r = 0.0f;
59	float g = 0.0f;
60	float b = 0.0f;
61	for (int32 i = 0; i < 20; i++) {
62		if (i < 10) {
63			h = ((float)i / 9.0) * 6.0;
64		} else {
65			h = ((float)(i - 9) / 10.0) * 6.0;
66			v = 0.5;
67		}
68
69		HSV_to_RGB(h, s, v, r, g, b);
70		color.red = (uint8)(255.0 * r);
71		color.green = (uint8)(255.0 * g);
72		color.blue = (uint8)(255.0 * b);
73		fSwatchViews[i] = new SwatchView("swatch", new BMessage(MSG_SET_COLOR),
74			this, color, SWATCH_VIEW_WIDTH, SWATCH_VIEW_HEIGHT);
75
76		fSwatchViews[i]->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
77
78		if (i < 10)
79			fTopSwatchViews->AddChild(fSwatchViews[i]);
80		else
81			fBottomSwatchViews->AddChild(fSwatchViews[i]);
82	}
83
84	// create current color swatch view
85	fCurrentColorSV = new SwatchView("current swatch",
86		new BMessage(MSG_COLOR_PICKER), this, color, 28.0, 28.0);
87
88	// When the color of this swatch changes via drag&drop, we want to
89	// adopt it as current color.
90	fCurrentColorSV->SetDroppedMessage(new BMessage(MSG_SET_COLOR));
91
92	// create color field and slider
93	fColorField = new ColorField(BPoint(0.0, 0.0), H_SELECTED,
94		1.0, B_HORIZONTAL);
95	fColorSlider = new ColorSlider(BPoint(0.0, 0.0), H_SELECTED,
96		1.0, 1.0, B_HORIZONTAL);
97	fAlphaSlider = new AlphaSlider(B_HORIZONTAL,
98		new BMessage(MSG_ALPHA_SLIDER));
99
100	// layout gui
101	fTopSwatchViews->SetSpacing(0, 0);
102	fTopSwatchViews->ResizeToPreferred();
103	fTopSwatchViews->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
104	fBottomSwatchViews->SetSpacing(0, 0);
105	fBottomSwatchViews->ResizeToPreferred();
106	fBottomSwatchViews->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
107
108	float paletteHeight = fBottomSwatchViews->Frame().Height()
109		+ fTopSwatchViews->Frame().Height() + 1;
110
111	fTopSwatchViews->MoveTo(paletteHeight + 2, 4);
112	fBottomSwatchViews->MoveTo(paletteHeight + 2,
113		fTopSwatchViews->Frame().bottom + 1);
114
115	fCurrentColorSV->MoveTo(0, fTopSwatchViews->Frame().top);
116	fCurrentColorSV->ResizeTo(paletteHeight, paletteHeight);
117	fCurrentColorSV->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_TOP);
118
119	float width = fTopSwatchViews->Frame().right
120		- fCurrentColorSV->Frame().left;
121
122	fColorField->ResizeTo(width, 40);
123	fColorField->FrameResized(width, 40);
124	fColorSlider->ResizeTo(width, 11);
125	fColorSlider->FrameResized(width, 11);
126	fAlphaSlider->ResizeTo(width, 11);
127	fAlphaSlider->FrameResized(width, 11);
128
129	fColorField->MoveTo(0, fBottomSwatchViews->Frame().bottom + 3);
130	fColorSlider->MoveTo(0, fColorField->Frame().bottom + 1);
131	fAlphaSlider->MoveTo(0, fColorSlider->Frame().bottom + 1);
132	fAlphaSlider->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
133
134	// configure self
135	ResizeTo(width, fAlphaSlider->Frame().bottom + 4);
136	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
137
138	// add views
139	AddChild(fCurrentColorSV);
140	AddChild(fTopSwatchViews);
141	AddChild(fBottomSwatchViews);
142	AddChild(fColorField);
143	AddChild(fColorSlider);
144	AddChild(fAlphaSlider);
145}
146
147
148SwatchGroup::~SwatchGroup()
149{
150	SetCurrentColor(NULL);
151}
152
153
154void
155SwatchGroup::ObjectChanged(const Observable* object)
156{
157	if (object != fCurrentColor || fIgnoreNotifications)
158		return;
159
160	rgb_color color = fCurrentColor->Color();
161
162	float h, s, v;
163	RGB_to_HSV(color.red / 255.0, color.green / 255.0, color.blue / 255.0,
164		h, s, v);
165
166	_SetColor(h, s, v, color.alpha);
167}
168
169
170// #pragma mark -
171
172
173void
174SwatchGroup::AttachedToWindow()
175{
176	fColorField->SetTarget(this);
177	fColorSlider->SetTarget(this);
178	fAlphaSlider->SetTarget(this);
179}
180
181
182void
183SwatchGroup::MessageReceived(BMessage* message)
184{
185	switch (message->what) {
186		case MSG_SET_COLOR:
187		{
188			rgb_color color;
189			if (restore_color_from_message(message, color) == B_OK) {
190// TODO: fix color picker panel to respect alpha
191if (message->HasRect("panel frame"))
192color.alpha = fAlphaSlider->Value();
193//
194				if (fCurrentColor != NULL)
195					fCurrentColor->SetColor(color);
196			}
197			// if message contains these fields,
198			// then it comes from the color picker panel.
199			// it also means the panel has died.
200			BRect frame;
201			SelectedColorMode mode;
202			if (message->FindRect("panel frame", &frame) == B_OK
203				&& message->FindInt32("panel mode", (int32*)&mode) == B_OK) {
204				// message came from the color picker panel
205				// we remember the settings of the panel for later
206				fColorPickerFrame = frame;
207				fColorPickerMode = mode;
208				// color picker panel has quit
209				fColorPickerPanel = NULL;
210			}
211			break;
212		}
213
214		case MSG_COLOR_FIELD:
215		{
216			// get h from color slider
217			float h = ((255 - fColorSlider->Value()) / 255.0) * 6.0;
218			float s, v;
219			// s and v are comming from the message
220			if (message->FindFloat("value", &s) == B_OK
221				&& message->FindFloat("value", 1, &v) == B_OK) {
222				_SetColor(h, s, v, fAlphaSlider->Value());
223			}
224			break;
225		}
226
227		case MSG_COLOR_SLIDER:
228		{
229			float h;
230			float s, v;
231			fColorSlider->GetOtherValues(&s, &v);
232			// h is comming from the message
233			if (message->FindFloat("value", &h) == B_OK)
234				_SetColor(h, s, v, fAlphaSlider->Value());
235			break;
236		}
237
238		case MSG_ALPHA_SLIDER:
239		{
240			float h = (1.0 - (float)fColorSlider->Value() / 255.0) * 6;
241			float s, v;
242			fColorSlider->GetOtherValues(&s, &v);
243			_SetColor(h, s, v, fAlphaSlider->Value());
244			break;
245		}
246
247		case MSG_COLOR_PICKER:
248		{
249			rgb_color color;
250			if (restore_color_from_message(message, color) < B_OK)
251				break;
252
253			if (fColorPickerPanel == NULL) {
254				fColorPickerPanel = new ColorPickerPanel(fColorPickerFrame,
255					color, fColorPickerMode, Window(),
256					new BMessage(MSG_SET_COLOR), this);
257				fColorPickerPanel->Show();
258			} else {
259				if (fColorPickerPanel->Lock()) {
260					fColorPickerPanel->SetColor(color);
261					fColorPickerPanel->Activate();
262					fColorPickerPanel->Unlock();
263				}
264			}
265			break;
266		}
267
268		default:
269			BView::MessageReceived(message);
270			break;
271	}
272}
273
274
275// #pragma mark -
276
277
278void
279SwatchGroup::SetCurrentColor(CurrentColor* color)
280{
281	if (fCurrentColor == color)
282		return;
283
284	if (fCurrentColor != NULL)
285		fCurrentColor->RemoveObserver(this);
286
287	fCurrentColor = color;
288
289	if (fCurrentColor != NULL) {
290		fCurrentColor->AddObserver(this);
291
292		ObjectChanged(fCurrentColor);
293	}
294}
295
296
297// #pragma mark -
298
299
300void
301SwatchGroup::_SetColor(rgb_color color)
302{
303	fCurrentColorSV->SetColor(color);
304}
305
306
307void
308SwatchGroup::_SetColor(float h, float s, float v, uint8 a)
309{
310	float r = 0.0f;
311	float g = 0.0f;
312	float b = 0.0f;
313	HSV_to_RGB(h, s, v, r, g, b);
314
315	rgb_color color;
316	color.red = (uint8)(r * 255.0);
317	color.green = (uint8)(g * 255.0);
318	color.blue = (uint8)(b * 255.0);
319	color.alpha = a;
320
321	if (!fColorField->IsTracking()) {
322		fColorField->SetFixedValue(h);
323		fColorField->SetMarkerToColor(color);
324	}
325	if (!fColorSlider->IsTracking()) {
326		fColorSlider->SetOtherValues(s, v);
327		fColorSlider->SetValue(255 - (int32)((h / 6.0) * 255.0 + 0.5));
328	}
329	if (!fAlphaSlider->IsTracking()) {
330		fAlphaSlider->SetColor(color);
331		fAlphaSlider->SetValue(a);
332	}
333
334	fIgnoreNotifications = true;
335
336	if (fCurrentColor)
337		fCurrentColor->SetColor(color);
338	_SetColor(color);
339
340	fIgnoreNotifications = false;
341}
342