1 // -*- C++ -*-
2 // --------------------------------------------------------------------
3 // Ipe object attributes
4 // --------------------------------------------------------------------
5 /*
6 
7     This file is part of the extensible drawing editor Ipe.
8     Copyright (c) 1993-2020 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 3 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 #ifndef IPEATTRIBUTES_H
33 #define IPEATTRIBUTES_H
34 
35 #include "ipebase.h"
36 #include "ipegeo.h"
37 
38 // --------------------------------------------------------------------
39 
40 namespace ipe {
41 
42   /*! \brief The different kinds of attributes.
43     \ingroup attr
44 
45     The same symbolic attribute (say "normal") has a different value
46     in the StyleSheet depending on the Kind of attribute. The main use
47     for Kind is as an argument to StyleSheet::find.
48 
49     ESymbol, EGradient, ETiling, and EEffect have their own lookup
50     methods in the StyleSheet.  The values are still useful as an
51     argument to allNames(), has(), and findDefinition().
52   */
53   enum Kind { EPen = 0, ESymbolSize, EArrowSize, EColor,
54 	      EDashStyle, ETextSize, ETextStretch,
55 	      ETextStyle, ELabelStyle,
56 	      EGridSize, EAngleSize, EOpacity, ETiling,
57 	      ESymbol, EGradient, EEffect };
58 
59   /*! \ingroup attr */
60   extern const char * const kind_names[];
61 
62   /*! \brief A Property identifies an attribute that an object can have.
63     \ingroup attr
64 
65     The Property identifies a unique attribute of an object, while
66     different Property values can be of the same ipe::Kind.  For
67     instance, both EPropStrokeColor and EPropFillColor identify an
68     Attribute of Kind EColor.
69   */
70   enum Property { EPropPen = 0, EPropSymbolSize,
71 		  EPropFArrow, EPropRArrow,
72 		  EPropFArrowSize, EPropRArrowSize,
73 		  EPropFArrowShape, EPropRArrowShape,
74 		  EPropStrokeColor, EPropFillColor, EPropMarkShape,
75 		  EPropPathMode, EPropDashStyle,
76 		  EPropTextSize, EPropTextStyle, EPropLabelStyle,
77 		  EPropOpacity, EPropStrokeOpacity, EPropTiling, EPropGradient,
78 		  EPropHorizontalAlignment, EPropVerticalAlignment,
79 		  EPropLineJoin, EPropLineCap, EPropFillRule,
80 		  EPropPinned, EPropTransformations,
81 		  EPropTransformableText, EPropSplineType,
82 		  EPropMinipage, EPropWidth,
83 		  EPropDecoration,
84   };
85 
86   /*! \ingroup attr */
87   extern const char * const property_names[];
88 
89   //! Path mode (stroked, filled, or both).
90   /*! \ingroup attr */
91   enum TPathMode { EStrokedOnly, EStrokedAndFilled, EFilledOnly };
92 
93   //! Horizontal alignment.
94   /*! \ingroup attr */
95   enum THorizontalAlignment { EAlignLeft, EAlignRight, EAlignHCenter };
96 
97   //! Vertical alignment.
98   /*! \ingroup attr */
99   enum TVerticalAlignment { EAlignBottom, EAlignBaseline,
100       EAlignTop, EAlignVCenter };
101 
102   //! Spline type.
103   /*! \ingroup attr */
104   enum TSplineType { EBSpline, ECardinalSpline, ESpiroSpline };
105 
106   //! Line join style.
107   /*! \ingroup attr */
108   /*! The EDefaultJoin means to use the setting from the style sheet. */
109   enum TLineJoin { EDefaultJoin, EMiterJoin, ERoundJoin, EBevelJoin };
110 
111   //! Line cap style.
112   /*! \ingroup attr */
113   /*! The EDefaultCap means to use the setting from the style sheet. */
114   enum TLineCap { EDefaultCap, EButtCap, ERoundCap, ESquareCap };
115 
116   //! Fill rule.
117   /*! \ingroup attr */
118   /*! The EDefaultRule means to use the setting from the style sheet. */
119   enum TFillRule { EDefaultRule, EWindRule, EEvenOddRule };
120 
121   //! Pinning status of objects.
122   /*! \ingroup attr */
123   enum TPinned { ENoPin = 0x00, EHorizontalPin = 0x01,
124       EVerticalPin = 0x02, EFixedPin = 0x03 };
125 
126   //! Transformations that are permitted for an object.
127   /*! \ingroup attr */
128   enum TTransformations { ETransformationsTranslations,
129       ETransformationsRigidMotions,
130       ETransformationsAffine };
131 
132   //! Selection status of an object on the page
133   /*! \ingroup attr */
134   enum TSelect { ENotSelected = 0, EPrimarySelected,
135       ESecondarySelected };
136 
137   // --------------------------------------------------------------------
138 
139   class Color {
140   public:
141     //! Default constructor.
Color()142     Color() { /* nothing */ }
143     explicit Color(String str);
144     explicit Color(int r, int g, int b);
145     void save(Stream &stream) const;
146     void saveRGB(Stream &stream) const;
147     bool isGray() const;
148     bool operator==(const Color &rhs) const;
149     inline bool operator!=(const Color &rhs) const {return !(*this == rhs); }
150   public:
151     Fixed iRed, iGreen, iBlue;
152   };
153 
154   //! A tiling pattern.
155   /*! \ingroup attr */
156   struct Tiling {
157     Angle iAngle;
158     double iStep;
159     double iWidth;
160   };
161 
162   //! A gradient pattern.
163   /*! \ingroup attr */
164   struct Gradient {
165     //! A color stop.
166     struct Stop {
167       //! Offset between 0.0 and 1.0.
168       double offset;
169       //! The color at this offset.
170       Color color;
171     };
172     //! There are two types of gradients, along an axis or between two circles.
173     enum TType { EAxial = 2, ERadial = 3 };
174     //! The type of gradient: axial or radial.
175     TType iType;
176     //! The coordinates of the axis endpoints, or the two circle centers.
177     Vector iV[2];
178     //! The radii of the two circles (not used for axial gradients).
179     double iRadius[2];
180     //! Whether to extend the gradient beyond the endpoints.
181     bool iExtend;
182     //! Gradient transformation.
183     Matrix iMatrix;
184     //! The color stops.
185     std::vector<Stop> iStops;
186   };
187 
188   //! Layout of a Page.
189   /*! \ingroup attr */
190   struct Layout {
191     //! Create null layout.
LayoutLayout192     Layout() { iPaperSize.x = -1.0; }
193     //! Is this an undefined (null) layout?
isNullLayout194     bool isNull() const { return iPaperSize.x < 0.0; }
195     //! Return rectangle describing the paper.
paperLayout196     Rect paper() const { return Rect(-iOrigin, iPaperSize - iOrigin); }
197     //! Dimensions of the media.
198     Vector iPaperSize;
199     //! Origin of the Ipe coordinate system relative to the paper.
200     Vector iOrigin;
201     //! Size of the frame (the drawing area).
202     Vector iFrameSize;
203     //! Paragraph skip (between textboxes).
204     double iParagraphSkip;
205     //! Crop paper to drawing.
206     bool iCrop;
207   };
208 
209   //! Padding for text bounding box.
210   /*! \ingroup attr */
211   struct TextPadding {
212   public:
213     double iLeft, iRight, iTop, iBottom;
214   };
215 
216   struct Effect {
217   public:
218     //! The various fancy effects that Acrobat Reader will show.
219     enum TEffect {
220       ENormal, ESplitHI, ESplitHO, ESplitVI, ESplitVO,
221       EBlindsH, EBlindsV, EBoxI, EBoxO,
222       EWipeLR, EWipeBT, EWipeRL, EWipeTB,
223       EDissolve, EGlitterLR, EGlitterTB, EGlitterD };
224 
225     Effect();
226     void pageDictionary(Stream &stream) const;
227 
228   public:
229     TEffect iEffect;
230     int iTransitionTime;
231     int iDuration;
232   };
233 
234   // --------------------------------------------------------------------
235 
236   class Repository {
237   public:
238     static Repository *get();
239     static void cleanup();
240     String toString(int index) const;
241     int toIndex(String str);
242     // int getIndex(String str) const;
243   private:
244     Repository();
245     static Repository *singleton;
246     std::vector<String> iStrings;
247   };
248 
249   // --------------------------------------------------------------------
250 
251   class Attribute {
252     enum { EMiniMask = 0xc0000000, ETypeMask = 0xe0000000,
253 	   ESymbolic = 0x80000000, EFixed = 0x40000000,
254 	   EAbsolute = 0xc0000000, EEnum = 0xe0000000,
255 	   EFixedMask = 0x3fffffff, ENameMask = 0x1fffffff,
256 	   EWhiteValue = ((1000 << 20) + (1000 << 10) + 1000),
257 	   EOneValue = EFixed|1000 };
258 
259   public:
260     //! Default constructor.
Attribute()261     explicit Attribute() { /* nothing */ }
262 
263     explicit Attribute(bool symbolic, String name);
264     explicit Attribute(Fixed value);
265     explicit Attribute(Color color);
Boolean(bool flag)266     static Attribute Boolean(bool flag) { return Attribute(EEnum + flag); }
Attribute(THorizontalAlignment align)267     explicit Attribute(THorizontalAlignment align) { iName = EEnum + align +2; }
Attribute(TVerticalAlignment align)268     explicit Attribute(TVerticalAlignment align) { iName = EEnum + align + 5; }
Attribute(TLineJoin join)269     explicit Attribute(TLineJoin join) { iName = EEnum + join + 9; }
Attribute(TLineCap cap)270     explicit Attribute(TLineCap cap) { iName = EEnum + cap + 13; }
Attribute(TFillRule rule)271     explicit Attribute(TFillRule rule) { iName = EEnum + rule + 17; }
Attribute(TPinned pin)272     explicit Attribute(TPinned pin) { iName = EEnum + pin + 20; }
Attribute(TTransformations trans)273     explicit Attribute(TTransformations trans) { iName = EEnum + trans + 24; }
Attribute(TPathMode pm)274     explicit Attribute(TPathMode pm) { iName = EEnum + pm + 27; }
Attribute(TSplineType st)275     explicit Attribute(TSplineType st) { iName = EEnum + st + 30; }
276 
277     //! Is it symbolic?
isSymbolic()278     inline bool isSymbolic() const {
279       return ((iName & ETypeMask) == ESymbolic); }
280     //! Is it an absolute string value?
isString()281     inline bool isString() const {
282       return ((iName & ETypeMask) == EAbsolute); }
283     //! Is it a color?
isColor()284     inline bool isColor() const {
285       return ((iName & EMiniMask)  == 0); }
286     //! Is it a number?
isNumber()287     inline bool isNumber() const {
288       return ((iName & EMiniMask) == EFixed); }
289     //! Is it an enumeration?
isEnum()290     inline bool isEnum() const {
291       return ((iName & ETypeMask) == EEnum); }
292 
293     //! Is it a boolean?
isBoolean()294     inline bool isBoolean() const {
295       return (isEnum() && 0 <= index() && index() <= 1); }
296 
297     //! Is it the symbolic name "normal"?
isNormal()298     inline bool isNormal() const { return (iName == ESymbolic); }
299 
300     //! Return index into Repository.
index()301     inline int index() const { return iName & ENameMask; }
302 
internal()303     int internal() const { return iName; }
304 
305     String string() const;
306     Fixed number() const;
307     Color color() const;
308 
boolean()309     bool boolean() const { return bool(index()); }
horizontalAlignment()310     THorizontalAlignment horizontalAlignment() const {
311       return THorizontalAlignment(index() - 2); }
verticalAlignment()312     TVerticalAlignment verticalAlignment() const {
313       return TVerticalAlignment(index() - 5); }
lineJoin()314     TLineJoin lineJoin() const {return TLineJoin(index() - 9); }
lineCap()315     TLineCap lineCap() const { return TLineCap(index() - 13); }
fillRule()316     TFillRule fillRule() const { return TFillRule(index() - 17); }
pinned()317     TPinned pinned() const { return TPinned(index() - 20); }
transformations()318     TTransformations transformations() const {
319       return TTransformations(index() - 24); }
pathMode()320     TPathMode pathMode() const { return TPathMode(index() - 27); }
splineType()321     TSplineType splineType() const { return TSplineType(index() - 30); }
322 
323     //! Are two values equal (only compares index!)
324     inline bool operator==(const Attribute &rhs) const {
325       return iName == rhs.iName; }
326 
327     //! Are two values different (only compares index!)
328     inline bool operator!=(const Attribute &rhs) const {
329       return iName != rhs.iName; }
330 
331     //! Create absolute black color.
BLACK()332     inline static Attribute BLACK() { return Attribute(0); }
333     //! Create absolute white color.
WHITE()334     inline static Attribute WHITE() { return Attribute(EWhiteValue); }
335     //! Create absolute number one.
ONE()336     inline static Attribute ONE() { return Attribute(EOneValue); }
337 
338     //! Create symbolic attribute "normal".
NORMAL()339     inline static Attribute NORMAL() { return Attribute(ESymbolic); }
340     //! Create symbolic attribute "undefined"
UNDEFINED()341     inline static Attribute UNDEFINED() { return Attribute(ESymbolic + 1); }
342     //! Create symbolic attribute "Background"
BACKGROUND()343     inline static Attribute BACKGROUND() { return Attribute(ESymbolic + 2); }
344     //! Create symbolic attribute "sym-stroke"
SYM_STROKE()345     inline static Attribute SYM_STROKE() { return Attribute(ESymbolic + 3); }
346     //! Create symbolic attribute "sym-fill"
SYM_FILL()347     inline static Attribute SYM_FILL() { return Attribute(ESymbolic + 4); }
348     //! Create symbolic attribute "sym-pen"
SYM_PEN()349     inline static Attribute SYM_PEN() { return Attribute(ESymbolic + 5); }
350     //! Create symbolic attribute "arrow/normal(spx)"
ARROW_NORMAL()351     inline static Attribute ARROW_NORMAL() { return Attribute(ESymbolic + 6); }
352     //! Create symbolic attribute "opaque"
OPAQUE()353     inline static Attribute OPAQUE() { return Attribute(ESymbolic + 7); }
354     //! Create symbolic attribute "arrow/arc(spx)"
ARROW_ARC()355     inline static Attribute ARROW_ARC() { return Attribute(ESymbolic + 8); }
356     //! Create symbolic attribute "arrow/farc(spx)"
ARROW_FARC()357     inline static Attribute ARROW_FARC() { return Attribute(ESymbolic + 9); }
358     //! Create symbolic attribute "arrow/ptarc(spx)"
ARROW_PTARC()359     inline static Attribute ARROW_PTARC() { return Attribute(ESymbolic + 10); }
360     //! Create symbolic attribute "arrow/fptarc(spx)"
ARROW_FPTARC()361     inline static Attribute ARROW_FPTARC() { return Attribute(ESymbolic + 11); }
362 
363     //! Is it one of the symbolic attributes "arrow/*arc(spc)"?
isArcArrow()364     inline bool isArcArrow() const {
365       return ESymbolic + 8 <= iName && iName <= ESymbolic + 11;
366     }
367 
368     bool isMidArrow() const;
369 
370     static Attribute makeColor(String str, Attribute deflt);
371     static Attribute makeScalar(String str, Attribute deflt);
372     static Attribute makeDashStyle(String str);
373     static Attribute makeTextSize(String str);
374 
375     static Attribute normal(Kind kind);
376 
377   private:
Attribute(int index)378     inline Attribute(int index) : iName(index) { /* nothing */ }
379     explicit Attribute(bool symbolic, int index);
380   private:
381     uint32_t iName;
382 
383     friend class StyleSheet;
384   };
385 
386   /*! \var AttributeSeq
387     \ingroup attr
388     \brief A sequence of attribute values.
389   */
390   typedef std::vector<Attribute> AttributeSeq;
391 
392   // --------------------------------------------------------------------
393 
394   /*! \var AttributeMapping
395     \ingroup attr
396     \brief Mapping one symbolic attribute to another one
397   */
398   struct AttributeMapping {
399     Kind kind;
400     Attribute from;
401     Attribute to;
402   };
403 
404   class AttributeMap {
405   public:
count()406     int count() const noexcept { return iMap.size(); }
407     Attribute map(Kind kind, Attribute sym) const;
408     void saveAsXml(Stream &stream) const;
409     void add(const AttributeMapping &map);
410   public:
411     std::vector<AttributeMapping> iMap;
412   };
413 
414   // --------------------------------------------------------------------
415 
416   class AllAttributes {
417   public:
418     AllAttributes();
419     TPathMode iPathMode;        //!< Should we stroke and/or fill?
420     Attribute iStroke;          //!< Stroke color.
421     Attribute iFill;            //!< Fill color.
422     Attribute iDashStyle;       //!< Dash style.
423     Attribute iPen;             //!< Pen (that is, line width).
424     bool iFArrow;               //!< Arrow forward?
425     bool iRArrow;               //!< Reverse arrow?
426     Attribute iFArrowShape;     //!< Shape of forward arrows
427     Attribute iRArrowShape;     //!< Shape of reverse arrows
428     Attribute iFArrowSize;      //!< Forward arrow size.
429     Attribute iRArrowSize;      //!< Reverse arrow size.
430     Attribute iSymbolSize;      //!< Symbol size.
431     Attribute iTextSize;        //!< Text size.
432     //! Horizontal alignment of label objects.
433     THorizontalAlignment iHorizontalAlignment;
434     //! Vertical alignment of label objects.
435     TVerticalAlignment iVerticalAlignment;
436     Attribute iTextStyle;       //!< Text style for minipages.
437     Attribute iLabelStyle;      //!< Text style for labels.
438     TPinned iPinned;            //!< Pinned status.
439     //! Should newly created text be transformable?
440     /*! If this is false, newly created text will only allow
441       translations.  Otherwise, the value of iTranslations is used (as
442       for other objects). */
443     bool iTransformableText;
444     /*! What kind of splines should be created? */
445     TSplineType iSplineType;
446     //! Allowed transformations.
447     TTransformations iTransformations;
448     TLineJoin iLineJoin;        //!< Line join style.
449     TLineCap iLineCap;          //!< Line cap style.
450     TFillRule iFillRule;        //!< Shape fill rule.
451     Attribute iOpacity;         //!< Opacity.
452     Attribute iStrokeOpacity;   //!< Stroke opacity.
453     Attribute iTiling;          //!< Tiling pattern.
454     Attribute iGradient;        //!< Gradient pattern.
455     Attribute iMarkShape;       //!< Shape of Mark to create.
456   };
457 
458   // --------------------------------------------------------------------
459 
460   /*! \relates Color */
461   inline Stream &operator<<(Stream &stream, const Color &attr)
462   {
463     attr.save(stream); return stream;
464   }
465 
466 } // namespace
467 
468 // --------------------------------------------------------------------
469 #endif
470