/* Copyright (c) 2008-2022 Jan W. Krieger () with contributions from: Razi Alavizadeh This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation, either version 2.1 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 Lesser General Public License (LGPL) for more details. You should have received a copy of the GNU Lesser General Public License (LGPL) along with this program. If not, see . */ #ifndef JKQTMATHTEXTSYMBOLNODE_H #define JKQTMATHTEXTSYMBOLNODE_H #include "jkqtmathtext/jkqtmathtext_imexport.h" #include "jkqtmathtext/jkqtmathtexttools.h" #include "jkqtmathtext/nodes/jkqtmathtextnode.h" #include #include class JKQTMathText; // forward // JKQTMATHTEXT_LIB_EXPORT /** \brief subclass representing one symbol (e.g. \c \\alpha , \c \\cdot ...) node in the syntax tree * \ingroup jkqtmathtext_items * * All supported symbols are stored in the static table symbols, which is filled by fillSymbolTable(). * The latter function is also the customization point for new symbols: * - For each symbol, the instruction name is stored as key, e.g. for \c \\alpha the key \c "alpha" is stored. * - for each instruction a SymbolFullProps describes the symbol and stores how to draw it. * - Each symbol has global properties (GlobalSymbolFlags, e.g. how to treat it's with etz.) and a set of representations. * Each representation is for one font-encoding (JKQTMathTextFontEncoding, i.e. Unicode, WinSymbol or Standard) * - each encoding representation SymbolProps specifies a text to represent the symol in SymbolProps::symbol and * can have additional flags, properties etc. * . * * Font Lookup for symbols works as follows in JKQTMathTextSymbolNode: * - if a character is found in the current (or to be used) font, it is taken from there (the font is specified in * SymbolFullProps::fontType) * - if the character is not found, it is looked for in the fallback fonts MTEFallbackGreek and MTEFallbackSymbols * - as a last resort, some symbols can be created otherwise, so if neither of the two options above * contain the required symbol, the symbol might be synthesized otherwise, or a rectangle with the size of "X" is drawn instead * . * */ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextSymbolNode: public JKQTMathTextNode { public: explicit JKQTMathTextSymbolNode(JKQTMathText* parent, const QString& name, bool addWhitespace); virtual ~JKQTMathTextSymbolNode() override; /** \copydoc JKQTMathTextNode::getTypeName() */ virtual QString getTypeName() const override; /** \copydoc JKQTMathTextNode::draw() */ virtual double draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; /** \copydoc JKQTMathTextNode::toHtml() */ virtual bool toHtml(QString& html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) override; /** \copydoc symbolName */ QString getSymbolName() const; /** \copydoc addWhitespace */ bool getAddWhitespace() const; /** \brief determine the size of the node, calls getSizeInternal() implementation of the actual type \see getSizeInternal() * * \param painter painter to use for determining the size * \param currentEv current environment object * \param[out] width width of the block/node * \param[out] baselineHeight distance from the bottom of the block/node-box to the baseline * \param[out] overallHeight overall height (bottom to top) of the node, the ascent is \c overallHeight-baselineHeight * \param[out] strikeoutPos position of the strikeout-line * \param[out] subSuperXCorrection x-correction as described for JKQTMathParser::intsubsuper_xcorrection_factor for placing sub-/superscript below/above the symbol * \param[out] subBesidesXCorrection x-correction as described for JKQTMathParser::intsubbesides_xcorrection_xfactor for placing sub-/superscript below/above the symbol * \param[in] prevNodeSize optional parameter, describing the size of the previous node (on the left). This may be used for layout of some nodes (e.g. sub/super to move correctly next to large parantheses ...) * */ void getSymbolSize(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, double& subSuperXCorrection, double& subBesidesXCorrection, const JKQTMathTextNodeSize* prevNodeSize=nullptr); /** \brief checks whether the given symbol name can be prepresented by this type of node */ static bool hasSymbol(const QString& symbolName); protected: /** \copydoc JKQTMathTextNode::getSizeInternal() */ virtual void getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; /** \copydoc JKQTMathTextNode::getSizeInternal() */ virtual void getSymbolSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, double& subSuperXCorrection, double& subBesidesXCorrection, const JKQTMathTextNodeSize* prevNodeSize=nullptr) ; /** \brief this string will be sent to the drawText method with properly set fonts */ QString symbolName; /** \brief add a whitespace to the symbol? */ bool addWhitespace; /** \brief flags specifying additional symbol features */ enum SymbolFlags: uint64_t { AsOutside= 0, /*!< \brief indicates that no properties are activated */ ItalicOn= 1 << 0, /*!< \brief make font italic in any case */ ItalicOff= 1 << 1, /*!< \brief make font non-italic (i.e. upright) in any case */ BoldOn= 1 << 2, /*!< \brief make font bold in any case */ BoldOff= 1 << 3, /*!< \brief make font non-bold (i,,e, normal weight) in any case */ DrawBar= 1 << 4, /*!< \brief indicates whether to draw a bar (like for \c \\hbar ) */ FlipUpDown=1 << 5, /*!< \brief indicates to flip the given symbol upside-down */ FlipLeftRight=1 << 6, /*!< \brief indicates to flip the given symbol left-right */ Rotate90=1 << 7, /*!< \brief indicates to rotate the symbol 90 degree */ DrawSlash=1 << 8, /*!< \brief indicates to overdraw a backslash (e.g. to combine 0 and / to form \\varnothing ) */ HeightIsAscent= 1 << 9, /*!< \brief if true, the height of the symbol equals the ascent of the font */ Upright=ItalicOff, NormalWeight=BoldOff, }; friend inline SymbolFlags operator~ (SymbolFlags a) { return (SymbolFlags)~static_cast(a); } friend inline SymbolFlags operator| (SymbolFlags a, SymbolFlags b) { return static_cast(static_cast(a) | static_cast(b)); } friend inline SymbolFlags operator& (SymbolFlags a, SymbolFlags b) { return static_cast(static_cast(a) & static_cast(b)); } friend inline SymbolFlags operator^ (SymbolFlags a, SymbolFlags b) { return static_cast(static_cast(a) ^ static_cast(b)); } friend inline SymbolFlags& operator|= (SymbolFlags& a, SymbolFlags b) { return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); } friend inline SymbolFlags& operator&= (SymbolFlags& a, SymbolFlags b) { return reinterpret_cast(reinterpret_cast(a) &= static_cast(b)); } friend inline SymbolFlags& operator^= (SymbolFlags& a, SymbolFlags b) { return reinterpret_cast(reinterpret_cast(a) ^= static_cast(b)); } friend inline bool has(SymbolFlags a, SymbolFlags b) { return (a&b)==b; } /** \brief flags specifying additional symbol features */ enum GlobalSymbolFlags: uint64_t { NoGLobalSymbolFlags= 0, /*!< \brief indicates that no properties are activated */ ExtendWidthInMathmode= 1 << 0, /*!< \brief this symbol has an extended width, when used within a moth-environment/in math-mode */ MakeWhitespaceHalf= 1 << 1, /*!< \brief symbol uses whitespaces in its text (SymbolProps::symbol). These should be typeset as half-spaces */ IntLikeSymbolCorrection= 1 << 2, /*!< \brief symbols, like \c \\int,\\iint,... require a correction in x-direction for subsequent sub-/superscripts ... this flag marks such symbols */ }; friend inline GlobalSymbolFlags operator~ (GlobalSymbolFlags a) { return (GlobalSymbolFlags)~static_cast(a); } friend inline GlobalSymbolFlags operator| (GlobalSymbolFlags a, GlobalSymbolFlags b) { return static_cast(static_cast(a) | static_cast(b)); } friend inline GlobalSymbolFlags operator& (GlobalSymbolFlags a, GlobalSymbolFlags b) { return static_cast(static_cast(a) & static_cast(b)); } friend inline GlobalSymbolFlags operator^ (GlobalSymbolFlags a, GlobalSymbolFlags b) { return static_cast(static_cast(a) ^ static_cast(b)); } friend inline GlobalSymbolFlags& operator|= (GlobalSymbolFlags& a, GlobalSymbolFlags b) { return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); } friend inline GlobalSymbolFlags& operator&= (GlobalSymbolFlags& a, GlobalSymbolFlags b) { return reinterpret_cast(reinterpret_cast(a) &= static_cast(b)); } friend inline GlobalSymbolFlags& operator^= (GlobalSymbolFlags& a, GlobalSymbolFlags b) { return reinterpret_cast(reinterpret_cast(a) ^= static_cast(b)); } friend inline bool has(GlobalSymbolFlags a, GlobalSymbolFlags b) { return (a&b)==b; } /** \brief calculates the bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */ static QRectF getBoundingRect(const QFontMetricsF& fm, const QString& text, GlobalSymbolFlags globalFlags); /** \brief calculates the tight bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */ static QRectF getTightBoundingRect(const QFontMetricsF& fm, const QString& text, GlobalSymbolFlags globalFlags); /** \brief draw \a text at (0,0) using QPainter \a p and taking the flags from \a globalFlags into account */ static void drawText(QPainter &p, const QString &text, GlobalSymbolFlags globalFlags); /** \brief properties of the symbol */ struct SymbolProps { SymbolProps(); /** \brief this constructor sets the given properties and sets html=symbol! replaces whitespaces in \a _ymbol with \c   for html, iff MakeWhitespaceHalf is set in \a _flags*/ SymbolProps(const QString& _symbol, SymbolFlags _flags=AsOutside, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); /** \brief the symbol or text used to render the symbol (i.e. not the name, * e.g. if the instruction/symbol name \c \\int is used, this would be \c QChar(0xF2) , * for \c \\sin it would be \c QString("sin") ...) */ QString symbol; /** \brief if \a symbol is a single character, this returns it, otherwise (empty or multi-character) it returns QChar() */ inline QChar getSymbolSingleChar() const { if (symbol.size()==1) return symbol[0]; return QChar(); } /** \brief flags switching special features */ SymbolFlags flags; /** \brief magnification factor for the font size */ double fontScalingFactor; /** \brief this corrects the y position of a symbol: draws at y <- y+ height*yfactor) */ double yShiftFactor; }; /** \brief properties of the symbol, extends SymbolProps with font... */ struct SymbolFullProps { /** \brief default constructor */ SymbolFullProps(); /** \brief typesets the symbol (described in \a props ) from the specified \a font, \a props is stored with encoding MTFEStandard, an optional HTML-string \A _html can be given */ SymbolFullProps(const QString& font, const SymbolProps& props, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief typesets the \a symbol from the specified \a font, \a props is stored with encoding MTFEStandard, an optional HTML-string \A _html can be given */ SymbolFullProps(const QString& font, const QString& symbol, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief \a props is stored with encoding MTFEStandard, an optional HTML-string \A _html can be given */ SymbolFullProps(const SymbolProps& props, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief \a props is stored with encoding MTFEStandard, uses the specified \a _fontType for drawing, an optional HTML-string \A _html can be given */ SymbolFullProps(JKQTMathTextEnvironmentFont _fontType, const SymbolProps& props, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief takes a \a symbol from the specified \a _fontType assuming MTFEStandard encoding, an optional HTML-string \A _html can be given */ SymbolFullProps(JKQTMathTextEnvironmentFont _fontType, const QString& symbol, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief single-alternative symbol for encoding \a enc0 and using symbol description \a props0 for it. An optional HTML-string \a _html can be provided */ SymbolFullProps(JKQTMathTextFontEncoding enc0, const SymbolProps& props0, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief single-alternative symbol for encoding \a enc0 and using symbol description \a props0 for it, uses the specified \a _fontType for drawing. An optional HTML-string \a _html can be provided */ SymbolFullProps(JKQTMathTextEnvironmentFont _fontType, JKQTMathTextFontEncoding enc0, const SymbolProps& props0, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief double-alternative symbol for encoding \a enc0 + \a enc1 and using symbol descriptions \a props0 + \a props1 for it. An optional HTML-string \a _html can be provided */ SymbolFullProps(JKQTMathTextFontEncoding enc0, const SymbolProps& props0, JKQTMathTextFontEncoding enc1, const SymbolProps& props1, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief double-alternative symbol for encoding \a enc0 + \a enc1 and using symbol descriptions \a props0 + \a props1 for it, uses the specified \a _fontType for drawing. An optional HTML-string \a _html can be provided */ SymbolFullProps(JKQTMathTextEnvironmentFont _fontType, JKQTMathTextFontEncoding enc0, const SymbolProps& props0, JKQTMathTextFontEncoding enc1, const SymbolProps& props1, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief triple-alternative symbol for encoding \a enc0 + \a enc1 + \a enc2 and using symbol descriptions \a props0 + \a props1 + \a props2 for it. An optional HTML-string \a _html can be provided */ SymbolFullProps(JKQTMathTextFontEncoding enc0, const SymbolProps& props0, JKQTMathTextFontEncoding enc1, const SymbolProps& props1, JKQTMathTextFontEncoding enc2, const SymbolProps& props2, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief triple-alternative symbol for encoding \a enc0 + \a enc1 + \a enc2 and using symbol descriptions \a props0 + \a props1 + \a props2 for it, uses the specified \a _fontType for drawing. An optional HTML-string \a _html can be provided */ SymbolFullProps(JKQTMathTextEnvironmentFont _fontType, JKQTMathTextFontEncoding enc0, const SymbolProps& props0, JKQTMathTextFontEncoding enc1, const SymbolProps& props1, JKQTMathTextFontEncoding enc2, const SymbolProps& props2, const QString& _html=QString(), SymbolFlags _htmlflags=AsOutside, double _htmlfontScalingFactor=1.0, double _htmlyShiftFactor=0.0); /** \brief font type to use for typesetting the symbol (default is MTcurrentFont, which just takes the font set in the surrounding environment) */ JKQTMathTextEnvironmentFont fontType; /** \brief font to use for output when fontType==MTcustomFont */ QString customFontFamily; /** \brief here the actual symbol properties for each JKQTMathTextFontEncoding are stored */ QHash props; /** \brief HTML entity/text to represent the symbol (empty html.symbol not available) */ SymbolProps html; /** \brief specifies global symbol flags */ GlobalSymbolFlags globalFlags; SymbolFullProps &add(JKQTMathTextFontEncoding enc, const SymbolProps& props); SymbolFullProps& addWinSymbol(const QString& _symbol, SymbolFlags _flags=AsOutside, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addMathOperatorWinSymbol(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addUprightWinSymbol(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addUnicode(const QString& _symbol, SymbolFlags _flags=AsOutside, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addUprightUnicode(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addMathOperatorUnicode(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addStd(const QString& _symbol, SymbolFlags _flags=AsOutside, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addMathOperatorStd(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addUprightStd(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addHtml(const QString& _symbol, SymbolFlags _flags=AsOutside, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addMathOperatorHtml(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addUprightHtml(const QString& _symbol, double _fontScalingFactor=1.0, double _yShiftFactor=0.0); SymbolFullProps& addGlobalFlags(GlobalSymbolFlags addglobalFlags); SymbolFullProps& setGlobalFlags(GlobalSymbolFlags addglobalFlags); /** \brief returns the QFont to use for drawing and the QString to draw with it */ QPair getDrawingData(JKQTMathTextEnvironment currentEv, JKQTMathText *parent) const; }; /** \brief creates a SymbolFullProps object for a symbol that can be typeset in any font, for SymbolFullProps::html the same text as a\a symbol is used */ static SymbolFullProps SimpleTextSymbol(const QString& symbol); /** \brief creates a SymbolFullProps object for a symbol that can be typeset in any font, a special html-string is given */ static SymbolFullProps SimpleTextSymbol(const QString& symbol, const QString& html); /** \brief creates a SymbolFullProps object for a symbol that can be typeset in any font, for SymbolFullProps::html the same text as a\a symbol is used */ static SymbolFullProps SimpleUprightTextSymbol(const QString& symbol); /** \brief creates a SymbolFullProps object for a symbol that can be typeset in any font, a special html-string is given */ static SymbolFullProps SimpleUprightTextSymbol(const QString& symbol, const QString& html); /** \brief constructs a SymbolProps for a math-operator like \c \\sin ..., i.e. ItalicOff, BoldOff, ExtendWidthInMathmode */ static SymbolFullProps MathOperatorSymbol(const QString& op); /** \brief constructs a SymbolProps with explicit HTML for a math-operator like \c \\sin ..., i.e. ItalicOff, BoldOff, ExtendWidthInMathmode */ static SymbolFullProps MathOperatorSymbol(const QString& op, const QString& ophtml); /** \brief constructs a SymbolProps for a math-operator like \c \\sin ..., i.e. ItalicOff, BoldOff, HeightIsAscent, ExtendWidthInMathmode */ static SymbolFullProps MathOperatorText(const QString& op); /** \brief constructs a SymbolProps with explicit HTML for a math-operator like \c \\sin ..., i.e. ItalicOff, BoldOff, HeightIsAscent, ExtendWidthInMathmode */ static SymbolFullProps MathOperatorText(const QString& op, const QString& ophtml); /** \brief constructs a SymbolProps for greek letter with the symbol in unicode-encoding \a letterUnicode and in WinSymbol-encoding letterWinWsymbol */ static SymbolFullProps GreekLetter_WinSymbol_Unicode_Html(const QString& letterWinSymbol, const QString& letterUnicode, const QString& html); /** \brief constructs a SymbolProps for a symbol with encoding in Standard-fonts a */ static SymbolFullProps SymbolStd(const QString& symbol, const QString& html=QString()); /** \brief constructs a SymbolProps for a symbol with encoding in UnicodeFull-fonts a */ static SymbolFullProps SymbolUnicode(const QString& symbol, const QString& html=QString()); /** \brief constructs a SymbolProps for a symbol with encoding in Standard-fonts a */ static SymbolFullProps UprightSymbolStd(const QString& symbol, const QString& html=QString()); /** \brief constructs a SymbolProps for a symbol with encoding in UnicodeFull-fonts a */ static SymbolFullProps UprightSymbolUnicode(const QString& symbol, const QString& html=QString()); /** \brief constructs a SymbolProps for a math-operator symbol like \c \\pm ... in unicode-full-encoding, i.e. ItalicOff, BoldOff, ExtendWidthInMathmode */ static SymbolFullProps MathOperatorSymbolUnicode(const QString& unicode); /** \brief symbols that can be generated in any standard-font */ static QHash symbols; /** \brief fill the symbol tables standardTextSymbols, winSymbolSymbol, ... with contents */ static void fillSymbolTables(); /** \brief retrieve the properties to render the given symbol \a symName in the current environment \a currentEv */ SymbolFullProps getSymbolProp(const QString& symName, const JKQTMathTextEnvironment& currentEv) const; }; #endif // JKQTMATHTEXTSYMBOLNODE_H