xref: /haiku/src/libs/icon/Icon.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #include "Icon.h"
10 
11 #include <new>
12 #include <stdio.h>
13 
14 #include "PathContainer.h"
15 #include "Shape.h"
16 #include "Style.h"
17 #include "StyleContainer.h"
18 
19 using std::nothrow;
20 
21 #ifdef ICON_O_MATIC
22 IconListener::IconListener() {}
23 IconListener::~IconListener() {}
24 #endif
25 
26 // #pragma mark -
27 
28 // constructor
29 Icon::Icon()
30 	: fStyles(new (nothrow) StyleContainer()),
31 	  fPaths(new (nothrow) PathContainer(true)),
32 	  fShapes(new (nothrow) ShapeContainer())
33 #ifdef ICON_O_MATIC
34 	, fListeners(2)
35 #endif
36 {
37 #ifdef ICON_O_MATIC
38 	if (fShapes)
39 		fShapes->AddListener(this);
40 #endif
41 }
42 
43 // constructor
44 Icon::Icon(const Icon& other)
45 	: fStyles(new (nothrow) StyleContainer()),
46 	  fPaths(new (nothrow) PathContainer(true)),
47 	  fShapes(new (nothrow) ShapeContainer())
48 #ifdef ICON_O_MATIC
49 	, fListeners(2)
50 #endif
51 {
52 	if (!fStyles || !fPaths || !fShapes)
53 		return;
54 
55 #ifdef ICON_O_MATIC
56 	fShapes->AddListener(this);
57 #endif
58 
59 	int32 styleCount = other.fStyles->CountStyles();
60 	for (int32 i = 0; i < styleCount; i++) {
61 		Style* style = other.fStyles->StyleAtFast(i);
62 		Style* clone = new (nothrow) Style(*style);
63 		if (!clone || !fStyles->AddStyle(clone)) {
64 			delete clone;
65 			return;
66 		}
67 	}
68 
69 	int32 pathCount = other.fPaths->CountPaths();
70 	for (int32 i = 0; i < pathCount; i++) {
71 		VectorPath* path = other.fPaths->PathAtFast(i);
72 		VectorPath* clone = new (nothrow) VectorPath(*path);
73 		if (!clone || !fPaths->AddPath(clone)) {
74 			delete clone;
75 			return;
76 		}
77 	}
78 
79 	int32 shapeCount = other.fShapes->CountShapes();
80 	for (int32 i = 0; i < shapeCount; i++) {
81 		Shape* shape = other.fShapes->ShapeAtFast(i);
82 		Shape* clone = new (nothrow) Shape(*shape);
83 		if (!clone || !fShapes->AddShape(clone)) {
84 			delete clone;
85 			return;
86 		}
87 		// the cloned shape references styles and paths in
88 		// the "other" icon, replace them with "local" styles
89 		// and paths
90 		int32 styleIndex = other.fStyles->IndexOf(shape->Style());
91 		clone->SetStyle(fStyles->StyleAt(styleIndex));
92 
93 		clone->Paths()->MakeEmpty();
94 		pathCount = shape->Paths()->CountPaths();
95 		for (int32 j = 0; j < pathCount; j++) {
96 			VectorPath* remote = shape->Paths()->PathAtFast(j);
97 			int32 index = other.fPaths->IndexOf(remote);
98 			VectorPath* local = fPaths->PathAt(index);
99 			if (!local) {
100 				printf("failed to match remote and "
101 					   "local paths while cloning icon\n");
102 				continue;
103 			}
104 			if (!clone->Paths()->AddPath(local)) {
105 				return;
106 			}
107 		}
108 	}
109 }
110 
111 // destructor
112 Icon::~Icon()
113 {
114 	if (fShapes) {
115 		fShapes->MakeEmpty();
116 #ifdef ICON_O_MATIC
117 		fShapes->RemoveListener(this);
118 #endif
119 		delete fShapes;
120 	}
121 	delete fPaths;
122 	delete fStyles;
123 }
124 
125 // InitCheck
126 status_t
127 Icon::InitCheck() const
128 {
129 	return fStyles && fPaths && fShapes ? B_OK : B_NO_MEMORY;
130 }
131 
132 #ifdef ICON_O_MATIC
133 // ShapeAdded
134 void
135 Icon::ShapeAdded(Shape* shape, int32 index)
136 {
137 	shape->AddObserver(this);
138 	_NotifyAreaInvalidated(shape->Bounds(true));
139 }
140 
141 // ShapeRemoved
142 void
143 Icon::ShapeRemoved(Shape* shape)
144 {
145 	shape->RemoveObserver(this);
146 	_NotifyAreaInvalidated(shape->Bounds(true));
147 }
148 
149 // ObjectChanged
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 // AddListener
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 // RemoveListener
176 bool
177 Icon::RemoveListener(IconListener* listener)
178 {
179 	return fListeners.RemoveItem((void*)listener);
180 }
181 #endif // ICON_O_MATIC
182 
183 
184 // Clone
185 Icon*
186 Icon::Clone() const
187 {
188 	return new (nothrow) Icon(*this);
189 }
190 
191 // MakeEmpty
192 void
193 Icon::MakeEmpty()
194 {
195 	fShapes->MakeEmpty();
196 	fPaths->MakeEmpty();
197 	fStyles->MakeEmpty();
198 }
199 
200 // #pragma mark -
201 
202 #ifdef ICON_O_MATIC
203 // _NotifyAreaInvalidated
204 void
205 Icon::_NotifyAreaInvalidated(const BRect& area) const
206 {
207 	BList listeners(fListeners);
208 	int32 count = listeners.CountItems();
209 	for (int32 i = 0; i < count; i++) {
210 		IconListener* listener
211 			= (IconListener*)listeners.ItemAtFast(i);
212 		listener->AreaInvalidated(area);
213 	}
214 }
215 #endif // ICON_O_MATIC
216 
217 
218