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