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