1 /* 2 * Copyright 2006, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "Shape.h" 10 11 #include <Message.h> 12 #include <TypeConstants.h> 13 14 #include <new> 15 #include <limits.h> 16 #include <stdio.h> 17 18 #include "agg_bounding_rect.h" 19 20 #ifdef ICON_O_MATIC 21 # include "CommonPropertyIDs.h" 22 # include "Property.h" 23 # include "PropertyObject.h" 24 #endif // ICON_O_MATIC 25 #include "Style.h" 26 #include "TransformerFactory.h" 27 28 using std::nothrow; 29 30 31 #ifdef ICON_O_MATIC 32 ShapeListener::ShapeListener() 33 { 34 } 35 36 37 ShapeListener::~ShapeListener() 38 { 39 } 40 #endif // ICON_O_MATIC 41 42 43 // #pragma mark - 44 45 46 Shape::Shape(::Style* style) 47 #ifdef ICON_O_MATIC 48 : IconObject("<shape>"), 49 Transformable(), 50 Observer(), 51 PathContainerListener(), 52 #else 53 : Transformable(), 54 #endif 55 56 fPaths(new (nothrow) PathContainer(false)), 57 fStyle(NULL), 58 59 fPathSource(fPaths), 60 fTransformers(4), 61 fNeedsUpdate(true), 62 63 fLastBounds(0, 0, -1, -1), 64 65 fHinting(false) 66 67 #ifdef ICON_O_MATIC 68 , fListeners(8) 69 #endif 70 { 71 SetStyle(style); 72 73 #ifdef ICON_O_MATIC 74 if (fPaths) 75 fPaths->AddListener(this); 76 #endif 77 } 78 79 80 Shape::Shape(const Shape& other) 81 #ifdef ICON_O_MATIC 82 : IconObject(other), 83 Transformable(other), 84 Observer(), 85 PathContainerListener(), 86 #else 87 : Transformable(other), 88 #endif 89 90 fPaths(new (nothrow) PathContainer(false)), 91 fStyle(NULL), 92 93 fPathSource(fPaths), 94 fTransformers(4), 95 fNeedsUpdate(true), 96 97 fLastBounds(0, 0, -1, -1), 98 99 fHinting(false) 100 101 #ifdef ICON_O_MATIC 102 , fListeners(8) 103 #endif 104 { 105 SetStyle(other.fStyle); 106 107 if (fPaths) { 108 #ifdef ICON_O_MATIC 109 fPaths->AddListener(this); 110 #endif 111 112 // copy the path references from 113 // the other shape 114 if (other.fPaths) { 115 int32 count = other.fPaths->CountPaths(); 116 for (int32 i = 0; i < count; i++) { 117 if (!fPaths->AddPath(other.fPaths->PathAtFast(i))) 118 break; 119 } 120 } 121 } 122 // clone vertex transformers 123 int32 count = other.CountTransformers(); 124 for (int32 i = 0; i < count; i++) { 125 Transformer* original = other.TransformerAtFast(i); 126 Transformer* cloned = original->Clone(fPathSource); 127 if (!AddTransformer(cloned)) { 128 delete cloned; 129 break; 130 } 131 } 132 } 133 134 135 Shape::~Shape() 136 { 137 int32 count = fTransformers.CountItems(); 138 for (int32 i = 0; i < count; i++) { 139 Transformer* t = (Transformer*)fTransformers.ItemAtFast(i); 140 #ifdef ICON_O_MATIC 141 t->RemoveObserver(this); 142 _NotifyTransformerRemoved(t); 143 #endif 144 delete t; 145 } 146 147 fPaths->MakeEmpty(); 148 #ifdef ICON_O_MATIC 149 fPaths->RemoveListener(this); 150 #endif 151 delete fPaths; 152 153 SetStyle(NULL); 154 } 155 156 157 // #pragma mark - 158 159 160 status_t 161 Shape::Unarchive(BMessage* archive) 162 { 163 #ifdef ICON_O_MATIC 164 // IconObject properties 165 status_t ret = IconObject::Unarchive(archive); 166 if (ret < B_OK) 167 return ret; 168 #else 169 status_t ret; 170 #endif 171 172 // hinting 173 if (archive->FindBool("hinting", &fHinting) < B_OK) 174 fHinting = false; 175 176 // recreate transformers 177 BMessage transformerArchive; 178 for (int32 i = 0; 179 archive->FindMessage("transformer", i, 180 &transformerArchive) == B_OK; 181 i++) { 182 Transformer* transformer 183 = TransformerFactory::TransformerFor( 184 &transformerArchive, VertexSource()); 185 if (!transformer || !AddTransformer(transformer)) { 186 delete transformer; 187 } 188 } 189 190 // read transformation 191 int32 size = Transformable::matrix_size; 192 const void* matrix; 193 ssize_t dataSize = size * sizeof(double); 194 ret = archive->FindData("transformation", B_DOUBLE_TYPE, 195 &matrix, &dataSize); 196 if (ret == B_OK && dataSize == (ssize_t)(size * sizeof(double))) 197 LoadFrom((const double*)matrix); 198 199 return B_OK; 200 } 201 202 203 #ifdef ICON_O_MATIC 204 status_t 205 Shape::Archive(BMessage* into, bool deep) const 206 { 207 status_t ret = IconObject::Archive(into, deep); 208 209 // hinting 210 if (ret == B_OK) 211 ret = into->AddBool("hinting", fHinting); 212 213 // transformers 214 if (ret == B_OK) { 215 int32 count = CountTransformers(); 216 for (int32 i = 0; i < count; i++) { 217 Transformer* transformer = TransformerAtFast(i); 218 BMessage transformerArchive; 219 ret = transformer->Archive(&transformerArchive); 220 if (ret == B_OK) 221 ret = into->AddMessage("transformer", &transformerArchive); 222 if (ret < B_OK) 223 break; 224 } 225 } 226 227 // transformation 228 if (ret == B_OK) { 229 int32 size = Transformable::matrix_size; 230 double matrix[size]; 231 StoreTo(matrix); 232 ret = into->AddData("transformation", B_DOUBLE_TYPE, 233 matrix, size * sizeof(double)); 234 } 235 236 return ret; 237 } 238 239 240 PropertyObject* 241 Shape::MakePropertyObject() const 242 { 243 PropertyObject* object = IconObject::MakePropertyObject(); 244 return object; 245 } 246 247 248 bool 249 Shape::SetToPropertyObject(const PropertyObject* object) 250 { 251 IconObject::SetToPropertyObject(object); 252 return true; 253 } 254 255 256 // #pragma mark - 257 258 259 void 260 Shape::TransformationChanged() 261 { 262 // TODO: notify appearance change 263 _NotifyRerender(); 264 } 265 266 267 // #pragma mark - 268 269 270 void 271 Shape::ObjectChanged(const Observable* object) 272 { 273 // simply pass on the event for now 274 // (a path, transformer or the style changed, 275 // the shape needs to be re-rendered) 276 _NotifyRerender(); 277 } 278 279 280 // #pragma mark - 281 282 283 void 284 Shape::PathAdded(VectorPath* path, int32 index) 285 { 286 path->AcquireReference(); 287 path->AddListener(this); 288 _NotifyRerender(); 289 } 290 291 292 void 293 Shape::PathRemoved(VectorPath* path) 294 { 295 path->RemoveListener(this); 296 _NotifyRerender(); 297 path->ReleaseReference(); 298 } 299 300 301 // #pragma mark - 302 303 304 void 305 Shape::PointAdded(int32 index) 306 { 307 _NotifyRerender(); 308 } 309 310 311 void 312 Shape::PointRemoved(int32 index) 313 { 314 _NotifyRerender(); 315 } 316 317 318 void 319 Shape::PointChanged(int32 index) 320 { 321 _NotifyRerender(); 322 } 323 324 325 void 326 Shape::PathChanged() 327 { 328 _NotifyRerender(); 329 } 330 331 332 void 333 Shape::PathClosedChanged() 334 { 335 _NotifyRerender(); 336 } 337 338 339 void 340 Shape::PathReversed() 341 { 342 _NotifyRerender(); 343 } 344 #endif // ICON_O_MATIC 345 346 347 // #pragma mark - 348 349 350 status_t 351 Shape::InitCheck() const 352 { 353 return fPaths ? B_OK : B_NO_MEMORY; 354 } 355 356 357 // #pragma mark - 358 359 360 void 361 Shape::SetStyle(::Style* style) 362 { 363 if (fStyle == style) 364 return; 365 366 #ifdef ICON_O_MATIC 367 if (fStyle) { 368 fStyle->RemoveObserver(this); 369 fStyle->ReleaseReference(); 370 } 371 ::Style* oldStyle = fStyle; 372 #endif 373 374 fStyle = style; 375 376 #ifdef ICON_O_MATIC 377 if (fStyle) { 378 fStyle->AcquireReference(); 379 fStyle->AddObserver(this); 380 } 381 382 _NotifyStyleChanged(oldStyle, fStyle); 383 #endif 384 } 385 386 387 // #pragma mark - 388 389 390 BRect 391 Shape::Bounds(bool updateLast) const 392 { 393 // TODO: what about sub-paths?!? 394 // the problem is that the path ids are 395 // nowhere stored while converting VectorPath 396 // to agg::path_storage, but it is also unclear 397 // if those would mean anything later on in 398 // the Transformer pipeline 399 uint32 pathID[1]; 400 pathID[0] = 0; 401 double left, top, right, bottom; 402 403 ::VertexSource& source = const_cast<Shape*>(this)->VertexSource(); 404 agg::conv_transform< ::VertexSource, Transformable> 405 transformedSource(source, *this); 406 agg::bounding_rect(transformedSource, pathID, 0, 1, 407 &left, &top, &right, &bottom); 408 409 BRect bounds(left, top, right, bottom); 410 411 if (updateLast) 412 fLastBounds = bounds; 413 414 return bounds; 415 } 416 417 418 ::VertexSource& 419 Shape::VertexSource() 420 { 421 ::VertexSource* source = &fPathSource; 422 423 int32 count = fTransformers.CountItems(); 424 for (int32 i = 0; i < count; i++) { 425 Transformer* t = (Transformer*)fTransformers.ItemAtFast(i); 426 t->SetSource(*source); 427 source = t; 428 } 429 430 if (fNeedsUpdate) { 431 fPathSource.Update(source->WantsOpenPaths(), 432 source->ApproximationScale()); 433 fNeedsUpdate = false; 434 } 435 436 return *source; 437 } 438 439 440 void 441 Shape::SetGlobalScale(double scale) 442 { 443 fPathSource.SetGlobalScale(scale); 444 } 445 446 447 bool 448 Shape::AddTransformer(Transformer* transformer) 449 { 450 return AddTransformer(transformer, CountTransformers()); 451 } 452 453 454 bool 455 Shape::AddTransformer(Transformer* transformer, int32 index) 456 { 457 if (!transformer) 458 return false; 459 460 if (!fTransformers.AddItem((void*)transformer, index)) 461 return false; 462 463 #ifdef ICON_O_MATIC 464 transformer->AddObserver(this); 465 466 _NotifyTransformerAdded(transformer, index); 467 #else 468 fNeedsUpdate = true; 469 #endif 470 return true; 471 } 472 473 474 bool 475 Shape::RemoveTransformer(Transformer* transformer) 476 { 477 if (fTransformers.RemoveItem((void*)transformer)) { 478 #ifdef ICON_O_MATIC 479 transformer->RemoveObserver(this); 480 481 _NotifyTransformerRemoved(transformer); 482 #else 483 fNeedsUpdate = true; 484 #endif 485 return true; 486 } 487 488 return false; 489 } 490 491 492 // #pragma mark - 493 494 495 int32 496 Shape::CountTransformers() const 497 { 498 return fTransformers.CountItems(); 499 } 500 501 502 bool 503 Shape::HasTransformer(Transformer* transformer) const 504 { 505 return fTransformers.HasItem((void*)transformer); 506 } 507 508 509 int32 510 Shape::IndexOf(Transformer* transformer) const 511 { 512 return fTransformers.IndexOf((void*)transformer); 513 } 514 515 516 Transformer* 517 Shape::TransformerAt(int32 index) const 518 { 519 return (Transformer*)fTransformers.ItemAt(index); 520 } 521 522 523 Transformer* 524 Shape::TransformerAtFast(int32 index) const 525 { 526 return (Transformer*)fTransformers.ItemAtFast(index); 527 } 528 529 530 // #pragma mark - 531 532 533 #ifdef ICON_O_MATIC 534 bool 535 Shape::AddListener(ShapeListener* listener) 536 { 537 if (listener && !fListeners.HasItem((void*)listener)) 538 return fListeners.AddItem((void*)listener); 539 return false; 540 } 541 542 543 bool 544 Shape::RemoveListener(ShapeListener* listener) 545 { 546 return fListeners.RemoveItem((void*)listener); 547 } 548 549 550 // #pragma mark - 551 552 553 void 554 Shape::_NotifyTransformerAdded(Transformer* transformer, int32 index) const 555 { 556 BList listeners(fListeners); 557 int32 count = listeners.CountItems(); 558 for (int32 i = 0; i < count; i++) { 559 ShapeListener* listener 560 = (ShapeListener*)listeners.ItemAtFast(i); 561 listener->TransformerAdded(transformer, index); 562 } 563 // TODO: merge Observable and ShapeListener interface 564 _NotifyRerender(); 565 } 566 567 568 void 569 Shape::_NotifyTransformerRemoved(Transformer* transformer) const 570 { 571 BList listeners(fListeners); 572 int32 count = listeners.CountItems(); 573 for (int32 i = 0; i < count; i++) { 574 ShapeListener* listener 575 = (ShapeListener*)listeners.ItemAtFast(i); 576 listener->TransformerRemoved(transformer); 577 } 578 // TODO: merge Observable and ShapeListener interface 579 _NotifyRerender(); 580 } 581 582 583 void 584 Shape::_NotifyStyleChanged(::Style* oldStyle, ::Style* newStyle) const 585 { 586 BList listeners(fListeners); 587 int32 count = listeners.CountItems(); 588 for (int32 i = 0; i < count; i++) { 589 ShapeListener* listener 590 = (ShapeListener*)listeners.ItemAtFast(i); 591 listener->StyleChanged(oldStyle, newStyle); 592 } 593 // TODO: merge Observable and ShapeListener interface 594 _NotifyRerender(); 595 } 596 597 598 void 599 Shape::_NotifyRerender() const 600 { 601 fNeedsUpdate = true; 602 Notify(); 603 } 604 #endif // ICON_O_MATIC 605 606 607 void 608 Shape::SetHinting(bool hinting) 609 { 610 if (fHinting == hinting) 611 return; 612 613 fHinting = hinting; 614 Notify(); 615 } 616 617