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