1 /* 2 * Copyright 2006-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 * Artur Wyszynski <harakash@gmail.com> 8 */ 9 10 #include "Gradient.h" 11 12 #include <math.h> 13 #include <stdio.h> 14 15 #include <Message.h> 16 17 18 // constructor 19 BGradient::ColorStop::ColorStop(const rgb_color c, float o) 20 { 21 color.red = c.red; 22 color.green = c.green; 23 color.blue = c.blue; 24 color.alpha = c.alpha; 25 offset = o; 26 } 27 28 29 // constructor 30 BGradient::ColorStop::ColorStop(uint8 r, uint8 g, uint8 b, uint8 a, float o) 31 { 32 color.red = r; 33 color.green = g; 34 color.blue = b; 35 color.alpha = a; 36 offset = o; 37 } 38 39 40 // constructor 41 BGradient::ColorStop::ColorStop(const ColorStop& other) 42 { 43 color.red = other.color.red; 44 color.green = other.color.green; 45 color.blue = other.color.blue; 46 color.alpha = other.color.alpha; 47 offset = other.offset; 48 } 49 50 51 // constructor 52 BGradient::ColorStop::ColorStop() 53 { 54 color.red = 0; 55 color.green = 0; 56 color.blue = 0; 57 color.alpha = 255; 58 offset = 0; 59 } 60 61 62 // operator!= 63 bool 64 BGradient::ColorStop::operator!=(const ColorStop& other) const 65 { 66 return color.red != other.color.red || 67 color.green != other.color.green || 68 color.blue != other.color.blue || 69 color.alpha != other.color.alpha || 70 offset != other.offset; 71 } 72 73 74 static int 75 sort_color_stops_by_offset(const void* _left, const void* _right) 76 { 77 const BGradient::ColorStop** left = (const BGradient::ColorStop**)_left; 78 const BGradient::ColorStop** right = (const BGradient::ColorStop**)_right; 79 if ((*left)->offset > (*right)->offset) 80 return 1; 81 else if ((*left)->offset < (*right)->offset) 82 return -1; 83 return 0; 84 } 85 86 87 // #pragma mark - 88 89 90 // constructor 91 BGradient::BGradient() 92 : BArchivable(), 93 fColorStops(4), 94 fType(TYPE_NONE) 95 { 96 } 97 98 99 // constructor 100 BGradient::BGradient(BMessage* archive) 101 : BArchivable(archive), 102 fColorStops(4), 103 fType(TYPE_NONE) 104 { 105 if (!archive) 106 return; 107 108 // color stops 109 ColorStop stop; 110 for (int32 i = 0; archive->FindFloat("offset", i, &stop.offset) >= B_OK; i++) { 111 if (archive->FindInt32("color", i, (int32*)&stop.color) >= B_OK) 112 AddColorStop(stop, i); 113 else 114 break; 115 } 116 if (archive->FindInt32("type", (int32*)&fType) < B_OK) 117 fType = TYPE_LINEAR; 118 119 // linear 120 if (archive->FindFloat("linear_x1", (float*)&fData.linear.x1) < B_OK) 121 fData.linear.x1 = 0.0f; 122 if (archive->FindFloat("linear_y1", (float*)&fData.linear.y1) < B_OK) 123 fData.linear.y1 = 0.0f; 124 if (archive->FindFloat("linear_x2", (float*)&fData.linear.x2) < B_OK) 125 fData.linear.x2 = 0.0f; 126 if (archive->FindFloat("linear_y2", (float*)&fData.linear.y2) < B_OK) 127 fData.linear.y2 = 0.0f; 128 129 // radial 130 if (archive->FindFloat("radial_cx", (float*)&fData.radial.cx) < B_OK) 131 fData.radial.cx = 0.0f; 132 if (archive->FindFloat("radial_cy", (float*)&fData.radial.cy) < B_OK) 133 fData.radial.cy = 0.0f; 134 if (archive->FindFloat("radial_radius", (float*)&fData.radial.radius) < B_OK) 135 fData.radial.radius = 0.0f; 136 137 // radial focus 138 if (archive->FindFloat("radial_f_cx", (float*)&fData.radial_focus.cx) < B_OK) 139 fData.radial_focus.cx = 0.0f; 140 if (archive->FindFloat("radial_f_cy", (float*)&fData.radial_focus.cy) < B_OK) 141 fData.radial_focus.cy = 0.0f; 142 if (archive->FindFloat("radial_f_fx", (float*)&fData.radial_focus.fx) < B_OK) 143 fData.radial_focus.fx = 0.0f; 144 if (archive->FindFloat("radial_f_fy", (float*)&fData.radial_focus.fy) < B_OK) 145 fData.radial_focus.fy = 0.0f; 146 if (archive->FindFloat("radial_f_radius", (float*)&fData.radial_focus.radius) < B_OK) 147 fData.radial_focus.radius = 0.0f; 148 149 // diamond 150 if (archive->FindFloat("diamond_cx", (float*)&fData.diamond.cx) < B_OK) 151 fData.diamond.cx = 0.0f; 152 if (archive->FindFloat("diamond_cy", (float*)&fData.diamond.cy) < B_OK) 153 fData.diamond.cy = 0.0f; 154 155 // conic 156 if (archive->FindFloat("conic_cx", (float*)&fData.conic.cx) < B_OK) 157 fData.conic.cx = 0.0f; 158 if (archive->FindFloat("conic_cy", (float*)&fData.conic.cy) < B_OK) 159 fData.conic.cy = 0.0f; 160 if (archive->FindFloat("conic_angle", (float*)&fData.conic.angle) < B_OK) 161 fData.conic.angle = 0.0f; 162 } 163 164 165 // destructor 166 BGradient::~BGradient() 167 { 168 MakeEmpty(); 169 } 170 171 172 // Archive 173 status_t 174 BGradient::Archive(BMessage* into, bool deep) const 175 { 176 status_t ret = BArchivable::Archive(into, deep); 177 178 // color steps 179 if (ret >= B_OK) { 180 for (int32 i = 0; ColorStop* stop = ColorStopAt(i); i++) { 181 ret = into->AddInt32("color", (const uint32&)stop->color); 182 if (ret < B_OK) 183 break; 184 ret = into->AddFloat("offset", stop->offset); 185 if (ret < B_OK) 186 break; 187 } 188 } 189 // gradient type 190 if (ret >= B_OK) 191 ret = into->AddInt32("type", (int32)fType); 192 193 // linear 194 if (ret >= B_OK) 195 ret = into->AddFloat("linear_x1", (float)fData.linear.x1); 196 if (ret >= B_OK) 197 ret = into->AddFloat("linear_y1", (float)fData.linear.y1); 198 if (ret >= B_OK) 199 ret = into->AddFloat("linear_x2", (float)fData.linear.x2); 200 if (ret >= B_OK) 201 ret = into->AddFloat("linear_y2", (float)fData.linear.y2); 202 203 // radial 204 if (ret >= B_OK) 205 ret = into->AddFloat("radial_cx", (float)fData.radial.cx); 206 if (ret >= B_OK) 207 ret = into->AddFloat("radial_cy", (float)fData.radial.cy); 208 if (ret >= B_OK) 209 ret = into->AddFloat("radial_radius", (float)fData.radial.radius); 210 211 // radial focus 212 if (ret >= B_OK) 213 ret = into->AddFloat("radial_f_cx", (float)fData.radial_focus.cx); 214 if (ret >= B_OK) 215 ret = into->AddFloat("radial_f_cy", (float)fData.radial_focus.cy); 216 if (ret >= B_OK) 217 ret = into->AddFloat("radial_f_fx", (float)fData.radial_focus.fx); 218 if (ret >= B_OK) 219 ret = into->AddFloat("radial_f_fy", (float)fData.radial_focus.fy); 220 if (ret >= B_OK) 221 ret = into->AddFloat("radial_f_radius", (float)fData.radial_focus.radius); 222 223 // diamond 224 if (ret >= B_OK) 225 ret = into->AddFloat("diamond_cx", (float)fData.diamond.cx); 226 if (ret >= B_OK) 227 ret = into->AddFloat("diamond_cy", (float)fData.diamond.cy); 228 229 // conic 230 if (ret >= B_OK) 231 ret = into->AddFloat("conic_cx", (float)fData.conic.cx); 232 if (ret >= B_OK) 233 ret = into->AddFloat("conic_cy", (float)fData.conic.cy); 234 if (ret >= B_OK) 235 ret = into->AddFloat("conic_angle", (float)fData.conic.angle); 236 237 // finish off 238 if (ret >= B_OK) 239 ret = into->AddString("class", "BGradient"); 240 241 return ret; 242 } 243 244 245 // operator= 246 BGradient& 247 BGradient::operator=(const BGradient& other) 248 { 249 SetColorStops(other); 250 fType = other.fType; 251 return *this; 252 } 253 254 255 // operator== 256 bool 257 BGradient::operator==(const BGradient& other) const 258 { 259 return ((other.GetType() == GetType()) && ColorStopsAreEqual(other)); 260 } 261 262 263 // operator!= 264 bool 265 BGradient::operator!=(const BGradient& other) const 266 { 267 return !(*this == other); 268 } 269 270 271 // ColorStopsAreEqual 272 bool 273 BGradient::ColorStopsAreEqual(const BGradient& other) const 274 { 275 int32 count = CountColorStops(); 276 if (count == other.CountColorStops() && 277 fType == other.fType) { 278 279 bool equal = true; 280 for (int32 i = 0; i < count; i++) { 281 ColorStop* ourStop = ColorStopAtFast(i); 282 ColorStop* otherStop = other.ColorStopAtFast(i); 283 if (*ourStop != *otherStop) { 284 equal = false; 285 break; 286 } 287 } 288 return equal; 289 } 290 return false; 291 } 292 293 294 // SetColorStops 295 void 296 BGradient::SetColorStops(const BGradient& other) 297 { 298 MakeEmpty(); 299 for (int32 i = 0; ColorStop* stop = other.ColorStopAt(i); i++) 300 AddColorStop(*stop, i); 301 } 302 303 304 // AddColor 305 int32 306 BGradient::AddColor(const rgb_color& color, float offset) 307 { 308 // find the correct index (sorted by offset) 309 ColorStop* stop = new ColorStop(color, offset); 310 int32 index = 0; 311 int32 count = CountColorStops(); 312 for (; index < count; index++) { 313 ColorStop* s = ColorStopAtFast(index); 314 if (s->offset > stop->offset) 315 break; 316 } 317 if (!fColorStops.AddItem((void*)stop, index)) { 318 delete stop; 319 return -1; 320 } 321 return index; 322 } 323 324 325 // AddColorStop 326 bool 327 BGradient::AddColorStop(const ColorStop& colorStop, int32 index) 328 { 329 ColorStop* stop = new ColorStop(colorStop); 330 if (!fColorStops.AddItem((void*)stop, index)) { 331 delete stop; 332 return false; 333 } 334 return true; 335 } 336 337 338 // RemoveColor 339 bool 340 BGradient::RemoveColor(int32 index) 341 { 342 ColorStop* stop = (ColorStop*)fColorStops.RemoveItem(index); 343 if (!stop) { 344 return false; 345 } 346 delete stop; 347 return true; 348 } 349 350 351 // SetColorStop 352 bool 353 BGradient::SetColorStop(int32 index, const ColorStop& color) 354 { 355 if (ColorStop* stop = ColorStopAt(index)) { 356 if (*stop != color) { 357 stop->color = color.color; 358 stop->offset = color.offset; 359 return true; 360 } 361 } 362 return false; 363 } 364 365 366 // SetColor 367 bool 368 BGradient::SetColor(int32 index, const rgb_color& color) 369 { 370 ColorStop* stop = ColorStopAt(index); 371 if (stop && stop->color != color) { 372 stop->color = color; 373 return true; 374 } 375 return false; 376 } 377 378 379 // SetOffset 380 bool 381 BGradient::SetOffset(int32 index, float offset) 382 { 383 ColorStop* stop = ColorStopAt(index); 384 if (stop && stop->offset != offset) { 385 stop->offset = offset; 386 return true; 387 } 388 return false; 389 } 390 391 392 // CountColorStops 393 int32 394 BGradient::CountColorStops() const 395 { 396 return fColorStops.CountItems(); 397 } 398 399 400 // ColorStopAt 401 BGradient::ColorStop* 402 BGradient::ColorStopAt(int32 index) const 403 { 404 return (ColorStop*)fColorStops.ItemAt(index); 405 } 406 407 408 // ColorStopAtFast 409 BGradient::ColorStop* 410 BGradient::ColorStopAtFast(int32 index) const 411 { 412 return (ColorStop*)fColorStops.ItemAtFast(index); 413 } 414 415 416 // ColorStops 417 BGradient::ColorStop* 418 BGradient::ColorStops() const 419 { 420 if (CountColorStops() > 0) { 421 return (ColorStop*) fColorStops.Items(); 422 } 423 return NULL; 424 } 425 426 427 // SortColorStopsByOffset 428 void 429 BGradient::SortColorStopsByOffset() 430 { 431 fColorStops.SortItems(sort_color_stops_by_offset); 432 } 433 434 435 // MakeEmpty 436 void 437 BGradient::MakeEmpty() 438 { 439 int32 count = CountColorStops(); 440 for (int32 i = 0; i < count; i++) 441 delete ColorStopAtFast(i); 442 fColorStops.MakeEmpty(); 443 } 444