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