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