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 "SwatchView.h"
10
11#include <new>
12#include <stdio.h>
13
14#include <Bitmap.h>
15#include <Cursor.h>
16#include <Looper.h>
17#include <Message.h>
18#include <TypeConstants.h>
19#include <Window.h>
20
21#include "cursors.h"
22#include "ui_defines.h"
23#include "support.h"
24#include "support_ui.h"
25
26
27#define DRAG_INIT_DIST 10.0
28
29
30SwatchView::SwatchView(const char* name, BMessage* message, BHandler* target,
31	rgb_color color, float width, float height)
32	:
33	BView(BRect(0.0, 0.0, width, height), name, B_FOLLOW_NONE, B_WILL_DRAW),
34	fColor(color),
35	fTrackingStart(-1.0, -1.0),
36	fActive(false),
37	fDropInvokes(false),
38	fClickMessage(message),
39	fDroppedMessage(NULL),
40	fTarget(target),
41	fWidth(width),
42	fHeight(height)
43{
44	SetViewColor(B_TRANSPARENT_32_BIT);
45	SetHighColor(fColor);
46}
47
48
49SwatchView::~SwatchView()
50{
51	delete fClickMessage;
52	delete fDroppedMessage;
53}
54
55
56inline void
57blend_color(rgb_color& a, const rgb_color& b, float alpha)
58{
59	float alphaInv = 1.0 - alpha;
60	a.red = (uint8)(b.red * alphaInv + a.red * alpha);
61	a.green = (uint8)(b.green * alphaInv + a.green * alpha);
62	a.blue = (uint8)(b.blue * alphaInv + a.blue * alpha);
63}
64
65
66void
67SwatchView::Draw(BRect updateRect)
68{
69	BRect r(Bounds());
70
71	rgb_color colorLight = tint_color(fColor, B_LIGHTEN_2_TINT);
72	rgb_color colorShadow = tint_color(fColor, B_DARKEN_2_TINT);
73
74	if (fColor.alpha < 255) {
75		// left/top
76		float alpha = fColor.alpha / 255.0;
77
78		rgb_color h = colorLight;
79		blend_color(h, kAlphaHigh, alpha);
80		rgb_color l = colorLight;
81		blend_color(l, kAlphaLow, alpha);
82
83		SetHighColor(h);
84		SetLowColor(l);
85
86		StrokeLine(BPoint(r.left, r.bottom - 1),
87				   BPoint(r.left, r.top), kDottedBig);
88		StrokeLine(BPoint(r.left + 1, r.top),
89				   BPoint(r.right, r.top), kDottedBig);
90
91		// right/bottom
92		h = colorShadow;
93		blend_color(h, kAlphaHigh, alpha);
94		l = colorShadow;
95		blend_color(l, kAlphaLow, alpha);
96
97		SetHighColor(h);
98		SetLowColor(l);
99
100		StrokeLine(BPoint(r.right, r.top + 1),
101				   BPoint(r.right, r.bottom), kDottedBig);
102		StrokeLine(BPoint(r.right - 1, r.bottom),
103				   BPoint(r.left, r.bottom), kDottedBig);
104
105		// fill
106		r.InsetBy(1.0, 1.0);
107
108		h = fColor;
109		blend_color(h, kAlphaHigh, alpha);
110		l = fColor;
111		blend_color(l, kAlphaLow, alpha);
112
113		SetHighColor(h);
114		SetLowColor(l);
115
116		FillRect(r, kDottedBig);
117	} else {
118		_StrokeRect(r, colorLight, colorShadow);
119		r.InsetBy(1.0, 1.0);
120		SetHighColor(fColor);
121		FillRect(r);
122	}
123}
124
125
126void
127SwatchView::MessageReceived(BMessage* message)
128{
129	switch (message->what) {
130		case B_PASTE:
131		{
132			rgb_color color;
133			if (restore_color_from_message(message, color) == B_OK) {
134				SetColor(color);
135				_Invoke(fDroppedMessage);
136			}
137			break;
138		}
139
140		default:
141			BView::MessageReceived(message);
142			break;
143	}
144}
145
146
147void
148SwatchView::MouseDown(BPoint where)
149{
150	if (Bounds().Contains(where))
151		fTrackingStart = where;
152}
153
154
155void
156SwatchView::MouseUp(BPoint where)
157{
158	if (Bounds().Contains(where) && Bounds().Contains(fTrackingStart))
159		_Invoke(fClickMessage);
160
161	fTrackingStart.x = -1.0;
162	fTrackingStart.y = -1.0;
163}
164
165
166void
167SwatchView::MouseMoved(BPoint where, uint32 transit,
168	const BMessage* dragMessage)
169{
170	if (transit == B_ENTERED_VIEW) {
171		BCursor cursor(kDropperCursor);
172		SetViewCursor(&cursor, true);
173	}
174
175	if (Bounds().Contains(fTrackingStart)) {
176		if (point_point_distance(where, fTrackingStart) > DRAG_INIT_DIST
177			|| transit == B_EXITED_VIEW) {
178			_DragColor();
179			fTrackingStart.x = -1.0;
180			fTrackingStart.y = -1.0;
181		}
182	}
183}
184
185
186void
187SwatchView::SetColor(rgb_color color)
188{
189	fColor = color;
190	SetHighColor(fColor);
191	Invalidate();
192}
193
194
195void
196SwatchView::SetClickedMessage(BMessage* message)
197{
198	if (message != fClickMessage)
199		delete fClickMessage;
200	fClickMessage = message;
201}
202
203
204void
205SwatchView::SetDroppedMessage(BMessage* message)
206{
207	if (message != fDroppedMessage)
208		delete fDroppedMessage;
209	fDroppedMessage = message;
210}
211
212
213void
214SwatchView::_Invoke(const BMessage* _message)
215{
216	if (_message == NULL)
217		return;
218
219	BHandler* target = fTarget;
220	if (target == NULL)
221		target = Window();
222
223	if (target == NULL)
224		return;
225
226	BLooper* looper = target->Looper();
227	if (looper == NULL)
228		return;
229
230	BMessage message(*_message);
231	message.AddPointer("be:source", (void*)this);
232	message.AddInt64("be:when", system_time());
233	message.AddBool("begin", true);
234	store_color_in_message(&message, fColor);
235	looper->PostMessage(&message, target);
236}
237
238
239void
240SwatchView::_StrokeRect(BRect r, rgb_color leftTop, rgb_color rightBottom)
241{
242	BeginLineArray(4);
243
244	AddLine(BPoint(r.left, r.bottom - 1), BPoint(r.left, r.top), leftTop);
245	AddLine(BPoint(r.left + 1, r.top), BPoint(r.right, r.top), leftTop);
246	AddLine(BPoint(r.right, r.top + 1), BPoint(r.right, r.bottom),
247		rightBottom);
248	AddLine(BPoint(r.right - 1, r.bottom), BPoint(r.left, r.bottom),
249		rightBottom);
250
251	EndLineArray();
252}
253
254
255void
256SwatchView::_DragColor()
257{
258	BBitmap* bitmap = new(std::nothrow) BBitmap(BRect(0.0, 0.0, 15.0, 15.0),
259		B_RGB32);
260
261	BMessage message = make_color_drop_message(fColor, bitmap);
262
263	DragMessage(&message, bitmap, B_OP_ALPHA, BPoint(9.0, 9.0));
264}
265
266