xref: /haiku/src/kits/interface/Gradient.cpp (revision 779ab335dd81d47f9aa7ef06822de37c8fec1c6e)
1991547efSStephan Aßmus /*
264eb49fdSStephan Aßmus  * Copyright 2006-2009, Haiku.
3991547efSStephan Aßmus  * Distributed under the terms of the MIT License.
4991547efSStephan Aßmus  *
5991547efSStephan Aßmus  * Authors:
6991547efSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
7991547efSStephan Aßmus  *		Artur Wyszynski <harakash@gmail.com>
8991547efSStephan Aßmus  */
9991547efSStephan Aßmus 
10991547efSStephan Aßmus #include "Gradient.h"
11991547efSStephan Aßmus 
1277b60d22SAdrien Destugues #include <algorithm>
13991547efSStephan Aßmus #include <math.h>
14991547efSStephan Aßmus #include <stdio.h>
15991547efSStephan Aßmus 
1636ef16bfSX512 #include <DataIO.h>
17991547efSStephan Aßmus #include <Message.h>
18991547efSStephan Aßmus 
1936ef16bfSX512 #include <AutoDeleter.h>
2036ef16bfSX512 #include <GradientLinear.h>
2136ef16bfSX512 #include <GradientRadial.h>
2236ef16bfSX512 #include <GradientRadialFocus.h>
2336ef16bfSX512 #include <GradientDiamond.h>
2436ef16bfSX512 #include <GradientConic.h>
2536ef16bfSX512 
26991547efSStephan Aßmus 
27991547efSStephan Aßmus // constructor
ColorStop(const rgb_color c,float o)2864eb49fdSStephan Aßmus BGradient::ColorStop::ColorStop(const rgb_color c, float o)
29991547efSStephan Aßmus {
30991547efSStephan Aßmus 	color.red = c.red;
31991547efSStephan Aßmus 	color.green = c.green;
32991547efSStephan Aßmus 	color.blue = c.blue;
33991547efSStephan Aßmus 	color.alpha = c.alpha;
34991547efSStephan Aßmus 	offset = o;
35991547efSStephan Aßmus }
36991547efSStephan Aßmus 
37991547efSStephan Aßmus 
38991547efSStephan Aßmus // constructor
ColorStop(uint8 r,uint8 g,uint8 b,uint8 a,float o)3964eb49fdSStephan Aßmus BGradient::ColorStop::ColorStop(uint8 r, uint8 g, uint8 b, uint8 a, float o)
40991547efSStephan Aßmus {
41991547efSStephan Aßmus 	color.red = r;
42991547efSStephan Aßmus 	color.green = g;
43991547efSStephan Aßmus 	color.blue = b;
44991547efSStephan Aßmus 	color.alpha = a;
45991547efSStephan Aßmus 	offset = o;
46991547efSStephan Aßmus }
47991547efSStephan Aßmus 
48991547efSStephan Aßmus 
49991547efSStephan Aßmus // constructor
ColorStop(const ColorStop & other)5064eb49fdSStephan Aßmus BGradient::ColorStop::ColorStop(const ColorStop& other)
51991547efSStephan Aßmus {
52991547efSStephan Aßmus 	color.red = other.color.red;
53991547efSStephan Aßmus 	color.green = other.color.green;
54991547efSStephan Aßmus 	color.blue = other.color.blue;
55991547efSStephan Aßmus 	color.alpha = other.color.alpha;
56991547efSStephan Aßmus 	offset = other.offset;
57991547efSStephan Aßmus }
58991547efSStephan Aßmus 
59991547efSStephan Aßmus 
60991547efSStephan Aßmus // constructor
ColorStop()6164eb49fdSStephan Aßmus BGradient::ColorStop::ColorStop()
62991547efSStephan Aßmus {
63991547efSStephan Aßmus 	color.red = 0;
64991547efSStephan Aßmus 	color.green = 0;
65991547efSStephan Aßmus 	color.blue = 0;
66991547efSStephan Aßmus 	color.alpha = 255;
67991547efSStephan Aßmus 	offset = 0;
68991547efSStephan Aßmus }
69991547efSStephan Aßmus 
70991547efSStephan Aßmus 
71991547efSStephan Aßmus // operator!=
72991547efSStephan Aßmus bool
operator !=(const ColorStop & other) const7364eb49fdSStephan Aßmus BGradient::ColorStop::operator!=(const ColorStop& other) const
74991547efSStephan Aßmus {
75991547efSStephan Aßmus 	return color.red != other.color.red ||
76991547efSStephan Aßmus 	color.green != other.color.green ||
77991547efSStephan Aßmus 	color.blue != other.color.blue ||
78991547efSStephan Aßmus 	color.alpha != other.color.alpha ||
79991547efSStephan Aßmus 	offset != other.offset;
80991547efSStephan Aßmus }
81991547efSStephan Aßmus 
82991547efSStephan Aßmus 
8377b60d22SAdrien Destugues static bool
sort_color_stops_by_offset(const BGradient::ColorStop * left,const BGradient::ColorStop * right)8477b60d22SAdrien Destugues sort_color_stops_by_offset(const BGradient::ColorStop* left,
8577b60d22SAdrien Destugues 	const BGradient::ColorStop* right)
86991547efSStephan Aßmus {
8777b60d22SAdrien Destugues 	return left->offset < right->offset;
88991547efSStephan Aßmus }
89991547efSStephan Aßmus 
90991547efSStephan Aßmus 
91991547efSStephan Aßmus // #pragma mark -
92991547efSStephan Aßmus 
93991547efSStephan Aßmus 
94991547efSStephan Aßmus // constructor
BGradient()95991547efSStephan Aßmus BGradient::BGradient()
96991547efSStephan Aßmus 	: BArchivable(),
9764eb49fdSStephan Aßmus 	fColorStops(4),
9852de6dceSStephan Aßmus 	fType(TYPE_NONE)
99991547efSStephan Aßmus {
100991547efSStephan Aßmus }
101991547efSStephan Aßmus 
102991547efSStephan Aßmus 
BGradient(const BGradient & other)1036d9c0146SAdrien Destugues BGradient::BGradient(const BGradient& other)
1046d9c0146SAdrien Destugues 	: BArchivable(),
1056d9c0146SAdrien Destugues 	fColorStops(std::max((int32)4, other.CountColorStops()))
1066d9c0146SAdrien Destugues {
1076d9c0146SAdrien Destugues 	*this = other;
1086d9c0146SAdrien Destugues }
1096d9c0146SAdrien Destugues 
1106d9c0146SAdrien Destugues 
111991547efSStephan Aßmus // constructor
BGradient(BMessage * archive)112991547efSStephan Aßmus BGradient::BGradient(BMessage* archive)
113991547efSStephan Aßmus 	: BArchivable(archive),
11464eb49fdSStephan Aßmus 	fColorStops(4),
11552de6dceSStephan Aßmus 	fType(TYPE_NONE)
116991547efSStephan Aßmus {
117991547efSStephan Aßmus 	if (!archive)
118991547efSStephan Aßmus 		return;
119991547efSStephan Aßmus 
12064eb49fdSStephan Aßmus 	// color stops
12164eb49fdSStephan Aßmus 	ColorStop stop;
12264eb49fdSStephan Aßmus 	for (int32 i = 0; archive->FindFloat("offset", i, &stop.offset) >= B_OK; i++) {
12364eb49fdSStephan Aßmus 		if (archive->FindInt32("color", i, (int32*)&stop.color) >= B_OK)
12464eb49fdSStephan Aßmus 			AddColorStop(stop, i);
125991547efSStephan Aßmus 		else
126991547efSStephan Aßmus 			break;
127991547efSStephan Aßmus 	}
128991547efSStephan Aßmus 	if (archive->FindInt32("type", (int32*)&fType) < B_OK)
12952de6dceSStephan Aßmus 		fType = TYPE_LINEAR;
130991547efSStephan Aßmus 
131991547efSStephan Aßmus 	// linear
132991547efSStephan Aßmus 	if (archive->FindFloat("linear_x1", (float*)&fData.linear.x1) < B_OK)
133991547efSStephan Aßmus 		fData.linear.x1 = 0.0f;
134991547efSStephan Aßmus 	if (archive->FindFloat("linear_y1", (float*)&fData.linear.y1) < B_OK)
135991547efSStephan Aßmus 		fData.linear.y1 = 0.0f;
136991547efSStephan Aßmus 	if (archive->FindFloat("linear_x2", (float*)&fData.linear.x2) < B_OK)
137991547efSStephan Aßmus 		fData.linear.x2 = 0.0f;
138991547efSStephan Aßmus 	if (archive->FindFloat("linear_y2", (float*)&fData.linear.y2) < B_OK)
139b355a208SStephan Aßmus 		fData.linear.y2 = 0.0f;
140991547efSStephan Aßmus 
141991547efSStephan Aßmus 	// radial
142991547efSStephan Aßmus 	if (archive->FindFloat("radial_cx", (float*)&fData.radial.cx) < B_OK)
143991547efSStephan Aßmus 		fData.radial.cx = 0.0f;
144991547efSStephan Aßmus 	if (archive->FindFloat("radial_cy", (float*)&fData.radial.cy) < B_OK)
145991547efSStephan Aßmus 		fData.radial.cy = 0.0f;
146991547efSStephan Aßmus 	if (archive->FindFloat("radial_radius", (float*)&fData.radial.radius) < B_OK)
147991547efSStephan Aßmus 		fData.radial.radius = 0.0f;
148991547efSStephan Aßmus 
149991547efSStephan Aßmus 	// radial focus
150991547efSStephan Aßmus 	if (archive->FindFloat("radial_f_cx", (float*)&fData.radial_focus.cx) < B_OK)
151991547efSStephan Aßmus 		fData.radial_focus.cx = 0.0f;
152991547efSStephan Aßmus 	if (archive->FindFloat("radial_f_cy", (float*)&fData.radial_focus.cy) < B_OK)
153991547efSStephan Aßmus 		fData.radial_focus.cy = 0.0f;
154991547efSStephan Aßmus 	if (archive->FindFloat("radial_f_fx", (float*)&fData.radial_focus.fx) < B_OK)
155991547efSStephan Aßmus 		fData.radial_focus.fx = 0.0f;
156991547efSStephan Aßmus 	if (archive->FindFloat("radial_f_fy", (float*)&fData.radial_focus.fy) < B_OK)
157991547efSStephan Aßmus 		fData.radial_focus.fy = 0.0f;
158b355a208SStephan Aßmus 	if (archive->FindFloat("radial_f_radius", (float*)&fData.radial_focus.radius) < B_OK)
159b355a208SStephan Aßmus 		fData.radial_focus.radius = 0.0f;
160991547efSStephan Aßmus 
161991547efSStephan Aßmus 	// diamond
162991547efSStephan Aßmus 	if (archive->FindFloat("diamond_cx", (float*)&fData.diamond.cx) < B_OK)
163991547efSStephan Aßmus 		fData.diamond.cx = 0.0f;
164991547efSStephan Aßmus 	if (archive->FindFloat("diamond_cy", (float*)&fData.diamond.cy) < B_OK)
165991547efSStephan Aßmus 		fData.diamond.cy = 0.0f;
166991547efSStephan Aßmus 
167991547efSStephan Aßmus 	// conic
168991547efSStephan Aßmus 	if (archive->FindFloat("conic_cx", (float*)&fData.conic.cx) < B_OK)
169991547efSStephan Aßmus 		fData.conic.cx = 0.0f;
170991547efSStephan Aßmus 	if (archive->FindFloat("conic_cy", (float*)&fData.conic.cy) < B_OK)
171991547efSStephan Aßmus 		fData.conic.cy = 0.0f;
172991547efSStephan Aßmus 	if (archive->FindFloat("conic_angle", (float*)&fData.conic.angle) < B_OK)
173991547efSStephan Aßmus 		fData.conic.angle = 0.0f;
174991547efSStephan Aßmus }
175991547efSStephan Aßmus 
176991547efSStephan Aßmus 
177991547efSStephan Aßmus // destructor
~BGradient()178991547efSStephan Aßmus BGradient::~BGradient()
179991547efSStephan Aßmus {
180991547efSStephan Aßmus 	MakeEmpty();
181991547efSStephan Aßmus }
182991547efSStephan Aßmus 
183991547efSStephan Aßmus 
184991547efSStephan Aßmus // Archive
185991547efSStephan Aßmus status_t
Archive(BMessage * into,bool deep) const186991547efSStephan Aßmus BGradient::Archive(BMessage* into, bool deep) const
187991547efSStephan Aßmus {
188991547efSStephan Aßmus 	status_t ret = BArchivable::Archive(into, deep);
189991547efSStephan Aßmus 
190991547efSStephan Aßmus 	// color steps
191991547efSStephan Aßmus 	if (ret >= B_OK) {
19264eb49fdSStephan Aßmus 		for (int32 i = 0; ColorStop* stop = ColorStopAt(i); i++) {
19364eb49fdSStephan Aßmus 			ret = into->AddInt32("color", (const uint32&)stop->color);
194991547efSStephan Aßmus 			if (ret < B_OK)
195991547efSStephan Aßmus 				break;
19664eb49fdSStephan Aßmus 			ret = into->AddFloat("offset", stop->offset);
197991547efSStephan Aßmus 			if (ret < B_OK)
198991547efSStephan Aßmus 				break;
199991547efSStephan Aßmus 		}
200991547efSStephan Aßmus 	}
201991547efSStephan Aßmus 	// gradient type
202991547efSStephan Aßmus 	if (ret >= B_OK)
203991547efSStephan Aßmus 		ret = into->AddInt32("type", (int32)fType);
204991547efSStephan Aßmus 
205991547efSStephan Aßmus 	// linear
206991547efSStephan Aßmus 	if (ret >= B_OK)
207991547efSStephan Aßmus 		ret = into->AddFloat("linear_x1", (float)fData.linear.x1);
208991547efSStephan Aßmus 	if (ret >= B_OK)
209991547efSStephan Aßmus 		ret = into->AddFloat("linear_y1", (float)fData.linear.y1);
210991547efSStephan Aßmus 	if (ret >= B_OK)
211991547efSStephan Aßmus 		ret = into->AddFloat("linear_x2", (float)fData.linear.x2);
212991547efSStephan Aßmus 	if (ret >= B_OK)
213991547efSStephan Aßmus 		ret = into->AddFloat("linear_y2", (float)fData.linear.y2);
214991547efSStephan Aßmus 
215991547efSStephan Aßmus 	// radial
216991547efSStephan Aßmus 	if (ret >= B_OK)
217991547efSStephan Aßmus 		ret = into->AddFloat("radial_cx", (float)fData.radial.cx);
218991547efSStephan Aßmus 	if (ret >= B_OK)
219991547efSStephan Aßmus 		ret = into->AddFloat("radial_cy", (float)fData.radial.cy);
220991547efSStephan Aßmus 	if (ret >= B_OK)
221991547efSStephan Aßmus 		ret = into->AddFloat("radial_radius", (float)fData.radial.radius);
222991547efSStephan Aßmus 
223991547efSStephan Aßmus 	// radial focus
224991547efSStephan Aßmus 	if (ret >= B_OK)
225991547efSStephan Aßmus 		ret = into->AddFloat("radial_f_cx", (float)fData.radial_focus.cx);
226991547efSStephan Aßmus 	if (ret >= B_OK)
227991547efSStephan Aßmus 		ret = into->AddFloat("radial_f_cy", (float)fData.radial_focus.cy);
228991547efSStephan Aßmus 	if (ret >= B_OK)
229991547efSStephan Aßmus 		ret = into->AddFloat("radial_f_fx", (float)fData.radial_focus.fx);
230991547efSStephan Aßmus 	if (ret >= B_OK)
231991547efSStephan Aßmus 		ret = into->AddFloat("radial_f_fy", (float)fData.radial_focus.fy);
232991547efSStephan Aßmus 	if (ret >= B_OK)
233b355a208SStephan Aßmus 		ret = into->AddFloat("radial_f_radius", (float)fData.radial_focus.radius);
234991547efSStephan Aßmus 
235991547efSStephan Aßmus 	// diamond
236991547efSStephan Aßmus 	if (ret >= B_OK)
237991547efSStephan Aßmus 		ret = into->AddFloat("diamond_cx", (float)fData.diamond.cx);
238991547efSStephan Aßmus 	if (ret >= B_OK)
239991547efSStephan Aßmus 		ret = into->AddFloat("diamond_cy", (float)fData.diamond.cy);
240991547efSStephan Aßmus 
241991547efSStephan Aßmus 	// conic
242991547efSStephan Aßmus 	if (ret >= B_OK)
243991547efSStephan Aßmus 		ret = into->AddFloat("conic_cx", (float)fData.conic.cx);
244991547efSStephan Aßmus 	if (ret >= B_OK)
245991547efSStephan Aßmus 		ret = into->AddFloat("conic_cy", (float)fData.conic.cy);
246991547efSStephan Aßmus 	if (ret >= B_OK)
247991547efSStephan Aßmus 		ret = into->AddFloat("conic_angle", (float)fData.conic.angle);
248991547efSStephan Aßmus 
249991547efSStephan Aßmus 	// finish off
250991547efSStephan Aßmus 	if (ret >= B_OK)
251991547efSStephan Aßmus 		ret = into->AddString("class", "BGradient");
252991547efSStephan Aßmus 
253991547efSStephan Aßmus 	return ret;
254991547efSStephan Aßmus }
255991547efSStephan Aßmus 
256991547efSStephan Aßmus 
257991547efSStephan Aßmus // operator=
258991547efSStephan Aßmus BGradient&
operator =(const BGradient & other)259991547efSStephan Aßmus BGradient::operator=(const BGradient& other)
260991547efSStephan Aßmus {
2616d9c0146SAdrien Destugues 	if (&other == this)
2626d9c0146SAdrien Destugues 		return *this;
2636d9c0146SAdrien Destugues 
26464eb49fdSStephan Aßmus 	SetColorStops(other);
265991547efSStephan Aßmus 	fType = other.fType;
2666d9c0146SAdrien Destugues 	switch (fType) {
2676d9c0146SAdrien Destugues 		case TYPE_LINEAR:
2686d9c0146SAdrien Destugues 			fData.linear = other.fData.linear;
2696d9c0146SAdrien Destugues 			break;
2706d9c0146SAdrien Destugues 		case TYPE_RADIAL:
2716d9c0146SAdrien Destugues 			fData.radial = other.fData.radial;
2726d9c0146SAdrien Destugues 			break;
2736d9c0146SAdrien Destugues 		case TYPE_RADIAL_FOCUS:
2746d9c0146SAdrien Destugues 			fData.radial_focus = other.fData.radial_focus;
2756d9c0146SAdrien Destugues 			break;
2766d9c0146SAdrien Destugues 		case TYPE_DIAMOND:
2776d9c0146SAdrien Destugues 			fData.diamond = other.fData.diamond;
2786d9c0146SAdrien Destugues 			break;
2796d9c0146SAdrien Destugues 		case TYPE_CONIC:
2806d9c0146SAdrien Destugues 			fData.conic = other.fData.conic;
2816d9c0146SAdrien Destugues 			break;
2826d9c0146SAdrien Destugues 		case TYPE_NONE:
2836d9c0146SAdrien Destugues 			break;
2846d9c0146SAdrien Destugues 	}
285991547efSStephan Aßmus 	return *this;
286991547efSStephan Aßmus }
287991547efSStephan Aßmus 
288991547efSStephan Aßmus 
289991547efSStephan Aßmus // operator==
290991547efSStephan Aßmus bool
operator ==(const BGradient & other) const291991547efSStephan Aßmus BGradient::operator==(const BGradient& other) const
292991547efSStephan Aßmus {
29364eb49fdSStephan Aßmus 	return ((other.GetType() == GetType()) && ColorStopsAreEqual(other));
294991547efSStephan Aßmus }
295991547efSStephan Aßmus 
296991547efSStephan Aßmus 
297991547efSStephan Aßmus // operator!=
298991547efSStephan Aßmus bool
operator !=(const BGradient & other) const299991547efSStephan Aßmus BGradient::operator!=(const BGradient& other) const
300991547efSStephan Aßmus {
301991547efSStephan Aßmus 	return !(*this == other);
302991547efSStephan Aßmus }
303991547efSStephan Aßmus 
304991547efSStephan Aßmus 
30564eb49fdSStephan Aßmus // ColorStopsAreEqual
306991547efSStephan Aßmus bool
ColorStopsAreEqual(const BGradient & other) const30764eb49fdSStephan Aßmus BGradient::ColorStopsAreEqual(const BGradient& other) const
308991547efSStephan Aßmus {
30964eb49fdSStephan Aßmus 	int32 count = CountColorStops();
31064eb49fdSStephan Aßmus 	if (count == other.CountColorStops() &&
311991547efSStephan Aßmus 		fType == other.fType) {
312991547efSStephan Aßmus 
313991547efSStephan Aßmus 		bool equal = true;
314991547efSStephan Aßmus 		for (int32 i = 0; i < count; i++) {
31564eb49fdSStephan Aßmus 			ColorStop* ourStop = ColorStopAtFast(i);
31664eb49fdSStephan Aßmus 			ColorStop* otherStop = other.ColorStopAtFast(i);
31764eb49fdSStephan Aßmus 			if (*ourStop != *otherStop) {
318991547efSStephan Aßmus 				equal = false;
319991547efSStephan Aßmus 				break;
320991547efSStephan Aßmus 			}
321991547efSStephan Aßmus 		}
322991547efSStephan Aßmus 		return equal;
323991547efSStephan Aßmus 	}
324991547efSStephan Aßmus 	return false;
325991547efSStephan Aßmus }
326991547efSStephan Aßmus 
327991547efSStephan Aßmus 
32864eb49fdSStephan Aßmus // SetColorStops
329991547efSStephan Aßmus void
SetColorStops(const BGradient & other)33064eb49fdSStephan Aßmus BGradient::SetColorStops(const BGradient& other)
331991547efSStephan Aßmus {
332991547efSStephan Aßmus 	MakeEmpty();
33364eb49fdSStephan Aßmus 	for (int32 i = 0; ColorStop* stop = other.ColorStopAt(i); i++)
33464eb49fdSStephan Aßmus 		AddColorStop(*stop, i);
335991547efSStephan Aßmus }
336991547efSStephan Aßmus 
337991547efSStephan Aßmus 
338991547efSStephan Aßmus // AddColor
339991547efSStephan Aßmus int32
AddColor(const rgb_color & color,float offset)340991547efSStephan Aßmus BGradient::AddColor(const rgb_color& color, float offset)
341991547efSStephan Aßmus {
342de3e2b51SAdrien Destugues 	// Out of bounds stops would crash the app_server
343de3e2b51SAdrien Destugues 	if (offset < 0.f || offset > 255.f)
344de3e2b51SAdrien Destugues 		return -1;
345de3e2b51SAdrien Destugues 
346991547efSStephan Aßmus 	// find the correct index (sorted by offset)
34764eb49fdSStephan Aßmus 	ColorStop* stop = new ColorStop(color, offset);
348991547efSStephan Aßmus 	int32 index = 0;
34964eb49fdSStephan Aßmus 	int32 count = CountColorStops();
350991547efSStephan Aßmus 	for (; index < count; index++) {
35164eb49fdSStephan Aßmus 		ColorStop* s = ColorStopAtFast(index);
35264eb49fdSStephan Aßmus 		if (s->offset > stop->offset)
353991547efSStephan Aßmus 			break;
354991547efSStephan Aßmus 	}
35564eb49fdSStephan Aßmus 	if (!fColorStops.AddItem((void*)stop, index)) {
35664eb49fdSStephan Aßmus 		delete stop;
357991547efSStephan Aßmus 		return -1;
358991547efSStephan Aßmus 	}
359991547efSStephan Aßmus 	return index;
360991547efSStephan Aßmus }
361991547efSStephan Aßmus 
362991547efSStephan Aßmus 
36364eb49fdSStephan Aßmus // AddColorStop
364991547efSStephan Aßmus bool
AddColorStop(const ColorStop & colorStop,int32 index)36564eb49fdSStephan Aßmus BGradient::AddColorStop(const ColorStop& colorStop, int32 index)
366991547efSStephan Aßmus {
36764eb49fdSStephan Aßmus 	ColorStop* stop = new ColorStop(colorStop);
36864eb49fdSStephan Aßmus 	if (!fColorStops.AddItem((void*)stop, index)) {
36964eb49fdSStephan Aßmus 		delete stop;
370991547efSStephan Aßmus 		return false;
371991547efSStephan Aßmus 	}
372991547efSStephan Aßmus 	return true;
373991547efSStephan Aßmus }
374991547efSStephan Aßmus 
375991547efSStephan Aßmus 
376991547efSStephan Aßmus // RemoveColor
377991547efSStephan Aßmus bool
RemoveColor(int32 index)378991547efSStephan Aßmus BGradient::RemoveColor(int32 index)
379991547efSStephan Aßmus {
38064eb49fdSStephan Aßmus 	ColorStop* stop = (ColorStop*)fColorStops.RemoveItem(index);
38164eb49fdSStephan Aßmus 	if (!stop) {
382991547efSStephan Aßmus 		return false;
383991547efSStephan Aßmus 	}
38464eb49fdSStephan Aßmus 	delete stop;
385991547efSStephan Aßmus 	return true;
386991547efSStephan Aßmus }
387991547efSStephan Aßmus 
388991547efSStephan Aßmus 
38964eb49fdSStephan Aßmus // SetColorStop
390991547efSStephan Aßmus bool
SetColorStop(int32 index,const ColorStop & color)39164eb49fdSStephan Aßmus BGradient::SetColorStop(int32 index, const ColorStop& color)
392991547efSStephan Aßmus {
39364eb49fdSStephan Aßmus 	if (ColorStop* stop = ColorStopAt(index)) {
39464eb49fdSStephan Aßmus 		if (*stop != color) {
39564eb49fdSStephan Aßmus 			stop->color = color.color;
39664eb49fdSStephan Aßmus 			stop->offset = color.offset;
397991547efSStephan Aßmus 			return true;
398991547efSStephan Aßmus 		}
399991547efSStephan Aßmus 	}
400991547efSStephan Aßmus 	return false;
401991547efSStephan Aßmus }
402991547efSStephan Aßmus 
403991547efSStephan Aßmus 
404991547efSStephan Aßmus // SetColor
405991547efSStephan Aßmus bool
SetColor(int32 index,const rgb_color & color)406991547efSStephan Aßmus BGradient::SetColor(int32 index, const rgb_color& color)
407991547efSStephan Aßmus {
40864eb49fdSStephan Aßmus 	ColorStop* stop = ColorStopAt(index);
40964eb49fdSStephan Aßmus 	if (stop && stop->color != color) {
41064eb49fdSStephan Aßmus 		stop->color = color;
411991547efSStephan Aßmus 		return true;
412991547efSStephan Aßmus 	}
413991547efSStephan Aßmus 	return false;
414991547efSStephan Aßmus }
415991547efSStephan Aßmus 
416991547efSStephan Aßmus 
417991547efSStephan Aßmus // SetOffset
418991547efSStephan Aßmus bool
SetOffset(int32 index,float offset)419991547efSStephan Aßmus BGradient::SetOffset(int32 index, float offset)
420991547efSStephan Aßmus {
42164eb49fdSStephan Aßmus 	ColorStop* stop = ColorStopAt(index);
42264eb49fdSStephan Aßmus 	if (stop && stop->offset != offset) {
42364eb49fdSStephan Aßmus 		stop->offset = offset;
424991547efSStephan Aßmus 		return true;
425991547efSStephan Aßmus 	}
426991547efSStephan Aßmus 	return false;
427991547efSStephan Aßmus }
428991547efSStephan Aßmus 
429991547efSStephan Aßmus 
43064eb49fdSStephan Aßmus // CountColorStops
431991547efSStephan Aßmus int32
CountColorStops() const43264eb49fdSStephan Aßmus BGradient::CountColorStops() const
433991547efSStephan Aßmus {
43464eb49fdSStephan Aßmus 	return fColorStops.CountItems();
435991547efSStephan Aßmus }
436991547efSStephan Aßmus 
437991547efSStephan Aßmus 
43864eb49fdSStephan Aßmus // ColorStopAt
43964eb49fdSStephan Aßmus BGradient::ColorStop*
ColorStopAt(int32 index) const44064eb49fdSStephan Aßmus BGradient::ColorStopAt(int32 index) const
441991547efSStephan Aßmus {
44264eb49fdSStephan Aßmus 	return (ColorStop*)fColorStops.ItemAt(index);
443991547efSStephan Aßmus }
444991547efSStephan Aßmus 
445991547efSStephan Aßmus 
44664eb49fdSStephan Aßmus // ColorStopAtFast
44764eb49fdSStephan Aßmus BGradient::ColorStop*
ColorStopAtFast(int32 index) const44864eb49fdSStephan Aßmus BGradient::ColorStopAtFast(int32 index) const
449991547efSStephan Aßmus {
45064eb49fdSStephan Aßmus 	return (ColorStop*)fColorStops.ItemAtFast(index);
451991547efSStephan Aßmus }
452991547efSStephan Aßmus 
453991547efSStephan Aßmus 
45464eb49fdSStephan Aßmus // ColorStops
45564eb49fdSStephan Aßmus BGradient::ColorStop*
ColorStops() const45664eb49fdSStephan Aßmus BGradient::ColorStops() const
457991547efSStephan Aßmus {
45864eb49fdSStephan Aßmus 	if (CountColorStops() > 0) {
45964eb49fdSStephan Aßmus 		return (ColorStop*) fColorStops.Items();
460991547efSStephan Aßmus 	}
461991547efSStephan Aßmus 	return NULL;
462991547efSStephan Aßmus }
463991547efSStephan Aßmus 
464991547efSStephan Aßmus 
46564eb49fdSStephan Aßmus // SortColorStopsByOffset
466991547efSStephan Aßmus void
SortColorStopsByOffset()46764eb49fdSStephan Aßmus BGradient::SortColorStopsByOffset()
468991547efSStephan Aßmus {
46977b60d22SAdrien Destugues 	// Use stable sort: stops with the same offset will retain their original
47077b60d22SAdrien Destugues 	// order. This can be used to have sharp color changes in the gradient.
47177b60d22SAdrien Destugues 	// BList.SortItems() uses qsort(), which isn't stable, and sometimes swaps
4723dfdd437SAdrien Destugues 	// such stops.
47377b60d22SAdrien Destugues 	const BGradient::ColorStop** first = (const BGradient::ColorStop**)fColorStops.Items();
47477b60d22SAdrien Destugues 	const BGradient::ColorStop** last = first + fColorStops.CountItems();
47577b60d22SAdrien Destugues 	std::stable_sort(first, last, sort_color_stops_by_offset);
476991547efSStephan Aßmus }
477991547efSStephan Aßmus 
478991547efSStephan Aßmus 
479991547efSStephan Aßmus // MakeEmpty
480991547efSStephan Aßmus void
MakeEmpty()481991547efSStephan Aßmus BGradient::MakeEmpty()
482991547efSStephan Aßmus {
48364eb49fdSStephan Aßmus 	int32 count = CountColorStops();
484991547efSStephan Aßmus 	for (int32 i = 0; i < count; i++)
48564eb49fdSStephan Aßmus 		delete ColorStopAtFast(i);
48664eb49fdSStephan Aßmus 	fColorStops.MakeEmpty();
487991547efSStephan Aßmus }
48836ef16bfSX512 
48936ef16bfSX512 
49036ef16bfSX512 status_t
Flatten(BDataIO * stream) const49136ef16bfSX512 BGradient::Flatten(BDataIO* stream) const
49236ef16bfSX512 {
49336ef16bfSX512 	int32 stopCount = CountColorStops();
49436ef16bfSX512 	stream->Write(&fType, sizeof(Type));
49536ef16bfSX512 	stream->Write(&stopCount, sizeof(int32));
49636ef16bfSX512 	if (stopCount > 0) {
49736ef16bfSX512 		for (int i = 0; i < stopCount; i++) {
49836ef16bfSX512 			stream->Write(ColorStopAtFast(i),
49936ef16bfSX512 				sizeof(ColorStop));
50036ef16bfSX512 		}
50136ef16bfSX512 	}
50236ef16bfSX512 
50336ef16bfSX512 	switch (fType) {
50436ef16bfSX512 		case TYPE_LINEAR:
50536ef16bfSX512 			stream->Write(&fData.linear.x1, sizeof(float));
50636ef16bfSX512 			stream->Write(&fData.linear.y1, sizeof(float));
50736ef16bfSX512 			stream->Write(&fData.linear.x2, sizeof(float));
50836ef16bfSX512 			stream->Write(&fData.linear.y2, sizeof(float));
50936ef16bfSX512 			break;
51036ef16bfSX512 		case TYPE_RADIAL:
51136ef16bfSX512 			stream->Write(&fData.radial.cx, sizeof(float));
51236ef16bfSX512 			stream->Write(&fData.radial.cy, sizeof(float));
51336ef16bfSX512 			stream->Write(&fData.radial.radius, sizeof(float));
51436ef16bfSX512 			break;
51536ef16bfSX512 		case TYPE_RADIAL_FOCUS:
51636ef16bfSX512 			stream->Write(&fData.radial_focus.cx, sizeof(float));
51736ef16bfSX512 			stream->Write(&fData.radial_focus.cy, sizeof(float));
51836ef16bfSX512 			stream->Write(&fData.radial_focus.fx, sizeof(float));
51936ef16bfSX512 			stream->Write(&fData.radial_focus.fy, sizeof(float));
52036ef16bfSX512 			stream->Write(&fData.radial_focus.radius, sizeof(float));
52136ef16bfSX512 			break;
52236ef16bfSX512 		case TYPE_DIAMOND:
52336ef16bfSX512 			stream->Write(&fData.diamond.cx, sizeof(float));
52436ef16bfSX512 			stream->Write(&fData.diamond.cy, sizeof(float));
52536ef16bfSX512 			break;
52636ef16bfSX512 		case TYPE_CONIC:
52736ef16bfSX512 			stream->Write(&fData.conic.cx, sizeof(float));
52836ef16bfSX512 			stream->Write(&fData.conic.cy, sizeof(float));
52936ef16bfSX512 			stream->Write(&fData.conic.angle, sizeof(float));
53036ef16bfSX512 			break;
53136ef16bfSX512 		case TYPE_NONE:
53236ef16bfSX512 			break;
53336ef16bfSX512 	}
53436ef16bfSX512 	return B_OK;
53536ef16bfSX512 }
53636ef16bfSX512 
53736ef16bfSX512 
53836ef16bfSX512 static BGradient*
gradient_for_type(BGradient::Type type)53936ef16bfSX512 gradient_for_type(BGradient::Type type)
54036ef16bfSX512 {
54136ef16bfSX512 	switch (type) {
54236ef16bfSX512 		case BGradient::TYPE_LINEAR:
54336ef16bfSX512 			return new (std::nothrow) BGradientLinear();
54436ef16bfSX512 		case BGradient::TYPE_RADIAL:
54536ef16bfSX512 			return new (std::nothrow) BGradientRadial();
54636ef16bfSX512 		case BGradient::TYPE_RADIAL_FOCUS:
54736ef16bfSX512 			return new (std::nothrow) BGradientRadialFocus();
54836ef16bfSX512 		case BGradient::TYPE_DIAMOND:
54936ef16bfSX512 			return new (std::nothrow) BGradientDiamond();
55036ef16bfSX512 		case BGradient::TYPE_CONIC:
55136ef16bfSX512 			return new (std::nothrow) BGradientConic();
55236ef16bfSX512 		case BGradient::TYPE_NONE:
55336ef16bfSX512 			return new (std::nothrow) BGradient();
55436ef16bfSX512 	}
55536ef16bfSX512 	return NULL;
55636ef16bfSX512 }
55736ef16bfSX512 
55836ef16bfSX512 
55936ef16bfSX512 status_t
Unflatten(BGradient * & output,BDataIO * stream)56036ef16bfSX512 BGradient::Unflatten(BGradient *&output, BDataIO* stream)
56136ef16bfSX512 {
56236ef16bfSX512 	output = NULL;
56336ef16bfSX512 	Type gradientType;
56436ef16bfSX512 	int32 colorsCount;
56536ef16bfSX512 	stream->Read(&gradientType, sizeof(Type));
56636ef16bfSX512 	status_t status = stream->Read(&colorsCount, sizeof(int32));
56736ef16bfSX512 	if (status < B_OK)
56836ef16bfSX512 		return status;
56936ef16bfSX512 
57036ef16bfSX512 	ObjectDeleter<BGradient> gradient(gradient_for_type(gradientType));
571*779ab335SX512 	if (!gradient.IsSet())
57236ef16bfSX512 		return B_NO_MEMORY;
57336ef16bfSX512 
57436ef16bfSX512 	if (colorsCount > 0) {
57536ef16bfSX512 		ColorStop stop;
57636ef16bfSX512 		for (int i = 0; i < colorsCount; i++) {
57736ef16bfSX512 			if ((status = stream->Read(&stop, sizeof(ColorStop))) < B_OK)
57836ef16bfSX512 				return status;
57936ef16bfSX512 			if (!gradient->AddColorStop(stop, i))
58036ef16bfSX512 				return B_NO_MEMORY;
58136ef16bfSX512 		}
58236ef16bfSX512 	}
58336ef16bfSX512 
58436ef16bfSX512 	switch (gradientType) {
58536ef16bfSX512 		case TYPE_LINEAR:
58636ef16bfSX512 			stream->Read(&gradient->fData.linear.x1, sizeof(float));
58736ef16bfSX512 			stream->Read(&gradient->fData.linear.y1, sizeof(float));
58836ef16bfSX512 			stream->Read(&gradient->fData.linear.x2, sizeof(float));
58936ef16bfSX512 			if ((status = stream->Read(&gradient->fData.linear.y2, sizeof(float))) < B_OK)
59036ef16bfSX512 				return status;
59136ef16bfSX512 			break;
59236ef16bfSX512 		case TYPE_RADIAL:
59336ef16bfSX512 			stream->Read(&gradient->fData.radial.cx, sizeof(float));
59436ef16bfSX512 			stream->Read(&gradient->fData.radial.cy, sizeof(float));
59536ef16bfSX512 			if ((stream->Read(&gradient->fData.radial.radius, sizeof(float))) < B_OK)
59636ef16bfSX512 				return status;
59736ef16bfSX512 			break;
59836ef16bfSX512 		case TYPE_RADIAL_FOCUS:
59936ef16bfSX512 			stream->Read(&gradient->fData.radial_focus.cx, sizeof(float));
60036ef16bfSX512 			stream->Read(&gradient->fData.radial_focus.cy, sizeof(float));
60136ef16bfSX512 			stream->Read(&gradient->fData.radial_focus.fx, sizeof(float));
60236ef16bfSX512 			stream->Read(&gradient->fData.radial_focus.fy, sizeof(float));
60336ef16bfSX512 			if ((stream->Read(&gradient->fData.radial_focus.radius, sizeof(float))) < B_OK)
60436ef16bfSX512 				return status;
60536ef16bfSX512 			break;
60636ef16bfSX512 		case TYPE_DIAMOND:
60736ef16bfSX512 			stream->Read(&gradient->fData.diamond.cx, sizeof(float));
60836ef16bfSX512 			if ((stream->Read(&gradient->fData.diamond.cy, sizeof(float))) < B_OK)
60936ef16bfSX512 				return status;
61036ef16bfSX512 			break;
61136ef16bfSX512 		case TYPE_CONIC:
61236ef16bfSX512 			stream->Read(&gradient->fData.conic.cx, sizeof(float));
61336ef16bfSX512 			stream->Read(&gradient->fData.conic.cy, sizeof(float));
61436ef16bfSX512 			if ((stream->Read(&gradient->fData.conic.angle, sizeof(float))) < B_OK)
61536ef16bfSX512 				return status;
61636ef16bfSX512 			break;
61736ef16bfSX512 		case TYPE_NONE:
61836ef16bfSX512 			break;
61936ef16bfSX512 	}
62036ef16bfSX512 
62136ef16bfSX512 	output = gradient.Detach();
62236ef16bfSX512 	return B_OK;
62336ef16bfSX512 }
624