2
// --------------------------------------------------------------------
3
// Ipe object attributes (not just color!)
4
// --------------------------------------------------------------------
7
This file is part of the extensible drawing editor Ipe.
8
Copyright (C) 1993-2004 Otfried Cheong
10
Ipe is free software; you can redistribute it and/or modify it
11
under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
As a special exception, you have permission to link Ipe with the
16
CGAL library and distribute executables, as long as you follow the
17
requirements of the Gnu General Public License in regard to all of
18
the software in the executable aside from CGAL.
20
Ipe is distributed in the hope that it will be useful, but WITHOUT
21
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
23
License for more details.
25
You should have received a copy of the GNU General Public License
26
along with Ipe; if not, you can find it at
27
"http://www.gnu.org/copyleft/gpl.html", or write to the Free
28
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34
// --------------------------------------------------------------------
36
/*! \defgroup attr Ipe Attributes
37
\brief Attributes for Ipe objects.
39
To make the representation of IpeObjects reasonably compact, Ipe
40
objects store attribute values as an index into an IpeRepository.
41
IpeAttribute encapsulates this index.
44
/*! \class IpeStrokeStyle
46
\brief Encapsulates line join, line cap, and eofill vs windfill rule.
48
This class encapsulates three IpeAttributes in the space of one \c int.
52
0x1000 join set in 0x0003
53
0x2000 cap set in 0x000c
54
0x4000 wind set in 0x0010
57
IpeAttribute IpeStrokeStyle::Join() const
60
return IpeAttribute(IpeAttribute::ELineJoin, false, iBits & 3);
61
return IpeAttribute();
64
IpeAttribute IpeStrokeStyle::Cap() const
67
return IpeAttribute(IpeAttribute::ELineCap, false, (iBits & 0x0c) >> 2);
68
return IpeAttribute();
71
IpeAttribute IpeStrokeStyle::WindRule() const
74
return IpeAttribute(IpeAttribute::EWindRule, false, (iBits & 0x10) >> 4);
75
return IpeAttribute();
78
void IpeStrokeStyle::SetJoin(int val)
81
iBits |= val + 0x1000;
84
void IpeStrokeStyle::SetCap(int val)
87
iBits |= (val << 2) + 0x2000;
90
void IpeStrokeStyle::SetWindRule(bool wind)
98
// --------------------------------------------------------------------
100
/*! \class IpeAttribute
102
\brief An attribute of an Ipe object.
104
An attribute is either null (i.e. not defined---it hasn't been set
105
yet), or symbolic (a name that has to be looked up using an
106
IpeStyleSheet), or an absolute value.
108
A null value is used in higher levels of the hierarchy to defer the
109
setting of the attribute to a lower level. For example, if the pen
110
width is set in an IpeGroup object, all its members have this
111
uniform pen width. To allow the members to have individual pen
112
width, the IpeGroup must have a null pen width.
114
To make the representation more compact, Ipe objects store attribute
115
values as an index into an IpeRepository. IpeAttribute encapsulates
116
this index. Its meaning is as follows:
118
- 0 : a <b>null</b> argument, see below,
120
- 2 : the solid line style
121
- 3 : the black color
122
- 4 : the white color
123
- if IsSymbolic: a symbolic name.
124
Use IpeStyleSheet to map to an absolute value.
125
- if IsNumeric: an absolute, numeric value.
126
Use Number() to return the number, in the range 0.0 to 16777.215
127
(with 3 digits fixed point precision).
128
- if IsValue: an absolute value.
129
Use IpeRepository to map to the absolute value.
131
An attribute is absolute (IsAbsolute() returns true) if it is
132
neither null nor symbolic.
134
Furthermore, the attribute stores the type of attribute, such as
135
scalar (a double value), color, dash style, etc.
137
Note the difference between the null color, which means that the
138
color has not yet been defined (it is left to lower-level objects),
139
and the "void" color, which means that the object should not be
142
When rendering an object, a null color is interpreted as the void
143
color. This allows leaf objects not to specify the void color.
145
Note that it is impossible for style sheets to redefine the meaning
146
of "black" and "white". If a user needs a symbolic name that is
147
black or white in some styles, she can always define another
148
symbolic name, e.g. "Black" and "White".
150
Note also the difference between null and "solid" (the special dash
151
style of a solid line). It is impossible for style sheets to
152
redefine the meaning of "solid".
154
When rendering an object, a null dash style is interpreted as solid.
158
//! Return kind of attribute.
159
IpeKind IpeAttribute::Kind() const
161
if (iName == 1 || iName == 3 || iName == 4)
165
return IpeKind((iName & EKindMask) >> EKindShift);
168
//! Create an attribute of given \a kind.
169
IpeAttribute::IpeAttribute(IpeKind kind, bool symbolic, int index)
171
iName = index | (kind << EKindShift) | (symbolic ? ESymbolic : EValue);
174
//! Create an absolute numeric attribute.
175
IpeAttribute::IpeAttribute(IpeKind kind, double value)
177
assert(value >= 0.0 && value <= 16777.215);
178
int ival = int(value * 1000.0 + 0.5);
179
iName = (kind << EKindShift) | EValue | ENumeric | ival;
182
// --------------------------------------------------------------------
186
\brief An absolute RGB color.
189
//! Construct a color.
190
IpeColor::IpeColor(IpeScalar red, IpeScalar green, IpeScalar blue)
198
void IpeColor::Save(IpeStream &stream) const
203
stream << iRed << " " << iGreen << " " << iBlue;
206
//! Is it an absolute gray value?
207
bool IpeColor::IsGray() const
209
return (iRed == iGreen && iRed == iBlue);
212
bool IpeColor::operator==(const IpeColor &rhs) const
214
return (iRed == rhs.iRed) && (iGreen == rhs.iGreen) && (iBlue == rhs.iBlue);
217
// --------------------------------------------------------------------
219
/*! \class IpeRepository
221
\brief Repository of attribute values.
223
Ipe documents can use symbolic attributes, such as 'normal', 'fat',
224
or 'thin' for line thickness, or 'red', 'navy', 'turquoise' for
225
color, as well as absolute attributes such as (0.5,0.5,0.5) for
226
medium gray. To avoid storing these very common values hundreds of
227
times, IpeRepository keeps a repository of all the non-scalar
228
attribute values in the document. Inside IpeObject's attributes are
229
represented as integer indices into the repository.
231
There are currently the following symbolic attributes:
233
- Line style (dash pattern)
237
These attributes can be symbolic, but the value is stored inside the
242
- Angle size (for angular snap)
248
IpeRepository::IpeRepository()
250
// ensure that string zero is 'normal'
251
iStrings.push_back("normal");
252
// ensure that symbolic dash styles 1 .. 4 are dashed, dotted, etc.
253
iStrings.push_back("dashed");
254
iStrings.push_back("dotted");
255
iStrings.push_back("dash dotted");
256
iStrings.push_back("dash dot dotted");
259
//! Return string with given index.
260
/*! Both positive (dash style) and negativ (symbolic name) index is
262
IpeString IpeRepository::ToString(IpeAttribute attr) const
264
assert(attr.IsSymbolic() ||
266
(attr.Kind() == IpeAttribute::EDashStyle ||
267
attr.Kind() == IpeAttribute::ETextSize));
268
return iStrings[attr.Index()];
271
//! Return color with given index
272
IpeColor IpeRepository::ToColor(IpeAttribute attr) const
274
assert(attr.Kind() == IpeAttribute::EColor);
276
return iColors[attr.Index()];
277
if (attr.Index() == 3)
278
return IpeColor(0.0, 0.0, 0.0);
279
assert(attr.Index() == 4);
280
return IpeColor(1.0, 1.0, 1.0);
283
//! Return value with given index.
284
double IpeRepository::ToScalar(IpeAttribute attr) const
286
assert(attr.Kind() < IpeAttribute::EDashStyle);
287
assert(attr.IsNumeric());
288
return attr.Number();
291
//! Return vector with given index
292
IpeVector IpeRepository::ToVector(IpeAttribute attr) const
294
assert(attr.IsValue() && (attr.Kind() == IpeAttribute::EMedia ||
295
attr.Kind() == IpeAttribute::ETextStretch));
296
return iVectors[attr.Index()];
299
/*! Lookup a string (add it if it doesn't exist yet), and return
300
symbolic attribute for it. */
301
IpeAttribute IpeRepository::ToSymbolic(IpeKind kind, IpeString name)
303
assert(!name.empty());
304
std::vector<IpeString>::const_iterator it =
305
std::find(iStrings.begin(), iStrings.end(), name);
306
if (it != iStrings.end())
307
return IpeAttribute(kind, true, (it - iStrings.begin()));
308
iStrings.push_back(name);
309
return IpeAttribute(kind, true, iStrings.size() - 1);
312
//! Lookup a color (add it if it doesn't exist yet), and return index.
313
IpeAttribute IpeRepository::ToAttribute(const IpeColor &color)
315
if (color == IpeColor(0.0, 0.0, 0.0))
316
return IpeAttribute::Black();
317
if (color == IpeColor(1.0, 1.0, 1.0))
318
return IpeAttribute::White();
319
std::vector<IpeColor>::const_iterator it =
320
std::find(iColors.begin(), iColors.end(), color);
321
if (it != iColors.end())
322
return IpeAttribute(IpeAttribute::EColor, false, (it - iColors.begin()));
323
iColors.push_back(color);
324
// IpeAttribute a = IpeAttribute(IpeAttribute::EColor, false, iColors.size() - 1);
325
return IpeAttribute(IpeAttribute::EColor, false, iColors.size() - 1);
328
//! Lookup \a value (add it if it doesn't exist yet), and return index.
329
IpeAttribute IpeRepository::ToAttribute(IpeKind kind, double value)
331
return IpeAttribute(kind, value);
334
//! Lookup \a vector (add it if it doesn't exist yet), and return index.
335
IpeAttribute IpeRepository::ToAttribute(IpeKind kind,
336
const IpeVector &vector)
338
std::vector<IpeVector>::const_iterator it =
339
std::find(iVectors.begin(), iVectors.end(), vector);
340
if (it != iVectors.end())
341
return IpeAttribute(kind, false, (it - iVectors.begin()));
342
iVectors.push_back(vector);
343
return IpeAttribute(kind, false, iVectors.size() - 1);
346
//! Create an IpeAttribute representing the color described.
347
/*! Empty string creates null color, string starting with a letter
348
creates a symbolic color (includes special case "void"), otherwise
350
IpeAttribute IpeRepository::MakeColor(IpeString str)
353
return IpeAttribute();
354
} else if (str == "void") {
355
return IpeAttribute::Void();
356
} else if (str == "black") {
357
return IpeAttribute::Black();
358
} else if (str == "white") {
359
return IpeAttribute::White();
360
} else if ('a' <= str[0] && str[0] <= 'z' ||
361
'A' <= str[0] && str[0] <= 'Z') {
362
return ToSymbolic(IpeAttribute::EColor, str);
366
st >> col.iRed >> col.iGreen;
368
col.iGreen = col.iBlue = col.iRed;
371
return ToAttribute(col);
375
//! Construct dash style attribute from string.
376
/*! Empty string creates null value, string starting with '[' creates
377
an absolute dash style, otherwise symbolic dash style (including the
378
special case "solid").
380
IpeAttribute IpeRepository::MakeDashStyle(IpeString str)
383
return IpeAttribute();
384
} else if (str == "solid") {
385
return IpeAttribute::Solid();
386
} else if (str[0] == '[') {
387
return MakeString(IpeAttribute::EDashStyle, str);
389
return ToSymbolic(IpeAttribute::EDashStyle, str);
392
//! Construct text size attribute from string.
393
/*! Empty string creates null value, string starting with digit
394
creates an numeric absolute value, string starting with letter
395
creates symbolic text size, anything else creates absolute (string)
398
IpeAttribute IpeRepository::MakeTextSize(IpeString str)
401
return IpeAttribute();
402
else if ('0' <= str[0] && str[0] <= '9')
403
return IpeAttribute(IpeAttribute::ETextSize, IpeLex(str).GetDouble());
404
else if ('a' <= str[0] && str[0] <= 'z' ||
405
'A' <= str[0] && str[0] <= 'Z')
406
return ToSymbolic(IpeAttribute::ETextSize, str);
408
return MakeString(IpeAttribute::ETextSize, str);
411
//! Construct absolute value (which is a string).
412
IpeAttribute IpeRepository::MakeString(IpeKind kind, IpeString str)
415
return IpeAttribute();
416
int index = ToSymbolic(kind, str).Index();
417
return IpeAttribute(kind, false, index);
420
//! Construct scalar attribute from string.
421
/*! Empty string creates null value, string starting with non-letter creates
422
an absolute value, string starting with letter creates symbolic value. */
423
IpeAttribute IpeRepository::MakeScalar(IpeKind kind, IpeString str)
426
return IpeAttribute();
427
} else if ('a' <= str[0] && str[0] <= 'z' ||
428
'A' <= str[0] && str[0] <= 'Z') {
429
return ToSymbolic(kind, str);
431
return ToAttribute(kind, IpeLex(str).GetDouble());
435
//! Construct vector attribute from string.
436
/*! Empty string creates null value, string starting with non-letter creates
437
an absolute value, string starting with letter creates symbolic value. */
438
IpeAttribute IpeRepository::MakeVector(IpeKind kind, IpeString str)
441
return IpeAttribute();
442
} else if ('a' <= str[0] && str[0] <= 'z' ||
443
'A' <= str[0] && str[0] <= 'Z') {
444
return ToSymbolic(kind, str);
449
return ToAttribute(kind, v);
453
//! Construct symbolic attribute from string.
454
/*! Empty string creates null value, anything else creates symbolic value. */
455
IpeAttribute IpeRepository::MakeSymbol(IpeKind kind, IpeString str)
458
return IpeAttribute();
460
return ToSymbolic(kind, str);
463
//! Return string representation of attribute (symbolic or absolute).
464
IpeString IpeRepository::String(IpeAttribute attr) const
468
if (attr.IsSymbolic())
469
return ToString(attr);
480
IpeStringStream stream(str);
481
if (attr.IsNumeric()) {
482
stream << attr.Number();
486
switch (attr.Kind()) {
487
case IpeAttribute::EColor:
488
stream << ToColor(attr);
490
case IpeAttribute::EDashStyle:
491
case IpeAttribute::ETextSize:
492
return ToString(attr);
493
case IpeAttribute::EMedia:
494
case IpeAttribute::ETextStretch:
495
stream << ToVector(attr);
498
stream << ToScalar(attr);
503
// --------------------------------------------------------------------