xref: /haiku/src/preferences/appearance/ColorPreview.cpp (revision 830f67ef991407f287dbc1238aa5f5906d90c991)
1 /*
2  * Copyright 2002-2016 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm, darkwyrm@earthlink.net
7  *		John Scipione, jscipione@gmail.com
8  */
9 
10 
11 #include "ColorPreview.h"
12 
13 #include <algorithm>
14 
15 #include <stdio.h>
16 
17 #include <Bitmap.h>
18 #include <Message.h>
19 #include <MessageRunner.h>
20 #include <String.h>
21 #include <View.h>
22 #include <Window.h>
23 
24 #include "defs.h"
25 
26 
27 
28 static const int32 kMsgMessageRunner = 'MsgR';
29 
30 
31 //	#pragma mark - ColorPreview
32 
33 
34 ColorPreview::ColorPreview(BRect frame, BMessage* message, uint32 resizingMode,
35 	uint32 flags)
36 	:
37 	BControl(frame, "ColorPreview", "", message, resizingMode,
38 		flags | B_WILL_DRAW),
39 	fColor(ui_color(B_PANEL_BACKGROUND_COLOR)),
40 	fDisabledColor((rgb_color){ 128, 128, 128 }),
41 	fMessageRunner(NULL),
42 	fIsRectangle(true)
43 {
44 	SetViewColor(B_TRANSPARENT_COLOR);
45 	SetLowColor(0, 0, 0);
46 }
47 
48 
49 ColorPreview::~ColorPreview(void)
50 {
51 }
52 
53 
54 void
55 ColorPreview::Draw(BRect updateRect)
56 {
57 	rgb_color color;
58 	if (IsEnabled())
59 		color = fColor;
60 	else
61 		color = fDisabledColor;
62 
63 	if (fIsRectangle) {
64 		if (IsEnabled()) {
65 			rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
66 			rgb_color shadow = tint_color(background, B_DARKEN_1_TINT);
67 			rgb_color darkShadow = tint_color(background, B_DARKEN_3_TINT);
68 			rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
69 
70 			BRect bounds(Bounds());
71 
72 			BeginLineArray(4);
73 			AddLine(BPoint(bounds.left, bounds.bottom),
74 			BPoint(bounds.left, bounds.top), shadow);
75 			AddLine(BPoint(bounds.left + 1.0, bounds.top),
76 			BPoint(bounds.right, bounds.top), shadow);
77 			AddLine(BPoint(bounds.right, bounds.top + 1.0),
78 			BPoint(bounds.right, bounds.bottom), light);
79 			AddLine(BPoint(bounds.right - 1.0, bounds.bottom),
80 			BPoint(bounds.left + 1.0, bounds.bottom), light);
81 			EndLineArray();
82 			bounds.InsetBy(1.0, 1.0);
83 
84 			BeginLineArray(4);
85 			AddLine(BPoint(bounds.left, bounds.bottom),
86 			BPoint(bounds.left, bounds.top), darkShadow);
87 			AddLine(BPoint(bounds.left + 1.0, bounds.top),
88 			BPoint(bounds.right, bounds.top), darkShadow);
89 			AddLine(BPoint(bounds.right, bounds.top + 1.0),
90 			BPoint(bounds.right, bounds.bottom), background);
91 			AddLine(BPoint(bounds.right - 1.0, bounds.bottom),
92 			BPoint(bounds.left + 1.0, bounds.bottom), background);
93 			EndLineArray();
94 			bounds.InsetBy(1.0, 1.0);
95 
96 			SetHighColor(color);
97 			FillRect(bounds);
98 		} else {
99 			SetHighColor(color);
100 			FillRect(Bounds());
101 		}
102 	} else {
103 		// fill background
104 		SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
105 		FillRect(updateRect);
106 
107 		SetHighColor(color);
108 		FillEllipse(Bounds());
109 
110 		if (IsEnabled())
111 			StrokeEllipse(Bounds(), B_SOLID_LOW);
112 	}
113 }
114 
115 
116 void
117 ColorPreview::MessageReceived(BMessage* message)
118 {
119 	// If we received a dropped message, see if it contains color data
120 	if (message->WasDropped()) {
121 		rgb_color* color;
122 		ssize_t size;
123 		if (message->FindData(kRGBColor, B_RGB_COLOR_TYPE,
124 				(const void**)&color, &size) == B_OK) {
125 			BMessage setColorMessage(SET_CURRENT_COLOR);
126 			setColorMessage.AddData(kRGBColor, B_RGB_COLOR_TYPE, color,
127 				sizeof(rgb_color));
128 			Invoke(&setColorMessage);
129 		}
130 	} else if ((int32)message->what == kMsgMessageRunner) {
131 		BPoint where;
132 		uint32 buttons;
133 		GetMouse(&where, &buttons);
134 
135 		_DragColor(where);
136 	}
137 
138 	BControl::MessageReceived(message);
139 }
140 
141 
142 void
143 ColorPreview::MouseDown(BPoint where)
144 {
145 	BWindow* window = Window();
146 	if (window != NULL)
147 		window->Activate();
148 
149 	fMessageRunner = new BMessageRunner(this, new BMessage(kMsgMessageRunner),
150 		300000, 1);
151 
152 	SetMouseEventMask(B_POINTER_EVENTS,
153 		B_SUSPEND_VIEW_FOCUS | B_LOCK_WINDOW_FOCUS);
154 
155 	BRect rect = Bounds().InsetByCopy(2.0f, 2.0f);
156 	rect.top = roundf(rect.bottom / 2.0f + 1);
157 
158 	if (rect.Contains(where)) {
159 		Invalidate();
160 		Invoke();
161 	}
162 
163 	BControl::MouseDown(where);
164 }
165 
166 
167 void
168 ColorPreview::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
169 {
170 	if (fMessageRunner != NULL)
171 		_DragColor(where);
172 
173 	BControl::MouseMoved(where, transit, message);
174 }
175 
176 
177 void
178 ColorPreview::MouseUp(BPoint where)
179 {
180 	delete fMessageRunner;
181 	fMessageRunner = NULL;
182 
183 	BControl::MouseUp(where);
184 }
185 
186 
187 rgb_color
188 ColorPreview::Color(void) const
189 {
190 	return fColor;
191 }
192 
193 
194 void
195 ColorPreview::SetColor(rgb_color color)
196 {
197 	color.alpha = 255;
198 
199 	SetHighColor(color);
200 	fColor = color;
201 
202 	Invalidate();
203 	Invoke();
204 }
205 
206 
207 void
208 ColorPreview::SetColor(uint8 red, uint8 green, uint8 blue)
209 {
210 	SetHighColor(red, green, blue);
211 	fColor.red = red;
212 	fColor.green = green;
213 	fColor.blue = blue;
214 	fColor.alpha = 255;
215 
216 	Invalidate();
217 	Invoke();
218 }
219 
220 
221 void
222 ColorPreview::SetMode(bool rectangle)
223 {
224 	fIsRectangle = rectangle;
225 }
226 
227 
228 //	#pragma mark - ColorPreview private methods
229 
230 
231 void
232 ColorPreview::_DragColor(BPoint where)
233 {
234 	BString hexStr;
235 	hexStr.SetToFormat("#%.2X%.2X%.2X", fColor.red, fColor.green, fColor.blue);
236 
237 	BMessage message(B_PASTE);
238 	message.AddData("text/plain", B_MIME_TYPE, hexStr.String(),
239 		hexStr.Length());
240 	message.AddData(kRGBColor, B_RGB_COLOR_TYPE, &fColor, sizeof(fColor));
241 
242 	BRect rect(0.0f, 0.0f, 20.0f, 20.0f);
243 
244 	BBitmap* bitmap = new BBitmap(rect, B_RGB32, true);
245 	if (bitmap->Lock()) {
246 		BView* view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW);
247 		bitmap->AddChild(view);
248 
249 		view->SetHighColor(B_TRANSPARENT_COLOR);
250 		view->FillRect(view->Bounds());
251 
252 		++rect.top;
253 		++rect.left;
254 
255 		view->SetHighColor(0, 0, 0, 100);
256 		view->FillRect(rect);
257 		rect.OffsetBy(-1.0f, -1.0f);
258 
259 		view->SetHighColor(std::min(255, (int)(1.2 * fColor.red + 40)),
260 			std::min(255, (int)(1.2 * fColor.green + 40)),
261 			std::min(255, (int)(1.2 * fColor.blue + 40)));
262 		view->StrokeRect(rect);
263 
264 		++rect.left;
265 		++rect.top;
266 
267 		view->SetHighColor((int32)(0.8 * fColor.red),
268 			(int32)(0.8 * fColor.green),
269 			(int32)(0.8 * fColor.blue));
270 		view->StrokeRect(rect);
271 
272 		--rect.right;
273 		--rect.bottom;
274 
275 		view->SetHighColor(fColor.red, fColor.green, fColor.blue);
276 		view->FillRect(rect);
277 		view->Sync();
278 
279 		bitmap->Unlock();
280 	}
281 
282 	DragMessage(&message, bitmap, B_OP_ALPHA, BPoint(14.0f, 14.0f));
283 
284 	MouseUp(where);
285 }
286