~ubuntu-branches/ubuntu/precise/ipe/precise

« back to all changes in this revision

Viewing changes to src/ipelib/ipecolor.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2004-06-08 00:44:02 UTC
  • Revision ID: james.westby@ubuntu.com-20040608004402-72yu51xlh7vt6p9m
Tags: upstream-6.0pre16
ImportĀ upstreamĀ versionĀ 6.0pre16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- C++ -*-
 
2
// --------------------------------------------------------------------
 
3
// Ipe object attributes (not just color!)
 
4
// --------------------------------------------------------------------
 
5
/*
 
6
 
 
7
    This file is part of the extensible drawing editor Ipe.
 
8
    Copyright (C) 1993-2004  Otfried Cheong
 
9
 
 
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.
 
14
 
 
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.
 
19
 
 
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.
 
24
 
 
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.
 
29
 
 
30
*/
 
31
 
 
32
#include "ipecolor.h"
 
33
 
 
34
// --------------------------------------------------------------------
 
35
 
 
36
/*! \defgroup attr Ipe Attributes
 
37
  \brief Attributes for Ipe objects.
 
38
 
 
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.
 
42
*/
 
43
 
 
44
/*! \class IpeStrokeStyle
 
45
  \ingroup attr
 
46
  \brief Encapsulates line join, line cap, and eofill vs windfill rule.
 
47
 
 
48
  This class encapsulates three IpeAttributes in the space of one \c int.
 
49
*/
 
50
 
 
51
/* Bit layout:
 
52
   0x1000 join set in 0x0003
 
53
   0x2000 cap set in 0x000c
 
54
   0x4000 wind set in 0x0010
 
55
 */
 
56
 
 
57
IpeAttribute IpeStrokeStyle::Join() const
 
58
{
 
59
  if (iBits & 0x1000)
 
60
    return IpeAttribute(IpeAttribute::ELineJoin, false, iBits & 3);
 
61
  return IpeAttribute();
 
62
}
 
63
 
 
64
IpeAttribute IpeStrokeStyle::Cap() const
 
65
{
 
66
  if (iBits & 0x2000)
 
67
    return IpeAttribute(IpeAttribute::ELineCap, false, (iBits & 0x0c) >> 2);
 
68
  return IpeAttribute();
 
69
}
 
70
 
 
71
IpeAttribute IpeStrokeStyle::WindRule() const
 
72
{
 
73
  if (iBits & 0x4000)
 
74
    return IpeAttribute(IpeAttribute::EWindRule, false, (iBits & 0x10) >> 4);
 
75
  return IpeAttribute();
 
76
}
 
77
 
 
78
void IpeStrokeStyle::SetJoin(int val)
 
79
{
 
80
  iBits &= ~0x03;
 
81
  iBits |= val + 0x1000;
 
82
}
 
83
 
 
84
void IpeStrokeStyle::SetCap(int val)
 
85
{
 
86
  iBits &= ~0x0c;
 
87
  iBits |= (val << 2) + 0x2000;
 
88
}
 
89
 
 
90
void IpeStrokeStyle::SetWindRule(bool wind)
 
91
{
 
92
  iBits &= ~0x10;
 
93
  iBits |= 0x4000;
 
94
  if (wind)
 
95
    iBits |= 0x10;
 
96
}
 
97
 
 
98
// --------------------------------------------------------------------
 
99
 
 
100
/*! \class IpeAttribute
 
101
  \ingroup attr
 
102
  \brief An attribute of an Ipe object.
 
103
 
 
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.
 
107
 
 
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.
 
113
 
 
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:
 
117
 
 
118
   - 0 : a <b>null</b> argument, see below,
 
119
   - 1 : the void color
 
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.
 
130
 
 
131
  An attribute is absolute (IsAbsolute() returns true) if it is
 
132
  neither null nor symbolic.
 
133
 
 
134
  Furthermore, the attribute stores the type of attribute, such as
 
135
  scalar (a double value), color, dash style, etc.
 
136
 
 
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
 
140
  stroked or filled.
 
141
 
 
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.
 
144
 
 
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".
 
149
 
 
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".
 
153
 
 
154
  When rendering an object, a null dash style is interpreted as solid.
 
155
 
 
156
*/
 
157
 
 
158
//! Return kind of attribute.
 
159
IpeKind IpeAttribute::Kind() const
 
160
{
 
161
  if (iName == 1 || iName == 3 || iName == 4)
 
162
    return EColor;
 
163
  if (iName == 2)
 
164
    return EDashStyle;
 
165
  return IpeKind((iName & EKindMask) >> EKindShift);
 
166
}
 
167
 
 
168
//! Create an attribute of given \a kind.
 
169
IpeAttribute::IpeAttribute(IpeKind kind, bool symbolic, int index)
 
170
{
 
171
  iName = index | (kind << EKindShift) | (symbolic ? ESymbolic : EValue);
 
172
}
 
173
 
 
174
//! Create an absolute numeric attribute.
 
175
IpeAttribute::IpeAttribute(IpeKind kind, double value)
 
176
{
 
177
  assert(value >= 0.0 && value <= 16777.215);
 
178
  int ival = int(value * 1000.0 + 0.5);
 
179
  iName = (kind << EKindShift) | EValue | ENumeric | ival;
 
180
}
 
181
 
 
182
// --------------------------------------------------------------------
 
183
 
 
184
/*! \class IpeColor
 
185
  \ingroup attr
 
186
  \brief An absolute RGB color.
 
187
*/
 
188
 
 
189
//! Construct a color.
 
190
IpeColor::IpeColor(IpeScalar red, IpeScalar green, IpeScalar blue)
 
191
{
 
192
  iRed = red;
 
193
  iGreen = green;
 
194
  iBlue = blue;
 
195
}
 
196
 
 
197
//! Save to stream.
 
198
void IpeColor::Save(IpeStream &stream) const
 
199
{
 
200
  if (IsGray())
 
201
    stream << iRed;
 
202
  else
 
203
    stream << iRed << " " << iGreen << " " << iBlue;
 
204
}
 
205
 
 
206
//! Is it an absolute gray value?
 
207
bool IpeColor::IsGray() const
 
208
{
 
209
  return (iRed == iGreen && iRed == iBlue);
 
210
}
 
211
 
 
212
bool IpeColor::operator==(const IpeColor &rhs) const
 
213
{
 
214
  return (iRed == rhs.iRed) && (iGreen == rhs.iGreen) && (iBlue == rhs.iBlue);
 
215
}
 
216
 
 
217
// --------------------------------------------------------------------
 
218
 
 
219
/*! \class IpeRepository
 
220
  \ingroup attr
 
221
  \brief Repository of attribute values.
 
222
 
 
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.
 
230
 
 
231
  There are currently the following symbolic attributes:
 
232
  - Color
 
233
  - Line style (dash pattern)
 
234
  - Font size
 
235
  - Media size
 
236
 
 
237
  These attributes can be symbolic, but the value is stored inside the
 
238
  IpeAttribute:
 
239
  - Mark size
 
240
  - Arrow size
 
241
  - Grid size
 
242
  - Angle size (for angular snap)
 
243
  - Line width
 
244
 
 
245
*/
 
246
 
 
247
//! Constructor.
 
248
IpeRepository::IpeRepository()
 
249
{
 
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");
 
257
}
 
258
 
 
259
//! Return string with given index.
 
260
/*! Both positive (dash style) and negativ (symbolic name) index is
 
261
  possible. */
 
262
IpeString IpeRepository::ToString(IpeAttribute attr) const
 
263
{
 
264
  assert(attr.IsSymbolic() ||
 
265
         attr.IsValue() &&
 
266
         (attr.Kind() == IpeAttribute::EDashStyle ||
 
267
          attr.Kind() == IpeAttribute::ETextSize));
 
268
  return iStrings[attr.Index()];
 
269
}
 
270
 
 
271
//! Return color with given index
 
272
IpeColor IpeRepository::ToColor(IpeAttribute attr) const
 
273
{
 
274
  assert(attr.Kind() == IpeAttribute::EColor);
 
275
  if (attr.IsValue())
 
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);
 
281
}
 
282
 
 
283
//! Return value with given index.
 
284
double IpeRepository::ToScalar(IpeAttribute attr) const
 
285
{
 
286
  assert(attr.Kind() < IpeAttribute::EDashStyle);
 
287
  assert(attr.IsNumeric());
 
288
  return attr.Number();
 
289
}
 
290
 
 
291
//! Return vector with given index
 
292
IpeVector IpeRepository::ToVector(IpeAttribute attr) const
 
293
{
 
294
  assert(attr.IsValue() && (attr.Kind() == IpeAttribute::EMedia ||
 
295
                            attr.Kind() == IpeAttribute::ETextStretch));
 
296
  return iVectors[attr.Index()];
 
297
}
 
298
 
 
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)
 
302
{
 
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);
 
310
}
 
311
 
 
312
//! Lookup a color (add it if it doesn't exist yet), and return index.
 
313
IpeAttribute IpeRepository::ToAttribute(const IpeColor &color)
 
314
{
 
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);
 
326
}
 
327
 
 
328
//! Lookup \a value (add it if it doesn't exist yet), and return index.
 
329
IpeAttribute IpeRepository::ToAttribute(IpeKind kind, double value)
 
330
{
 
331
  return IpeAttribute(kind, value);
 
332
}
 
333
 
 
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)
 
337
{
 
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);
 
344
}
 
345
 
 
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
 
349
  absolute color. */
 
350
IpeAttribute IpeRepository::MakeColor(IpeString str)
 
351
{
 
352
  if (str.empty()) {
 
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);
 
363
  } else {
 
364
    IpeLex st(str);
 
365
    IpeColor col;
 
366
    st >> col.iRed >> col.iGreen;
 
367
    if (st.Eos())
 
368
      col.iGreen = col.iBlue = col.iRed;
 
369
    else
 
370
      st >> col.iBlue;
 
371
    return ToAttribute(col);
 
372
  }
 
373
}
 
374
 
 
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").
 
379
*/
 
380
IpeAttribute IpeRepository::MakeDashStyle(IpeString str)
 
381
{
 
382
  if (str.empty()) {
 
383
    return IpeAttribute();
 
384
  } else if (str == "solid") {
 
385
    return IpeAttribute::Solid();
 
386
  } else if (str[0] == '[') {
 
387
    return MakeString(IpeAttribute::EDashStyle, str);
 
388
  } else
 
389
    return ToSymbolic(IpeAttribute::EDashStyle, str);
 
390
}
 
391
 
 
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)
 
396
  text size.
 
397
*/
 
398
IpeAttribute IpeRepository::MakeTextSize(IpeString str)
 
399
{
 
400
  if (str.empty())
 
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);
 
407
  else
 
408
    return MakeString(IpeAttribute::ETextSize, str);
 
409
}
 
410
 
 
411
//! Construct absolute value (which is a string).
 
412
IpeAttribute IpeRepository::MakeString(IpeKind kind, IpeString str)
 
413
{
 
414
  if (str.empty())
 
415
    return IpeAttribute();
 
416
  int index = ToSymbolic(kind, str).Index();
 
417
  return IpeAttribute(kind, false, index);
 
418
}
 
419
 
 
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)
 
424
{
 
425
  if (str.empty()) {
 
426
    return IpeAttribute();
 
427
  } else if ('a' <= str[0] && str[0] <= 'z' ||
 
428
             'A' <= str[0] && str[0] <= 'Z') {
 
429
    return ToSymbolic(kind, str);
 
430
  } else {
 
431
    return ToAttribute(kind, IpeLex(str).GetDouble());
 
432
  }
 
433
}
 
434
 
 
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)
 
439
{
 
440
  if (str.empty()) {
 
441
    return IpeAttribute();
 
442
  } else if ('a' <= str[0] && str[0] <= 'z' ||
 
443
             'A' <= str[0] && str[0] <= 'Z') {
 
444
    return ToSymbolic(kind, str);
 
445
  } else {
 
446
    IpeLex lex(str);
 
447
    IpeVector v;
 
448
    lex >> v.iX >> v.iY;
 
449
    return ToAttribute(kind, v);
 
450
  }
 
451
}
 
452
 
 
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)
 
456
{
 
457
  if (str.empty())
 
458
    return IpeAttribute();
 
459
  else
 
460
    return ToSymbolic(kind, str);
 
461
}
 
462
 
 
463
//! Return string representation of attribute (symbolic or absolute).
 
464
IpeString IpeRepository::String(IpeAttribute attr) const
 
465
{
 
466
  if (attr.IsNull())
 
467
    return IpeString();
 
468
  if (attr.IsSymbolic())
 
469
    return ToString(attr);
 
470
  if (attr.IsVoid())
 
471
    return "void";
 
472
  if (attr.IsSolid())
 
473
    return "solid";
 
474
  if (attr.IsBlack())
 
475
    return "black";
 
476
  if (attr.IsWhite())
 
477
    return "white";
 
478
 
 
479
  IpeString str;
 
480
  IpeStringStream stream(str);
 
481
  if (attr.IsNumeric()) {
 
482
    stream << attr.Number();
 
483
    return str;
 
484
  }
 
485
 
 
486
  switch (attr.Kind()) {
 
487
  case IpeAttribute::EColor:
 
488
    stream << ToColor(attr);
 
489
    return str;
 
490
  case IpeAttribute::EDashStyle:
 
491
  case IpeAttribute::ETextSize:
 
492
    return ToString(attr);
 
493
  case IpeAttribute::EMedia:
 
494
  case IpeAttribute::ETextStretch:
 
495
    stream << ToVector(attr);
 
496
    return str;
 
497
  default:
 
498
    stream << ToScalar(attr);
 
499
    return str;
 
500
  }
 
501
}
 
502
 
 
503
// --------------------------------------------------------------------