xref: /haiku/src/libs/icon/Icon.cpp (revision 1454f3c27aec3e7879a58e7cedc9d66d90c773a7)
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