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 21 using std::nothrow; 22 23 #ifdef ICON_O_MATIC 24 IconListener::IconListener() {} 25 IconListener::~IconListener() {} 26 #endif 27 28 // #pragma mark - 29 30 31 Icon::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 45 Icon::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 117 Icon::~Icon() 118 { 119 fShapes.MakeEmpty(); 120 #ifdef ICON_O_MATIC 121 fShapes.RemoveListener(this); 122 #endif 123 } 124 125 126 status_t 127 Icon::InitCheck() const 128 { 129 return B_OK; 130 } 131 132 #ifdef ICON_O_MATIC 133 134 void 135 Icon::ItemAdded(Shape* shape, int32 index) 136 { 137 shape->AddObserver(this); 138 _NotifyAreaInvalidated(shape->Bounds(true)); 139 } 140 141 142 void 143 Icon::ItemRemoved(Shape* shape) 144 { 145 shape->RemoveObserver(this); 146 _NotifyAreaInvalidated(shape->Bounds(true)); 147 } 148 149 150 void 151 Icon::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 163 bool 164 Icon::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 176 bool 177 Icon::RemoveListener(IconListener* listener) 178 { 179 return fListeners.RemoveItem((void*)listener); 180 } 181 #endif // ICON_O_MATIC 182 183 184 Icon* 185 Icon::Clone() const 186 { 187 return new (nothrow) Icon(*this); 188 } 189 190 191 void 192 Icon::MakeEmpty() 193 { 194 fShapes.MakeEmpty(); 195 fPaths.MakeEmpty(); 196 fStyles.MakeEmpty(); 197 } 198 199 // #pragma mark - 200 201 202 #ifdef ICON_O_MATIC 203 void 204 Icon::_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