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
25using std::nothrow;
26
27
28Style::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
50Style::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
73Style::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
89Style::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
112Style::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
145Style::~Style()
146{
147	SetGradient(NULL);
148
149#ifdef ICON_O_MATIC
150	delete fImage;
151#endif
152}
153
154
155#ifdef ICON_O_MATIC
156void
157Style::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
170status_t
171Style::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
191bool
192Style::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
209bool
210Style::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
225void
226Style::SetColor(const rgb_color& color)
227{
228	if (*(uint32*)&fColor == *(uint32*)&color)
229		return;
230
231	fColor = color;
232	Notify();
233}
234
235
236void
237Style::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
285void
286Style::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
303const agg::rgba8*
304Style::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