xref: /haiku/src/libs/icon/style/Style.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
1 /*
2  * Copyright 2006, 2023, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  *		Zardshard
8  */
9 
10 #include "Style.h"
11 
12 #include <new>
13 
14 #include <Bitmap.h>
15 #include <Message.h>
16 
17 #ifdef ICON_O_MATIC
18 # include "ui_defines.h"
19 #else
20 # define kWhite (rgb_color){ 255, 255, 255, 255 }
21 #endif // ICON_O_MATIC
22 
23 #include "GradientTransformable.h"
24 
25 using std::nothrow;
26 
27 
28 Style::Style()
29 #ifdef ICON_O_MATIC
30 	: IconObject("<style>"),
31 	  Observer(),
32 #else
33 	:
34 #endif
35 
36 	  fColor(kWhite),
37 	  fGradient(NULL),
38 	  fColors(NULL),
39 #ifdef ICON_O_MATIC
40 	  fImage(NULL),
41 	  fAlpha(255),
42 #endif
43 
44 	  fGammaCorrectedColors(NULL),
45 	  fGammaCorrectedColorsValid(false)
46 {
47 }
48 
49 
50 Style::Style(const rgb_color& color)
51 #ifdef ICON_O_MATIC
52 	: IconObject("<style>"),
53 	  Observer(),
54 #else
55 	:
56 #endif
57 
58 	  fColor(color),
59 	  fGradient(NULL),
60 	  fColors(NULL),
61 #ifdef ICON_O_MATIC
62 	  fImage(NULL),
63 	  fAlpha(255),
64 #endif
65 
66 	  fGammaCorrectedColors(NULL),
67 	  fGammaCorrectedColorsValid(false)
68 {
69 }
70 
71 
72 #ifdef ICON_O_MATIC
73 Style::Style(BBitmap* image)
74 	: IconObject("<style>"),
75 	  Observer(),
76 
77 	  fColor(kWhite),
78 	  fGradient(NULL),
79 	  fColors(NULL),
80 	  fImage(image),
81 
82 	  fGammaCorrectedColors(NULL),
83 	  fGammaCorrectedColorsValid(false)
84 {
85 }
86 #endif
87 
88 
89 Style::Style(const Style& other)
90 #ifdef ICON_O_MATIC
91 	: IconObject(other),
92 	  Observer(),
93 #else
94 	:
95 #endif
96 
97 	  fColor(other.fColor),
98 	  fGradient(NULL),
99 	  fColors(NULL),
100 #ifdef ICON_O_MATIC
101 	  fImage(other.fImage != NULL ? new (nothrow) BBitmap(other.fImage) : NULL),
102 	  fAlpha(255),
103 #endif
104 
105 	  fGammaCorrectedColors(NULL),
106 	  fGammaCorrectedColorsValid(false)
107 {
108 	SetGradient(other.fGradient);
109 }
110 
111 // constructor
112 Style::Style(BMessage* archive)
113 #ifdef ICON_O_MATIC
114 	: IconObject(archive),
115 	  Observer(),
116 #else
117 	:
118 #endif
119 
120 	  fColor(kWhite),
121 	  fGradient(NULL),
122 	  fColors(NULL),
123 #ifdef ICON_O_MATIC
124 	  fImage(NULL),
125 	  fAlpha(255),
126 #endif
127 
128 	  fGammaCorrectedColors(NULL),
129 	  fGammaCorrectedColorsValid(false)
130 {
131 	if (!archive)
132 		return;
133 
134 	if (archive->FindInt32("color", (int32*)&fColor) < B_OK)
135 		fColor = kWhite;
136 
137 	BMessage gradientArchive;
138 	if (archive->FindMessage("gradient", &gradientArchive) == B_OK) {
139 		::Gradient gradient(&gradientArchive);
140 		SetGradient(&gradient);
141 	}
142 }
143 
144 
145 Style::~Style()
146 {
147 	SetGradient(NULL);
148 
149 #ifdef ICON_O_MATIC
150 	delete fImage;
151 #endif
152 }
153 
154 
155 #ifdef ICON_O_MATIC
156 void
157 Style::ObjectChanged(const Observable* object)
158 {
159 	if (object == fGradient && fColors) {
160 		fGradient->MakeGradient((uint32*)fColors, 256);
161 		fGammaCorrectedColorsValid = false;
162 		Notify();
163 	}
164 }
165 
166 
167 // #pragma mark -
168 
169 
170 status_t
171 Style::Archive(BMessage* into, bool deep) const
172 {
173 	status_t ret = IconObject::Archive(into, deep);
174 
175 	if (ret == B_OK)
176 		ret = into->AddInt32("color", (uint32&)fColor);
177 
178 	if (ret == B_OK && fGradient) {
179 		BMessage gradientArchive;
180 		ret = fGradient->Archive(&gradientArchive, deep);
181 		if (ret == B_OK)
182 			ret = into->AddMessage("gradient", &gradientArchive);
183 	}
184 
185 	// Archiving the fImage is the responsibility of ReferenceImage
186 
187 	return ret;
188 }
189 
190 
191 bool
192 Style::operator==(const Style& other) const
193 {
194 	if (fGradient) {
195 		if (other.fGradient)
196 			return *fGradient == *other.fGradient;
197 		else
198 			return false;
199 	} else {
200 		if (!other.fGradient)
201 			return *(uint32*)&fColor == *(uint32*)&other.fColor;
202 		else
203 			return false;
204 	}
205 }
206 #endif // ICON_O_MATIC
207 
208 
209 bool
210 Style::HasTransparency() const
211 {
212 	if (fGradient) {
213 		int32 count = fGradient->CountColors();
214 		for (int32 i = 0; i < count; i++) {
215 			BGradient::ColorStop* step = fGradient->ColorAtFast(i);
216 			if (step->color.alpha < 255)
217 				return true;
218 		}
219 		return false;
220 	}
221 	return fColor.alpha < 255;
222 }
223 
224 
225 void
226 Style::SetColor(const rgb_color& color)
227 {
228 	if (*(uint32*)&fColor == *(uint32*)&color)
229 		return;
230 
231 	fColor = color;
232 	Notify();
233 }
234 
235 
236 void
237 Style::SetGradient(const ::Gradient* gradient)
238 {
239 	if (!fGradient && !gradient)
240 		return;
241 
242 	if (gradient) {
243 		if (!fGradient) {
244 			fGradient = new (nothrow) ::Gradient(*gradient);
245 			if (fGradient) {
246 #ifdef ICON_O_MATIC
247 				fGradient->AddObserver(this);
248 #endif
249 				// generate gradient
250 				fColors = new agg::rgba8[256];
251 				fGradient->MakeGradient((uint32*)fColors, 256);
252 				fGammaCorrectedColorsValid = false;
253 
254 				Notify();
255 			}
256 		} else {
257 			if (*fGradient != *gradient) {
258 				*fGradient = *gradient;
259 			}
260 		}
261 	} else {
262 #ifdef ICON_O_MATIC
263 		fGradient->RemoveObserver(this);
264 #endif
265 		delete[] fColors;
266 		delete[] fGammaCorrectedColors;
267 #ifdef ICON_O_MATIC
268 		if (fGradient != NULL)
269 			fGradient->ReleaseReference();
270 
271 		delete fImage;
272 		fImage = NULL;
273 #else
274 		delete fGradient;
275 #endif
276 		fColors = NULL;
277 		fGammaCorrectedColors = NULL;
278 		fGradient = NULL;
279 		Notify();
280 	}
281 }
282 
283 
284 #ifdef ICON_O_MATIC
285 void
286 Style::SetBitmap(BBitmap* image)
287 {
288 	delete fImage;
289 	fImage = image;
290 
291 	// TODO: This does not reset fGradient or fColors. Currently, this is not
292 	// required, since Icon-O-Matic never turns Gradients into Bitmaps. Probably,
293 	// this class should be subclassed if this feature is ever required. For more
294 	// information, see the todo item in the header file.
295 	if (fGradient != NULL)
296 		debugger("Not implemented");
297 
298 	Notify();
299 }
300 #endif // ICON_O_MATIC
301 
302 
303 const agg::rgba8*
304 Style::GammaCorrectedColors(const GammaTable& table) const
305 {
306 	if (!fColors)
307 		return NULL;
308 
309 	if (!fGammaCorrectedColors)
310 		fGammaCorrectedColors = new agg::rgba8[256];
311 
312 	if (!fGammaCorrectedColorsValid) {
313 		for (int32 i = 0; i < 256; i++) {
314 			fGammaCorrectedColors[i].r = table.dir(fColors[i].r);
315 			fGammaCorrectedColors[i].g = table.dir(fColors[i].g);
316 			fGammaCorrectedColors[i].b = table.dir(fColors[i].b);
317 			fGammaCorrectedColors[i].a = fColors[i].a;
318 			fGammaCorrectedColors[i].premultiply();
319 		}
320 		fGammaCorrectedColorsValid = true;
321 	}
322 
323 	return fGammaCorrectedColors;
324 }
325 
326