1 /* 2 * This program source code file is part of KiCad, a free EDA CAD application. 3 * 4 * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr 5 * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, you may find one here: 19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 20 * or you may search the http://www.gnu.org website for the version 2 license, 21 * or you may write to the Free Software Foundation, Inc., 22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24 25 #ifndef EDA_TEXT_H_ 26 #define EDA_TEXT_H_ 27 28 #include <memory> 29 #include <vector> 30 31 #include <outline_mode.h> 32 #include <eda_rect.h> 33 34 class OUTPUTFORMATTER; 35 class SHAPE_COMPOUND; 36 class SHAPE_POLY_SET; 37 class wxFindReplaceData; 38 39 40 /** 41 * A helper for the text to polygon callback function. 42 * 43 * These variables are parameters used in #addTextSegmToPoly but #addTextSegmToPoly is a 44 * callback function so the cannot be sent as arguments. 45 */ 46 struct TSEGM_2_POLY_PRMS 47 { 48 int m_textWidth; 49 int m_error; 50 SHAPE_POLY_SET* m_cornerBuffer; 51 }; 52 53 54 /** 55 * Callback function used to convert text segments to polygons. 56 */ 57 extern void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData ); 58 59 60 namespace KIGFX 61 { 62 class RENDER_SETTINGS; 63 class COLOR4D; 64 } 65 66 using KIGFX::RENDER_SETTINGS; 67 using KIGFX::COLOR4D; 68 69 /// Frequent text rotations, used with {Set,Get}TextAngle(), 70 /// in 0.1 degrees for now, hoping to migrate to degrees eventually. 71 #define TEXT_ANGLE_HORIZ 0 72 #define TEXT_ANGLE_VERT 900 73 74 // part of the kicad_plugin.h family of defines. 75 // See kicad_plugin.h for the choice of the value 76 // When set when calling EDA_TEXT::Format, disable writing the "hide" keyword in save file 77 #define CTL_OMIT_HIDE (1 << 6) 78 79 80 // Graphic Text justify: 81 // Values -1,0,1 are used in computations, do not change them 82 enum EDA_TEXT_HJUSTIFY_T { 83 GR_TEXT_HJUSTIFY_LEFT = -1, 84 GR_TEXT_HJUSTIFY_CENTER = 0, 85 GR_TEXT_HJUSTIFY_RIGHT = 1 86 }; 87 88 89 enum EDA_TEXT_VJUSTIFY_T { 90 GR_TEXT_VJUSTIFY_TOP = -1, 91 GR_TEXT_VJUSTIFY_CENTER = 0, 92 GR_TEXT_VJUSTIFY_BOTTOM = 1 93 }; 94 95 96 /** 97 * This is the "default-of-the-default" hardcoded text size; individual 98 * application define their own default policy starting with this 99 * (usually with a user option or project). 100 */ 101 #define DEFAULT_SIZE_TEXT 50 // default text height (in mils, i.e. 1/1000") 102 #define DIM_ANCRE_TEXTE 2 // Anchor size for text 103 104 105 /** 106 * A container for text effects. 107 * 108 * These fields are bundled so they can be easily copied together as a lot. The privacy 109 * policy is established by client (incorporating) code. 110 */ 111 struct TEXT_EFFECTS 112 { 113 TEXT_EFFECTS( int aSetOfBits = 0 ) : bitsTEXT_EFFECTS114 bits( aSetOfBits ), 115 hjustify( GR_TEXT_HJUSTIFY_CENTER ), 116 vjustify( GR_TEXT_VJUSTIFY_CENTER ), 117 penwidth( 0 ), 118 angle( 0.0 ) 119 {} 120 121 int bits; ///< any set of booleans a client uses. 122 signed char hjustify; ///< horizontal justification 123 signed char vjustify; ///< vertical justification 124 wxSize size; 125 int penwidth; 126 double angle; ///< now: 0.1 degrees; future: degrees 127 wxPoint pos; 128 BitTEXT_EFFECTS129 void Bit( int aBit, bool aValue ) { aValue ? bits |= (1<<aBit) : bits &= ~(1<<aBit); } BitTEXT_EFFECTS130 bool Bit( int aBit ) const { return bits & (1<<aBit); } 131 }; 132 133 134 /** 135 * A mix-in class (via multiple inheritance) that handles texts such as labels, parts, 136 * components, or footprints. Because it's a mix-in class, care is used to provide 137 * function names (accessors) that to not collide with function names likely to be seen 138 * in the combined derived classes. 139 */ 140 class EDA_TEXT 141 { 142 public: 143 EDA_TEXT( const wxString& text = wxEmptyString ); 144 145 EDA_TEXT( const EDA_TEXT& aText ); 146 147 virtual ~EDA_TEXT(); 148 149 /** 150 * Return the string associated with the text object. 151 * 152 * @return a const wxString reference containing the string of the item. 153 */ GetText()154 virtual const wxString& GetText() const { return m_text; } 155 156 /** 157 * Return the string actually shown after processing of the base text. 158 * 159 * @param aDepth is used to prevent infinite recursions and loops when expanding 160 * text variables. 161 */ 162 virtual wxString GetShownText( int aDepth = 0 ) const { return m_shown_text; } 163 164 /** 165 * Returns a shortened version (max 15 characters) of the shown text 166 */ 167 wxString ShortenedShownText() const; 168 169 /** 170 * Indicates the ShownText has text var references which need to be processed. 171 */ HasTextVars()172 bool HasTextVars() const { return m_shown_text_has_text_var_refs; } 173 174 virtual void SetText( const wxString& aText ); 175 176 /** 177 * The TextThickness is that set by the user. The EffectiveTextPenWidth also factors 178 * in bold text and thickness clamping. 179 */ SetTextThickness(int aWidth)180 void SetTextThickness( int aWidth ) { m_e.penwidth = aWidth; }; GetTextThickness()181 int GetTextThickness() const { return m_e.penwidth; }; 182 183 /** 184 * The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultWidth. 185 */ 186 int GetEffectiveTextPenWidth( int aDefaultWidth = 0 ) const; 187 SetTextAngle(double aAngle)188 virtual void SetTextAngle( double aAngle ) 189 { 190 // Higher level classes may be more restrictive than this by overloading 191 // SetTextAngle() or merely calling EDA_TEXT::SetTextAngle() after clamping 192 // aAngle before calling this lowest inline accessor. 193 m_e.angle = aAngle; 194 } GetTextAngle()195 double GetTextAngle() const { return m_e.angle; } 196 GetTextAngleDegrees()197 double GetTextAngleDegrees() const { return GetTextAngle() / 10.0; } GetTextAngleRadians()198 double GetTextAngleRadians() const { return GetTextAngle() * M_PI/1800; } 199 SetItalic(bool isItalic)200 void SetItalic( bool isItalic ) { m_e.Bit( TE_ITALIC, isItalic ); } IsItalic()201 bool IsItalic() const { return m_e.Bit( TE_ITALIC ); } 202 SetBold(bool aBold)203 void SetBold( bool aBold ) { m_e.Bit( TE_BOLD, aBold); } IsBold()204 bool IsBold() const { return m_e.Bit( TE_BOLD ); } 205 SetVisible(bool aVisible)206 virtual void SetVisible( bool aVisible ) { m_e.Bit( TE_VISIBLE, aVisible ); } IsVisible()207 virtual bool IsVisible() const { return m_e.Bit( TE_VISIBLE ); } 208 SetMirrored(bool isMirrored)209 void SetMirrored( bool isMirrored ) { m_e.Bit( TE_MIRROR, isMirrored ); } IsMirrored()210 bool IsMirrored() const { return m_e.Bit( TE_MIRROR ); } 211 212 /** 213 * @param aAllow true if ok to use multiline option, false if ok to use only single line 214 * text. (Single line is faster in calculations than multiline.) 215 */ SetMultilineAllowed(bool aAllow)216 void SetMultilineAllowed( bool aAllow ) { m_e.Bit( TE_MULTILINE, aAllow ); } IsMultilineAllowed()217 bool IsMultilineAllowed() const { return m_e.Bit( TE_MULTILINE ); } 218 GetHorizJustify()219 EDA_TEXT_HJUSTIFY_T GetHorizJustify() const { return EDA_TEXT_HJUSTIFY_T( m_e.hjustify ); }; GetVertJustify()220 EDA_TEXT_VJUSTIFY_T GetVertJustify() const { return EDA_TEXT_VJUSTIFY_T( m_e.vjustify ); }; 221 SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)222 void SetHorizJustify( EDA_TEXT_HJUSTIFY_T aType ) { m_e.hjustify = aType; }; SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)223 void SetVertJustify( EDA_TEXT_VJUSTIFY_T aType ) { m_e.vjustify = aType; }; 224 225 /** 226 * Set the text effects from another instance. 227 * 228 * #TEXT_EFFECTS is not exposed in the public API, but includes everything except the actual 229 * text string itself. 230 */ 231 void SetEffects( const EDA_TEXT& aSrc ); 232 233 /** 234 * Swap the text effects of the two involved instances. 235 * 236 * #TEXT_EFFECTS is not exposed in the public API, but includes everything except the actual 237 * text string itself. 238 */ 239 void SwapEffects( EDA_TEXT& aTradingPartner ); 240 241 void SwapText( EDA_TEXT& aTradingPartner ); 242 243 void CopyText( const EDA_TEXT& aSrc ); 244 245 /** 246 * Helper function used in search and replace dialog. 247 * 248 * Perform a text replace using the find and replace criteria in \a aSearchData. 249 * 250 * @param aSearchData A reference to a wxFindReplaceData object containing the 251 * search and replace criteria. 252 * @return True if the text item was modified, otherwise false. 253 */ 254 bool Replace( const wxFindReplaceData& aSearchData ); 255 256 bool IsDefaultFormatting() const; 257 SetTextSize(const wxSize & aNewSize)258 void SetTextSize( const wxSize& aNewSize ) { m_e.size = aNewSize; } GetTextSize()259 const wxSize& GetTextSize() const { return m_e.size; } 260 SetTextWidth(int aWidth)261 void SetTextWidth( int aWidth ) { m_e.size.x = aWidth; } GetTextWidth()262 int GetTextWidth() const { return m_e.size.x; } 263 SetTextHeight(int aHeight)264 void SetTextHeight( int aHeight ) { m_e.size.y = aHeight; } GetTextHeight()265 int GetTextHeight() const { return m_e.size.y; } 266 SetTextPos(const wxPoint & aPoint)267 void SetTextPos( const wxPoint& aPoint ) { m_e.pos = aPoint; } GetTextPos()268 const wxPoint& GetTextPos() const { return m_e.pos; } 269 SetTextX(int aX)270 void SetTextX( int aX ) { m_e.pos.x = aX; } SetTextY(int aY)271 void SetTextY( int aY ) { m_e.pos.y = aY; } 272 Offset(const wxPoint & aOffset)273 void Offset( const wxPoint& aOffset ) { m_e.pos += aOffset; } 274 Empty()275 void Empty() { m_text.Empty(); } 276 277 static EDA_TEXT_HJUSTIFY_T MapHorizJustify( int aHorizJustify ); 278 279 static EDA_TEXT_VJUSTIFY_T MapVertJustify( int aVertJustify ); 280 281 /** 282 * Print this text object to the device context \a aDC. 283 * 284 * @param aDC the current Device Context. 285 * @param aOffset draw offset (usually (0,0)). 286 * @param aColor text color. 287 * @param aDisplay_mode #FILLED or #SKETCH. 288 */ 289 void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, 290 const COLOR4D& aColor, OUTLINE_MODE aDisplay_mode = FILLED ); 291 292 /** 293 * Convert the text shape to a list of segment. 294 * 295 * Each segment is stored as 2 wxPoints: the starting point and the ending point 296 * there are therefore 2*n points. 297 */ 298 std::vector<wxPoint> TransformToSegmentList() const; 299 300 /** 301 * Convert the text bounding box to a rectangular polygon depending on the text 302 * orientation, the bounding box is not always horizontal or vertical 303 * 304 * Used in filling zones calculations 305 * Circles and arcs are approximated by segments 306 * 307 * @param aCornerBuffer a buffer to store the polygon. 308 * @param aClearanceValue the clearance around the text bounding box 309 * to the real clearance value (usually near from 1.0). 310 */ 311 void TransformBoundingBoxWithClearanceToPolygon( SHAPE_POLY_SET* aCornerBuffer, 312 int aClearanceValue ) const; 313 314 std::shared_ptr<SHAPE_COMPOUND> GetEffectiveTextShape() const; 315 316 /** 317 * Test if \a aPoint is within the bounds of this object. 318 * 319 * @param aPoint A wxPoint to test. 320 * @param aAccuracy Amount to inflate the bounding box. 321 * @return true if a hit, else false. 322 */ 323 virtual bool TextHitTest( const wxPoint& aPoint, int aAccuracy = 0 ) const; 324 325 /** 326 * Test if object bounding box is contained within or intersects \a aRect. 327 * 328 * @param aRect Rect to test against. 329 * @param aContains Test for containment instead of intersection if true. 330 * @param aAccuracy Amount to inflate the bounding box. 331 * @return true if a hit, else false. 332 */ 333 virtual bool TextHitTest( const EDA_RECT& aRect, bool aContains, int aAccuracy = 0 ) const; 334 335 /** 336 * @return the text length in internal units. 337 * @param aLine the line of text to consider. For single line text, this parameter 338 * is always m_Text. 339 * @param aThickness the stroke width of the text. 340 */ 341 int LenSize( const wxString& aLine, int aThickness ) const; 342 343 /** 344 * Useful in multiline texts to calculate the full text or a line area (for zones filling, 345 * locate functions....) 346 * 347 * @param aLine The line of text to consider. Pass -1 for all lines. 348 * @param aInvertY Invert the Y axis when calculating bounding box. 349 * @return the rect containing the line of text (i.e. the position and the size of one line) 350 * this rectangle is calculated for 0 orient text. 351 * If orientation is not 0 the rect must be rotated to match the physical area 352 */ 353 EDA_RECT GetTextBox( int aLine = -1, bool aInvertY = false ) const; 354 355 /** 356 * Return the distance between two lines of text. 357 * 358 * Calculates the distance (pitch) between two lines of text. This distance includes the 359 * interline distance plus room for characters like j, {, and [. It also used for single 360 * line text, to calculate the text bounding box. 361 */ 362 int GetInterline() const; 363 364 /** 365 * @return a wxString with the style name( Normal, Italic, Bold, Bold+Italic). 366 */ 367 wxString GetTextStyleName() const; 368 369 /** 370 * Populate \a aPositions with the position of each line of a multiline text, according 371 * to the vertical justification and the rotation of the whole text. 372 * 373 * @param aPositions is the list to populate by the wxPoint positions. 374 * @param aLineCount is the number of lines (not recalculated here for efficiency reasons. 375 */ 376 void GetLinePositions( std::vector<wxPoint>& aPositions, int aLineCount ) const; 377 378 /** 379 * Output the object to \a aFormatter in s-expression form. 380 * 381 * @param aFormatter The #OUTPUTFORMATTER object to write to. 382 * @param aNestLevel The indentation next level. 383 * @param aControlBits The control bit definition for object specific formatting. 384 * @throw IO_ERROR on write error. 385 */ 386 virtual void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const; 387 GetDrawRotation()388 virtual double GetDrawRotation() const { return GetTextAngle(); } GetDrawPos()389 virtual wxPoint GetDrawPos() const { return GetTextPos(); } GetDrawHorizJustify()390 virtual EDA_TEXT_HJUSTIFY_T GetDrawHorizJustify() const { return GetHorizJustify(); }; GetDrawVertJustify()391 virtual EDA_TEXT_VJUSTIFY_T GetDrawVertJustify() const { return GetVertJustify(); }; 392 393 int Compare( const EDA_TEXT* aOther ) const; 394 395 private: 396 void cacheShownText(); 397 398 /** 399 * Print each line of this EDA_TEXT.. 400 * 401 * @param aOffset draw offset (usually (0,0)). 402 * @param aColor text color. 403 * @param aFillMode FILLED or SKETCH 404 * @param aText the single line of text to draw. 405 * @param aPos the position of this line ). 406 */ 407 void printOneLineOfText( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, 408 const COLOR4D& aColor, OUTLINE_MODE aFillMode, const wxString& aText, 409 const wxPoint& aPos ); 410 411 wxString m_text; 412 wxString m_shown_text; // Cache of unescaped text for efficient access 413 bool m_shown_text_has_text_var_refs; 414 415 TEXT_EFFECTS m_e; // Private bitflags for text styling. API above 416 // provides accessor funcs. 417 enum TE_FLAGS { 418 TE_MIRROR, 419 TE_ITALIC, 420 TE_BOLD, 421 TE_MULTILINE, 422 TE_VISIBLE, 423 }; 424 }; 425 426 427 #endif // EDA_TEXT_H_ 428