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