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