1/* 2 * Copyright 2006, 2023, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan A��mus <superstippi@gmx.de> 7 * Zardshard 8 */ 9 10#include "Icon.h" 11 12#include <new> 13#include <stdio.h> 14 15#include "PathSourceShape.h" 16#include "ReferenceImage.h" 17#include "Shape.h" 18#include "Style.h" 19#include "VectorPath.h" 20 21using std::nothrow; 22 23#ifdef ICON_O_MATIC 24IconListener::IconListener() {} 25IconListener::~IconListener() {} 26#endif 27 28// #pragma mark - 29 30 31Icon::Icon() 32 : fStyles(true), 33 fPaths(true), 34 fShapes(true) 35#ifdef ICON_O_MATIC 36 , fListeners(2) 37#endif 38{ 39#ifdef ICON_O_MATIC 40 fShapes.AddListener(this); 41#endif 42} 43 44 45Icon::Icon(const Icon& other) 46 : fStyles(true), 47 fPaths(true), 48 fShapes(true) 49#ifdef ICON_O_MATIC 50 , fListeners(2) 51#endif 52{ 53#ifdef ICON_O_MATIC 54 fShapes.AddListener(this); 55#endif 56 57 int32 styleCount = other.fStyles.CountItems(); 58 for (int32 i = 0; i < styleCount; i++) { 59 Style* style = other.fStyles.ItemAtFast(i); 60 Style* clone = new (nothrow) Style(*style); 61 if (!clone || !fStyles.AddItem(clone)) { 62 delete clone; 63 return; 64 } 65 } 66 67 int32 pathCount = other.fPaths.CountItems(); 68 for (int32 i = 0; i < pathCount; i++) { 69 VectorPath* path = other.fPaths.ItemAtFast(i); 70 VectorPath* clone = new (nothrow) VectorPath(*path); 71 if (!clone || !fPaths.AddItem(clone)) { 72 delete clone; 73 return; 74 } 75 } 76 77 int32 shapeCount = other.fShapes.CountItems(); 78 for (int32 i = 0; i < shapeCount; i++) { 79 Shape* shape = other.fShapes.ItemAtFast(i); 80 Shape* clone = shape->Clone(); 81 if (!clone || !fShapes.AddItem(clone)) { 82 delete clone; 83 return; 84 } 85 86 // PathSourceShapes require further handling 87 PathSourceShape* pathSourceShape = dynamic_cast<PathSourceShape*>(shape); 88 PathSourceShape* pathSourceShapeClone = dynamic_cast<PathSourceShape*>(clone); 89 if (pathSourceShape != NULL && pathSourceShapeClone != NULL) { 90 // the cloned shape references styles and paths in 91 // the "other" icon, replace them with "local" styles 92 // and paths 93 94 int32 styleIndex = other.fStyles.IndexOf(pathSourceShape->Style()); 95 pathSourceShapeClone->SetStyle(fStyles.ItemAt(styleIndex)); 96 97 pathSourceShapeClone->Paths()->MakeEmpty(); 98 pathCount = pathSourceShape->Paths()->CountItems(); 99 for (int32 j = 0; j < pathCount; j++) { 100 VectorPath* remote = pathSourceShape->Paths()->ItemAtFast(j); 101 int32 index = other.fPaths.IndexOf(remote); 102 VectorPath* local = fPaths.ItemAt(index); 103 if (!local) { 104 printf("failed to match remote and " 105 "local paths while cloning icon\n"); 106 continue; 107 } 108 if (!pathSourceShapeClone->Paths()->AddItem(local)) { 109 return; 110 } 111 } 112 } 113 } 114} 115 116 117Icon::~Icon() 118{ 119 fShapes.MakeEmpty(); 120#ifdef ICON_O_MATIC 121 fShapes.RemoveListener(this); 122#endif 123} 124 125 126status_t 127Icon::InitCheck() const 128{ 129 return B_OK; 130} 131 132#ifdef ICON_O_MATIC 133 134void 135Icon::ItemAdded(Shape* shape, int32 index) 136{ 137 shape->AddObserver(this); 138 _NotifyAreaInvalidated(shape->Bounds(true)); 139} 140 141 142void 143Icon::ItemRemoved(Shape* shape) 144{ 145 shape->RemoveObserver(this); 146 _NotifyAreaInvalidated(shape->Bounds(true)); 147} 148 149 150void 151Icon::ObjectChanged(const Observable* object) 152{ 153 const Shape* shape = dynamic_cast<const Shape*>(object); 154 if (shape) { 155 BRect area = shape->LastBounds(); 156 area = area | shape->Bounds(true); 157 area.InsetBy(-1, -1); 158 _NotifyAreaInvalidated(area); 159 } 160} 161 162 163bool 164Icon::AddListener(IconListener* listener) 165{ 166 if (listener && !fListeners.HasItem((void*)listener)) { 167 if (fListeners.AddItem((void*)listener)) { 168 listener->AreaInvalidated(BRect(0, 0, 63, 63)); 169 return true; 170 } 171 } 172 return false; 173} 174 175 176bool 177Icon::RemoveListener(IconListener* listener) 178{ 179 return fListeners.RemoveItem((void*)listener); 180} 181#endif // ICON_O_MATIC 182 183 184Icon* 185Icon::Clone() const 186{ 187 return new (nothrow) Icon(*this); 188} 189 190 191void 192Icon::MakeEmpty() 193{ 194 fShapes.MakeEmpty(); 195 fPaths.MakeEmpty(); 196 fStyles.MakeEmpty(); 197} 198 199// #pragma mark - 200 201 202#ifdef ICON_O_MATIC 203void 204Icon::_NotifyAreaInvalidated(const BRect& area) const 205{ 206 BList listeners(fListeners); 207 int32 count = listeners.CountItems(); 208 for (int32 i = 0; i < count; i++) { 209 IconListener* listener 210 = (IconListener*)listeners.ItemAtFast(i); 211 listener->AreaInvalidated(area); 212 } 213} 214#endif // ICON_O_MATIC 215