1/*
2 * Copyright 2006-2007, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan A��mus <superstippi@gmx.de>
7 */
8
9
10#include "StrokeTransformer.h"
11
12#ifdef ICON_O_MATIC
13# include <Message.h>
14
15# include "CommonPropertyIDs.h"
16# include "OptionProperty.h"
17# include "Property.h"
18# include "PropertyObject.h"
19#endif // ICON_O_MATIC
20
21#include <new>
22
23
24_USING_ICON_NAMESPACE
25using std::nothrow;
26
27
28// constructor
29StrokeTransformer::StrokeTransformer(VertexSource& source)
30	: Transformer("Stroke"),
31	  PathTransformer(source),
32	  Stroke(source)
33{
34}
35
36// constructor
37StrokeTransformer::StrokeTransformer(VertexSource& source,
38									 BMessage* archive)
39	: Transformer(archive),
40	  PathTransformer(source),
41	  Stroke(source)
42{
43	if (!archive)
44		return;
45
46	int32 mode;
47	if (archive->FindInt32("line cap", &mode) == B_OK)
48		line_cap((agg::line_cap_e)mode);
49
50	if (archive->FindInt32("line join", &mode) == B_OK)
51		line_join((agg::line_join_e)mode);
52
53	if (archive->FindInt32("inner join", &mode) == B_OK)
54		inner_join((agg::inner_join_e)mode);
55
56	double value;
57	if (archive->FindDouble("width", &value) == B_OK)
58		width(value);
59
60	if (archive->FindDouble("miter limit", &value) == B_OK)
61		miter_limit(value);
62
63	if (archive->FindDouble("inner miter limit", &value) == B_OK)
64		inner_miter_limit(value);
65
66	if (archive->FindDouble("shorten", &value) == B_OK)
67		shorten(value);
68}
69
70// destructor
71StrokeTransformer::~StrokeTransformer()
72{
73}
74
75// Clone
76Transformer*
77StrokeTransformer::Clone() const
78{
79	StrokeTransformer* clone = new (nothrow) StrokeTransformer(*fSource);
80	if (clone) {
81		clone->line_cap(line_cap());
82		clone->line_join(line_join());
83		clone->inner_join(inner_join());
84		clone->width(width());
85		clone->miter_limit(miter_limit());
86		clone->inner_miter_limit(inner_miter_limit());
87		clone->shorten(shorten());
88	}
89	return clone;
90}
91
92// rewind
93void
94StrokeTransformer::rewind(unsigned path_id)
95{
96	Stroke::rewind(path_id);
97}
98
99// vertex
100unsigned
101StrokeTransformer::vertex(double* x, double* y)
102{
103	return Stroke::vertex(x, y);
104}
105
106// SetSource
107void
108StrokeTransformer::SetSource(VertexSource& source)
109{
110	PathTransformer::SetSource(source);
111	Stroke::attach(source);
112}
113
114// WantsOpenPaths
115bool
116StrokeTransformer::WantsOpenPaths() const
117{
118	return true;
119}
120
121// ApproximationScale
122double
123StrokeTransformer::ApproximationScale() const
124{
125	double scale = fSource->ApproximationScale();
126	double factor = fabs(width());
127	if (factor > 1.0)
128		scale *= factor;
129	return scale;
130}
131
132// #pragma mark -
133
134#ifdef ICON_O_MATIC
135
136// Archive
137status_t
138StrokeTransformer::Archive(BMessage* into, bool deep) const
139{
140	status_t ret = Transformer::Archive(into, deep);
141
142	if (ret == B_OK)
143		into->what = archive_code;
144
145	if (ret == B_OK)
146		ret = into->AddInt32("line cap", line_cap());
147
148	if (ret == B_OK)
149		ret = into->AddInt32("line join", line_join());
150
151	if (ret == B_OK)
152		ret = into->AddInt32("inner join", inner_join());
153
154	if (ret == B_OK)
155		ret = into->AddDouble("width", width());
156
157	if (ret == B_OK)
158		ret = into->AddDouble("miter limit", miter_limit());
159
160	if (ret == B_OK)
161		ret = into->AddDouble("inner miter limit", inner_miter_limit());
162
163	if (ret == B_OK)
164		ret = into->AddDouble("shorten",shorten());
165
166	return ret;
167}
168
169// MakePropertyObject
170PropertyObject*
171StrokeTransformer::MakePropertyObject() const
172{
173	PropertyObject* object = Transformer::MakePropertyObject();
174	if (!object)
175		return NULL;
176
177	// width
178	object->AddProperty(new FloatProperty(PROPERTY_WIDTH, width()));
179
180	// cap mode
181	OptionProperty* property = new OptionProperty(PROPERTY_CAP_MODE);
182	property->AddOption(agg::butt_cap, "Butt");
183	property->AddOption(agg::square_cap, "Square");
184	property->AddOption(agg::round_cap, "Round");
185	property->SetCurrentOptionID(line_cap());
186
187	object->AddProperty(property);
188
189	// join mode
190	property = new OptionProperty(PROPERTY_JOIN_MODE);
191	property->AddOption(agg::miter_join, "Miter");
192	property->AddOption(agg::round_join, "Round");
193	property->AddOption(agg::bevel_join, "Bevel");
194	property->SetCurrentOptionID(line_join());
195
196	object->AddProperty(property);
197
198	// miter limit
199	if (line_join() == agg::miter_join) {
200		object->AddProperty(new FloatProperty(PROPERTY_MITER_LIMIT,
201											  miter_limit()));
202	}
203
204//	// shorten
205//	object->AddProperty(new FloatProperty(PROPERTY_STROKE_SHORTEN,
206//										  shorten()));
207
208	return object;
209}
210
211// SetToPropertyObject
212bool
213StrokeTransformer::SetToPropertyObject(const PropertyObject* object)
214{
215	AutoNotificationSuspender _(this);
216	Transformer::SetToPropertyObject(object);
217
218	// width
219	float w = object->Value(PROPERTY_WIDTH, (float)width());
220	if (w != width()) {
221		width(w);
222		Notify();
223	}
224
225	// cap mode
226	OptionProperty* property = dynamic_cast<OptionProperty*>(
227			object->FindProperty(PROPERTY_CAP_MODE));
228	if (property && line_cap() != property->CurrentOptionID()) {
229		line_cap((agg::line_cap_e)property->CurrentOptionID());
230		Notify();
231	}
232	// join mode
233	property = dynamic_cast<OptionProperty*>(
234		object->FindProperty(PROPERTY_JOIN_MODE));
235	if (property && line_join() != property->CurrentOptionID()) {
236		line_join((agg::line_join_e)property->CurrentOptionID());
237		Notify();
238	}
239
240	// miter limit
241	float l = object->Value(PROPERTY_MITER_LIMIT, (float)miter_limit());
242	if (l != miter_limit()) {
243		miter_limit(l);
244		Notify();
245	}
246
247	// shorten
248	float s = object->Value(PROPERTY_STROKE_SHORTEN, (float)shorten());
249	if (s != shorten()) {
250		shorten(s);
251		Notify();
252	}
253
254	return HasPendingNotifications();
255}
256
257#endif // ICON_O_MATIC
258
259
260