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