kicad-source/include/eda_text.h
jean-pierre charras a075a80b3c Move all CTL_OMIT_xxx flags definitions into a new file ctl_flags.h
Previously, they were defined in different files, and sometimes redefined.
This change should not create an actual code change.
However, this move shows there are the same value used for different flags,
so another fix should be made later.
2024-07-14 18:10:37 +02:00

451 lines
16 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2004-2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef EDA_TEXT_H_
#define EDA_TEXT_H_
#include <memory>
#include <vector>
#include <outline_mode.h>
#include <eda_search_data.h>
#include <font/glyph.h>
#include <font/text_attributes.h>
class OUTPUTFORMATTER;
class SHAPE_COMPOUND;
class SHAPE_POLY_SET;
// These are only here for algorithmic safety, not to tell the user what to do.
// PL_EDITOR has the least resolution (its internal units are microns), so the min size is chosen
// to yield 1 in PL_EDITOR.
// The max size chosen is somewhat arbitrary, but no one has complained yet.
#define TEXT_MIN_SIZE_MM 0.001 ///< Minimum text size (1 micron).
#define TEXT_MAX_SIZE_MM 250.0 ///< Maximum text size in mm (~10 inches)
namespace KIGFX
{
class RENDER_SETTINGS;
class COLOR4D;
}
namespace KIFONT
{
class METRICS;
}
using KIGFX::RENDER_SETTINGS;
using KIGFX::COLOR4D;
/**
* This is the "default-of-the-default" hardcoded text size; individual application define their
* own default policy starting with this (usually with a user option or project).
*/
#define DEFAULT_SIZE_TEXT 50 // default text height (in mils, i.e. 1/1000")
/**
* A mix-in class (via multiple inheritance) that handles texts such as labels, parts,
* components, or footprints. Because it's a mix-in class, care is used to provide
* function names (accessors) that to not collide with function names likely to be seen
* in the combined derived classes.
*/
class EDA_TEXT
{
public:
EDA_TEXT( const EDA_IU_SCALE& aIuScale, const wxString& aText = wxEmptyString );
EDA_TEXT( const EDA_TEXT& aText );
virtual ~EDA_TEXT();
EDA_TEXT& operator=( const EDA_TEXT& aItem );
/**
* Return the string associated with the text object.
*
* @return a const wxString reference containing the string of the item.
*/
virtual const wxString& GetText() const { return m_text; }
/**
* Return the string actually shown after processing of the base text.
*
* @param aAllowExtraText is true to allow adding more text than the initial expanded text,
* for intance a title, a prefix for texts in display functions.
* False to disable any added text (for instance when writing the shown text in netlists).
* @param aDepth is used to prevent infinite recursions and loops when expanding
* text variables.
*/
virtual wxString GetShownText( bool aAllowExtraText, int aDepth = 0 ) const
{
return m_shown_text;
}
/**
* Indicates the ShownText has text var references which need to be processed.
*/
bool HasTextVars() const { return m_shown_text_has_text_var_refs; }
virtual void SetText( const wxString& aText );
/**
* The TextThickness is that set by the user. The EffectiveTextPenWidth also factors
* in bold text and thickness clamping.
*/
void SetTextThickness( int aWidth );
int GetTextThickness() const { return m_attributes.m_StrokeWidth; };
/**
* The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
*/
int GetEffectiveTextPenWidth( int aDefaultPenWidth = 0 ) const;
virtual void SetTextAngle( const EDA_ANGLE& aAngle );
const EDA_ANGLE& GetTextAngle() const { return m_attributes.m_Angle; }
// For property system:
void SetTextAngleDegrees( double aOrientation )
{
SetTextAngle( EDA_ANGLE( aOrientation, DEGREES_T ) );
}
double GetTextAngleDegrees() const { return m_attributes.m_Angle.AsDegrees(); }
void SetItalic( bool aItalic );
bool IsItalic() const { return m_attributes.m_Italic; }
void SetBold( bool aBold );
void SetBoldFlag( bool aBold );
bool IsBold() const { return m_attributes.m_Bold; }
virtual void SetVisible( bool aVisible );
virtual bool IsVisible() const { return m_attributes.m_Visible; }
void SetMirrored( bool isMirrored );
bool IsMirrored() const { return m_attributes.m_Mirrored; }
/**
* @param aAllow true if ok to use multiline option, false if ok to use only single line
* text. (Single line is faster in calculations than multiline.)
*/
void SetMultilineAllowed( bool aAllow );
bool IsMultilineAllowed() const { return m_attributes.m_Multiline; }
void SetHorizJustify( GR_TEXT_H_ALIGN_T aType );
GR_TEXT_H_ALIGN_T GetHorizJustify() const { return m_attributes.m_Halign; };
void SetVertJustify( GR_TEXT_V_ALIGN_T aType );
GR_TEXT_V_ALIGN_T GetVertJustify() const { return m_attributes.m_Valign; };
void SetKeepUpright( bool aKeepUpright );
bool IsKeepUpright() const { return m_attributes.m_KeepUpright; }
void FlipHJustify()
{
if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
else if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
}
/**
* Set the text attributes from another instance.
*/
void SetAttributes( const EDA_TEXT& aSrc, bool aSetPosition = true );
/**
* Swap the text attributes of the two involved instances.
*/
void SwapAttributes( EDA_TEXT& aTradingPartner );
void SwapText( EDA_TEXT& aTradingPartner );
void CopyText( const EDA_TEXT& aSrc );
void SetAttributes( const TEXT_ATTRIBUTES& aTextAttrs ) { m_attributes = aTextAttrs; }
const TEXT_ATTRIBUTES& GetAttributes() const { return m_attributes; }
/**
* Helper function used in search and replace dialog.
*
* Perform a text replace using the find and replace criteria in \a aSearchData.
*
* @param aSearchData A reference to a EDA_SEARCH_DATA object containing the
* search and replace criteria.
* @return True if the text item was modified, otherwise false.
*/
bool Replace( const EDA_SEARCH_DATA& aSearchData );
bool IsDefaultFormatting() const;
void SetFont( KIFONT::FONT* aFont );
KIFONT::FONT* GetFont() const { return m_attributes.m_Font; }
wxString GetFontName() const;
void SetFontIndex( int aIdx );
int GetFontIndex() const;
void SetLineSpacing( double aLineSpacing );
double GetLineSpacing() const { return m_attributes.m_LineSpacing; }
void SetTextSize( VECTOR2I aNewSize, bool aEnforceMinTextSize = true );
VECTOR2I GetTextSize() const { return m_attributes.m_Size; }
void SetTextWidth( int aWidth );
int GetTextWidth() const { return m_attributes.m_Size.x; }
void SetTextHeight( int aHeight );
int GetTextHeight() const { return m_attributes.m_Size.y; }
void SetTextColor( const COLOR4D& aColor ) { m_attributes.m_Color = aColor; }
COLOR4D GetTextColor() const { return m_attributes.m_Color; }
void SetTextPos( const VECTOR2I& aPoint );
const VECTOR2I& GetTextPos() const { return m_pos; }
void SetTextX( int aX );
void SetTextY( int aY );
void Offset( const VECTOR2I& aOffset );
void Empty();
static GR_TEXT_H_ALIGN_T MapHorizJustify( int aHorizJustify );
static GR_TEXT_V_ALIGN_T MapVertJustify( int aVertJustify );
/**
* Print this text object to the device context \a aDC.
*
* @param aDC the current Device Context.
* @param aOffset draw offset (usually (0,0)).
* @param aColor text color.
* @param aDisplay_mode #FILLED or #SKETCH.
*/
void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset, const COLOR4D& aColor,
OUTLINE_MODE aDisplay_mode = FILLED );
/**
* build a list of segments (SHAPE_SEGMENT) to describe a text shape.
* @param aTriangulate: true to build also the triangulation of each shape
* @param aUseTextRotation: true to use the actual text draw rotation.
* false to build a list of shape for a not rotated text ("native" shapes).
*/
std::shared_ptr<SHAPE_COMPOUND> GetEffectiveTextShape( bool aTriangulate = true,
const BOX2I& aBBox = BOX2I(),
const EDA_ANGLE& aAngle = ANGLE_0 ) const;
/**
* Test if \a aPoint is within the bounds of this object.
*
* @param aPoint A VECTOR2I to test.
* @param aAccuracy Amount to inflate the bounding box.
* @return true if a hit, else false.
*/
virtual bool TextHitTest( const VECTOR2I& aPoint, int aAccuracy = 0 ) const;
/**
* Test if object bounding box is contained within or intersects \a aRect.
*
* @param aRect Rect to test against.
* @param aContains Test for containment instead of intersection if true.
* @param aAccuracy Amount to inflate the bounding box.
* @return true if a hit, else false.
*/
virtual bool TextHitTest( const BOX2I& aRect, bool aContains, int aAccuracy = 0 ) const;
/**
* Useful in multiline texts to calculate the full text or a line area (for zones filling,
* locate functions....)
*
* @param aLine The line of text to consider. Pass -1 for all lines.
* @return the rect containing the line of text (i.e. the position and the size of one line)
* this rectangle is calculated for 0 orient text.
* If orientation is not 0 the rect must be rotated to match the physical area
*/
BOX2I GetTextBox( int aLine = -1 ) const;
/**
* Return the distance between two lines of text.
*
* Calculates the distance (pitch) between two lines of text. This distance includes the
* interline distance plus room for characters like j, {, and [. It also used for single
* line text, to calculate the text bounding box.
*/
int GetInterline() const;
/**
* @return a wxString with the style name( Normal, Italic, Bold, Bold+Italic).
*/
wxString GetTextStyleName() const;
/**
* Populate \a aPositions with the position of each line of a multiline text, according
* to the vertical justification and the rotation of the whole text.
*
* @param aPositions is the list to populate by the VECTOR2I positions.
* @param aLineCount is the number of lines (not recalculated here for efficiency reasons.
*/
void GetLinePositions( std::vector<VECTOR2I>& aPositions, int aLineCount ) const;
/**
* Return the levenstein distance between two texts.
*
* Return a value of 0.0 - 1.0 where 1.0 is a perfect match.
*/
double Levenshtein( const EDA_TEXT& aOther ) const;
double Similarity( const EDA_TEXT& aOther ) const;
/**
* Output the object to \a aFormatter in s-expression form.
*
* @param aFormatter The #OUTPUTFORMATTER object to write to.
* @param aNestLevel The indentation next level.
* @param aControlBits The control bit definition for object specific formatting.
* @throw IO_ERROR on write error.
*/
virtual void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const;
virtual EDA_ANGLE GetDrawRotation() const { return GetTextAngle(); }
virtual VECTOR2I GetDrawPos() const { return GetTextPos(); }
virtual void ClearRenderCache();
virtual void ClearBoundingBoxCache();
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
GetRenderCache( const KIFONT::FONT* aFont, const wxString& forResolvedText,
const VECTOR2I& aOffset = { 0, 0 } ) const;
// Support for reading the cache from disk.
void SetupRenderCache( const wxString& aResolvedText, const KIFONT::FONT* aFont,
const EDA_ANGLE& aAngle, const VECTOR2I& aOffset );
void AddRenderCacheGlyph( const SHAPE_POLY_SET& aPoly );
int Compare( const EDA_TEXT* aOther ) const;
bool operator==( const EDA_TEXT& aRhs ) const { return Compare( &aRhs ) == 0; }
bool operator<( const EDA_TEXT& aRhs ) const { return Compare( &aRhs ) < 0; }
bool operator>( const EDA_TEXT& aRhs ) const { return Compare( &aRhs ) > 0; }
virtual bool HasHyperlink() const { return !m_hyperlink.IsEmpty(); }
wxString GetHyperlink() const { return m_hyperlink; }
void SetHyperlink( wxString aLink ) { m_hyperlink = aLink; }
void RemoveHyperlink() { m_hyperlink = wxEmptyString; }
/**
* Check if aURL is a valid hyperlink.
*
* @param aURL String to validate
* @return true if aURL is a valid hyperlink
*/
static bool ValidateHyperlink( const wxString& aURL );
/**
* Check if aHref is a valid internal hyperlink.
*
* @param aHref String to validate
* @param aDestination [optional] pointer to populate with the destination page
* @return true if aHref is a valid internal hyperlink. Does *not* check if the destination
* page actually exists.
*/
static bool IsGotoPageHref( const wxString& aHref, wxString* aDestination = nullptr );
/**
* Generate a href to a page in the current schematic.
*
* @param aDestination Destination sheet's page number.
* @return A hyperlink href string that goes to the specified page.
*/
static wxString GotoPageHref( const wxString& aDestination );
protected:
virtual KIFONT::FONT* getDrawFont() const;
virtual const KIFONT::METRICS& getFontMetrics() const;
virtual void cacheShownText();
/**
* Print each line of this EDA_TEXT.
*
* @param aOffset draw offset (usually (0,0)).
* @param aColor text color.
* @param aFillMode FILLED or SKETCH
* @param aText the single line of text to draw.
* @param aPos the position of this line ).
*/
void printOneLineOfText( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset,
const COLOR4D& aColor, OUTLINE_MODE aFillMode, const wxString& aText,
const VECTOR2I& aPos );
protected:
/**
* A hyperlink URL. If empty, this text object is not a hyperlink.
*/
wxString m_hyperlink;
private:
wxString m_text;
wxString m_shown_text; // Cache of unescaped text for efficient access
bool m_shown_text_has_text_var_refs;
std::reference_wrapper<const EDA_IU_SCALE> m_IuScale;
mutable wxString m_render_cache_text;
mutable const KIFONT::FONT* m_render_cache_font;
mutable EDA_ANGLE m_render_cache_angle;
mutable VECTOR2I m_render_cache_offset;
mutable std::vector<std::unique_ptr<KIFONT::GLYPH>> m_render_cache;
mutable bool m_bounding_box_cache_valid;
mutable VECTOR2I m_bounding_box_cache_pos;
mutable int m_bounding_box_cache_line;
mutable BOX2I m_bounding_box_cache;
TEXT_ATTRIBUTES m_attributes;
VECTOR2I m_pos;
};
extern std::ostream& operator<<( std::ostream& aStream, const EDA_TEXT& aAttributes );
template<>
struct std::hash<EDA_TEXT>
{
std::size_t operator()( const EDA_TEXT& aText ) const
{
return hash_val( aText.GetText(), aText.GetAttributes(), aText.GetTextPos().x,
aText.GetTextPos().y );
}
};
#endif // EDA_TEXT_H_