2
// --------------------------------------------------------------------
3
// Ipe object attributes (not just color!)
4
// --------------------------------------------------------------------
7
This file is part of the extensible drawing editor Ipe.
8
Copyright (C) 1993-2007 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 IpeDashStyle
46
\brief An absolute dash style.
49
/*! \class IpeStrokeStyle
51
\brief Encapsulates line join, line cap, and eofill vs windfill rule.
53
This class encapsulates three IpeAttributes in the space of one \c int.
57
0x1000 join set in 0x0003
58
0x2000 cap set in 0x000c
59
0x4000 wind set in 0x0010
62
IpeAttribute IpeStrokeStyle::Join() const
65
return IpeAttribute(IpeAttribute::ELineJoin, false, iBits & 3);
66
return IpeAttribute();
69
IpeAttribute IpeStrokeStyle::Cap() const
72
return IpeAttribute(IpeAttribute::ELineCap, false, (iBits & 0x0c) >> 2);
73
return IpeAttribute();
76
IpeAttribute IpeStrokeStyle::WindRule() const
79
return IpeAttribute(IpeAttribute::EWindRule, false, (iBits & 0x10) >> 4);
80
return IpeAttribute();
84
/*! If \a val < 0 or \a val > 2, set to default. */
85
void IpeStrokeStyle::SetJoin(int val)
87
if (0 <= val && val <= 2) {
89
iBits |= val + 0x1000;
95
/*! If \a val < 0 or \a val > 2, set to default. */
96
void IpeStrokeStyle::SetCap(int val)
98
if (0 <= val && val <= 2) {
100
iBits |= (val << 2) + 0x2000;
105
//! Set wind rule (0 = even-odd file, 1 = wind fill)
106
/*! If \a val < 0 or \a val > 1, set to default. */
107
void IpeStrokeStyle::SetWindRule(int val)
109
if (0 <= val && val <= 1) {
118
//! Set join from attribute.
119
void IpeStrokeStyle::SetJoin(IpeAttribute val)
124
SetJoin(val.Index());
127
//! Set line cap from attribute.
128
void IpeStrokeStyle::SetCap(IpeAttribute val)
136
//! Set wind rule from attribute.
137
void IpeStrokeStyle::SetWindRule(IpeAttribute val)
142
SetWindRule(val.Index());
145
// --------------------------------------------------------------------
147
/*! \class IpeAttribute
149
\brief An attribute of an Ipe object.
151
An attribute is either null (i.e. not defined---it hasn't been set
152
yet), or symbolic (a name that has to be looked up using an
153
IpeStyleSheet), or an absolute value.
155
A null value is used in higher levels of the hierarchy to defer the
156
setting of the attribute to a lower level. For example, if the pen
157
width is set in an IpeGroup object, all its members have this
158
uniform pen width. To allow the members to have individual pen
159
width, the IpeGroup must have a null pen width.
161
To make the representation more compact, Ipe objects store attribute
162
values as an index into an IpeRepository. IpeAttribute encapsulates
163
this index. Its meaning is as follows:
165
- 0 : a <b>null</b> argument, see below,
166
- 1 : the void color or line style
167
- 2 : the solid line style
168
- 3 : the black color
169
- 4 : the white color
170
- if IsSymbolic: a symbolic name.
171
Use IpeStyleSheet to map to an absolute value.
172
- if IsNumeric: an absolute, numeric value.
173
Use Number() to return the number, in the range 0.0 to 16777.215
174
(with 3 digits fixed point precision).
175
- if IsValue: an absolute value.
176
Use IpeRepository to map to the absolute value.
178
An attribute is absolute (IsAbsolute() returns true) if it is
179
neither null nor symbolic.
181
Furthermore, the attribute stores the type of attribute, such as
182
scalar (a double value), color, dash style, etc.
184
Note the difference between the null color, which means that the
185
color has not yet been defined (it is left to lower-level objects),
186
and the "void" color, which means that the object should not be
189
When rendering an object, a null color is interpreted as the void
190
color. This allows leaf objects not to specify the void color.
192
Note that it is impossible for style sheets to redefine the meaning
193
of "black" and "white". If a user needs a symbolic name that is
194
black or white in some styles, she can always define another
195
symbolic name, e.g. "Black" and "White".
197
Note also the difference between null and "solid" (the special dash
198
style of a solid line). It is impossible for style sheets to
199
redefine the meaning of "solid".
201
When rendering an object, a null dash style is interpreted as solid.
205
//! Return kind of attribute.
206
IpeKind IpeAttribute::Kind() const
208
if (iName == 1 || iName == 3 || iName == 4)
212
return IpeKind((iName & EKindMask) >> EKindShift);
215
//! Create an attribute of given \a kind.
216
IpeAttribute::IpeAttribute(IpeKind kind, bool symbolic, int index)
218
iName = index | (kind << EKindShift) | (symbolic ? ESymbolic : EValue);
221
//! Create an absolute numeric attribute.
222
IpeAttribute::IpeAttribute(IpeKind kind, IpeFixed value)
224
iName = (kind << EKindShift) | EValue | ENumeric | value.Internal();
227
// --------------------------------------------------------------------
231
\brief An absolute RGB color.
234
//! Construct a color.
235
IpeColor::IpeColor(IpeScalar red, IpeScalar green, IpeScalar blue)
243
void IpeColor::Save(IpeStream &stream) const
248
stream << iRed << " " << iGreen << " " << iBlue;
251
//! Is it an absolute gray value?
252
bool IpeColor::IsGray() const
254
return (iRed == iGreen && iRed == iBlue);
257
bool IpeColor::operator==(const IpeColor &rhs) const
259
return (iRed == rhs.iRed) && (iGreen == rhs.iGreen) && (iBlue == rhs.iBlue);
262
// --------------------------------------------------------------------
264
/*! \class IpeRepository
266
\brief Repository of attribute values.
268
Ipe documents can use symbolic attributes, such as 'normal', 'fat',
269
or 'thin' for line thickness, or 'red', 'navy', 'turquoise' for
270
color, as well as absolute attributes such as (0.5,0.5,0.5) for
271
medium gray. To avoid storing these very common values hundreds of
272
times, IpeRepository keeps a repository of all the non-scalar
273
attribute values in the document. Inside IpeObject's attributes are
274
represented as integer indices into the repository.
276
There are currently the following symbolic attributes with values
277
stored in the repository.
279
- Line style (dash pattern)
281
- Text style (Latex style)
283
The following attributes can be symbolic, but if they are absolute
284
then the scalar value is stored inside the IpeAttribute (not in the
289
- Angle size (for angular snap)
292
Finally, line join, line cap, and the fill rule cannot be symbolic.
293
They can be null, or have an absolute value stored inside the
298
IpeRepository::IpeRepository()
300
// ensure that string zero is 'normal'
301
iStrings.push_back("normal");
302
// ensure that symbolic dash styles 1 .. 4 are dashed, dotted, etc.
303
iStrings.push_back("dashed");
304
iStrings.push_back("dotted");
305
iStrings.push_back("dash dotted");
306
iStrings.push_back("dash dot dotted");
309
//! Return string with given index.
310
/*! Both symbolic and absolute values are possible. */
311
IpeString IpeRepository::ToString(IpeAttribute attr) const
313
assert(attr.IsSymbolic() ||
315
(attr.Kind() == IpeAttribute::EDashStyle ||
316
attr.Kind() == IpeAttribute::ETextStyle ||
317
attr.Kind() == IpeAttribute::ETextSize)));
318
return iStrings[attr.Index()];
321
//! Return color with given index
322
IpeColor IpeRepository::ToColor(IpeAttribute attr) const
324
assert(attr.Kind() == IpeAttribute::EColor);
326
return iColors[attr.Index()];
327
if (attr.Index() == 3)
328
return IpeColor(0.0, 0.0, 0.0);
329
assert(attr.Index() == 4);
330
return IpeColor(1.0, 1.0, 1.0);
333
//! Return value with given index.
334
IpeFixed IpeRepository::ToScalar(IpeAttribute attr) const
336
assert(attr.Kind() < IpeAttribute::EDashStyle);
337
assert(attr.IsNumeric());
338
return attr.Number();
341
/*! Lookup a string (add it if it doesn't exist yet), and return
342
symbolic attribute for it. */
343
IpeAttribute IpeRepository::ToSymbolic(IpeKind kind, IpeString name)
345
assert(!name.empty());
346
std::vector<IpeString>::const_iterator it =
347
std::find(iStrings.begin(), iStrings.end(), name);
348
if (it != iStrings.end())
349
return IpeAttribute(kind, true, (it - iStrings.begin()));
350
iStrings.push_back(name);
351
return IpeAttribute(kind, true, iStrings.size() - 1);
354
//! Lookup a color (add it if it doesn't exist yet), and return index.
355
IpeAttribute IpeRepository::ToAttribute(const IpeColor &color)
357
if (color == IpeColor(0.0, 0.0, 0.0))
358
return IpeAttribute::Black();
359
if (color == IpeColor(1.0, 1.0, 1.0))
360
return IpeAttribute::White();
361
std::vector<IpeColor>::const_iterator it =
362
std::find(iColors.begin(), iColors.end(), color);
363
if (it != iColors.end())
364
return IpeAttribute(IpeAttribute::EColor, false, (it - iColors.begin()));
365
iColors.push_back(color);
366
return IpeAttribute(IpeAttribute::EColor, false, iColors.size() - 1);
369
//! Lookup \a value (add it if it doesn't exist yet), and return index.
370
IpeAttribute IpeRepository::ToAttribute(IpeKind kind, IpeFixed value)
372
return IpeAttribute(kind, value);
375
//! Create an IpeAttribute representing the color described.
376
/*! Empty string creates null color, string starting with a letter
377
creates a symbolic color (includes special case "void"), otherwise
379
IpeAttribute IpeRepository::MakeColor(IpeString str)
382
return IpeAttribute();
383
} else if (str == "void") {
384
return IpeAttribute::Void();
385
} else if (str == "black") {
386
return IpeAttribute::Black();
387
} else if (str == "white") {
388
return IpeAttribute::White();
389
} else if (('a' <= str[0] && str[0] <= 'z') ||
390
('A' <= str[0] && str[0] <= 'Z')) {
391
return ToSymbolic(IpeAttribute::EColor, str);
395
st >> col.iRed >> col.iGreen;
397
col.iGreen = col.iBlue = col.iRed;
400
return ToAttribute(col);
404
//! Construct dash style attribute from string.
405
/*! Empty string creates null value, string starting with '[' creates
406
an absolute dash style, otherwise symbolic dash style (including the
407
special case "solid").
409
IpeAttribute IpeRepository::MakeDashStyle(IpeString str)
412
return IpeAttribute();
413
} else if (str == "void") {
414
return IpeAttribute::Void();
415
} else if (str == "solid") {
416
return IpeAttribute::Solid();
417
} else if (str[0] == '[') {
418
return MakeString(IpeAttribute::EDashStyle, str);
420
return ToSymbolic(IpeAttribute::EDashStyle, str);
423
//! Construct text size attribute from string.
424
/*! Empty string creates null value, string starting with digit
425
creates an numeric absolute value, string starting with letter
426
creates symbolic text size, anything else creates absolute (string)
429
IpeAttribute IpeRepository::MakeTextSize(IpeString str)
432
return IpeAttribute();
433
else if ('0' <= str[0] && str[0] <= '9')
434
return IpeAttribute(IpeAttribute::ETextSize, IpeLex(str).GetFixed());
435
else if (('a' <= str[0] && str[0] <= 'z') ||
436
('A' <= str[0] && str[0] <= 'Z'))
437
return ToSymbolic(IpeAttribute::ETextSize, str);
439
return MakeString(IpeAttribute::ETextSize, str);
442
//! Construct absolute value (which is a string).
443
IpeAttribute IpeRepository::MakeString(IpeKind kind, IpeString str)
446
return IpeAttribute();
447
int index = ToSymbolic(kind, str).Index();
448
return IpeAttribute(kind, false, index);
451
//! Construct scalar attribute from string.
452
/*! Empty string creates null value, string starting with non-letter creates
453
an absolute value, string starting with letter creates symbolic value. */
454
IpeAttribute IpeRepository::MakeScalar(IpeKind kind, IpeString str)
457
return IpeAttribute();
458
} else if (('a' <= str[0] && str[0] <= 'z') ||
459
('A' <= str[0] && str[0] <= 'Z')) {
460
return ToSymbolic(kind, str);
462
return ToAttribute(kind, IpeLex(str).GetFixed());
466
//! Construct symbolic attribute from string.
467
/*! Empty string creates null value, anything else creates symbolic value. */
468
IpeAttribute IpeRepository::MakeSymbol(IpeKind kind, IpeString str)
471
return IpeAttribute();
473
return ToSymbolic(kind, str);
476
//! Construct symbolic attribute from string.
477
/*! Like MakeSymbol, but will not create new repository entry. */
478
IpeAttribute IpeRepository::GetSymbol(IpeKind kind, IpeString str) const
481
std::vector<IpeString>::const_iterator it =
482
std::find(iStrings.begin(), iStrings.end(), str);
483
if (it != iStrings.end())
484
return IpeAttribute(kind, true, (it - iStrings.begin()));
486
return IpeAttribute();
489
//! Return string representation of attribute (symbolic or absolute).
490
IpeString IpeRepository::String(IpeAttribute attr) const
494
if (attr.IsSymbolic())
495
return ToString(attr);
506
IpeStringStream stream(str);
507
if (attr.IsNumeric()) {
508
stream << attr.Number();
512
switch (attr.Kind()) {
513
case IpeAttribute::EColor:
514
stream << ToColor(attr);
516
case IpeAttribute::EDashStyle:
517
case IpeAttribute::ETextSize:
518
case IpeAttribute::ETextStyle:
519
return ToString(attr);
521
stream << ToScalar(attr);
526
// --------------------------------------------------------------------