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