diff --git a/doc/dox/todo.dox b/doc/dox/todo.dox index 0c4bccf112..153349ecd3 100644 --- a/doc/dox/todo.dox +++ b/doc/dox/todo.dox @@ -39,7 +39,7 @@ This page lists several todos and wishes for future version of JKQTPlotter
  • JKQTMathText:
  • diff --git a/doc/images/jkqtmathtext/jkqtmathtext_unicode.png b/doc/images/jkqtmathtext/jkqtmathtext_unicode.png new file mode 100644 index 0000000000..fe4cb185a0 Binary files /dev/null and b/doc/images/jkqtmathtext/jkqtmathtext_unicode.png differ diff --git a/examples/jkqtmathtext_test/testform.cpp b/examples/jkqtmathtext_test/testform.cpp index e6877c064c..f860d83ccf 100644 --- a/examples/jkqtmathtext_test/testform.cpp +++ b/examples/jkqtmathtext_test/testform.cpp @@ -67,6 +67,7 @@ TestForm::TestForm(QWidget *parent) : ui->cmbTestset->addItem("text (bold)", "text \\mathbf{bold}"); ui->cmbTestset->addItem("textcolor", "text \\mathbf{bold}\\textcolor{red}{RED}"); ui->cmbTestset->addItem("userfont", "text, \\userfont{Arial}{Arial}, \\userfont{Comic Sans MS}{Comic Sans MS}"); + ui->cmbTestset->addItem("unicode", "star: \\unicode{2605}, circonflex: \\unicode{109}"); const auto mathDecoExample=[](const QString& deco)->QString { return "\\"+deco+"{x}\\"+deco+"{i}\\"+deco+"{X}\\"+deco+"{\\psi}\\"+deco+"{abc}"; }; ui->cmbTestset->addItem("decoration: math", "$"+mathDecoExample("vec")+" -- "+mathDecoExample("grave")+" -- "+mathDecoExample("acute")+" -- "+mathDecoExample("dot")+" -- "+mathDecoExample("ddot")+" -- "+mathDecoExample("ocirc")+" -- "+mathDecoExample("overline")+" -- "+mathDecoExample("underline")+" -- "+mathDecoExample("hat")+" -- "+mathDecoExample("widehat")+" -- "+mathDecoExample("check")+" -- "+mathDecoExample("widecheck")+" -- "+mathDecoExample("breve")+" -- "+mathDecoExample("tilde")+" -- "+mathDecoExample("widetilde")+" -- "+mathDecoExample("uul")+" -- "+mathDecoExample("ool")+" -- "+mathDecoExample("bar")+" -- "+mathDecoExample("arrow")+" -- "+mathDecoExample("cancel")+" -- "+mathDecoExample("bcancel")+" -- "+mathDecoExample("xcancel")+" -- "+mathDecoExample("sout")+"$"); ui->cmbTestset->addItem("decoration: text", "Text \\ul{underlined Text Equator} -- \\ol{overlined Text Equator} -- \\sout{striked out Text Equator} -- \\cancel{canceled out Text Equator} -- \\bcancel{b-canceled out Text Equator} -- \\xcancel{x-canceled out Text Equator}"); @@ -430,6 +431,7 @@ QTreeWidgetItem *TestForm::createTree(JKQTMathTextNode *node, QTreeWidgetItem* p JKQTMathTextListNode* lstN=dynamic_cast(node); JKQTMathTextModifiedTextPropsInstructionNode* inst1N=dynamic_cast(node); JKQTMathTextBoxInstructionNode* inst1B=dynamic_cast(node); + JKQTMathTextSimpleInstructionNode* instS=dynamic_cast(node); JKQTMathTextSubscriptNode* subN=dynamic_cast(node); JKQTMathTextSuperscriptNode* superN=dynamic_cast(node); JKQTMathTextBraceNode* braceN=dynamic_cast(node); @@ -476,6 +478,8 @@ QTreeWidgetItem *TestForm::createTree(JKQTMathTextNode *node, QTreeWidgetItem* p } else if (subN) { name=QString("MTsubscriptNode"); if (subN->getChild()) ti->addChild(createTree(subN->getChild(), ti)); + } else if (instS) { + name=QString("SimpleInstructionNode: \'%1\' (subsuper=%2, params=%3)").arg(instS->getInstructionName()).arg(instS->isSubSuperscriptAboveBelowNode()).arg(instS->getParameters().join("/")); } else if (inst1N) { name=QString("ModTxtPropsInstructionNode: \'%1\' (subsuper=%2, params=%3)").arg(inst1N->getInstructionName()).arg(inst1N->isSubSuperscriptAboveBelowNode()).arg(inst1N->getParameters().join("/")); if (inst1N->getChild()) ti->addChild(createTree(inst1N->getChild(), ti)); diff --git a/lib/jkqtmathtext/jkqtmathtext.cpp b/lib/jkqtmathtext/jkqtmathtext.cpp index 719aac0bbd..f7d1532439 100644 --- a/lib/jkqtmathtext/jkqtmathtext.cpp +++ b/lib/jkqtmathtext/jkqtmathtext.cpp @@ -1708,6 +1708,16 @@ JKQTMathTextNode* JKQTMathText::parseInstruction(bool *_foundError, bool* getNew if (foundError){ error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(Nparams+1)); } + } else if (JKQTMathTextSimpleInstructionNode::supportsInstructionName(currentInstructionName)) { + const size_t Nparams=JKQTMathTextSimpleInstructionNode::countParametersOfInstruction(currentInstructionName); + bool foundError=false; + const QStringList params=parseStringParams(true, Nparams, &foundError); + if (!foundError) { + child=new JKQTMathTextSimpleInstructionNode(this, currentInstructionName, params); + } + if (foundError){ + error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(Nparams)); + } } else if (JKQTMathTextBoxInstructionNode::supportsInstructionName(currentInstructionName)) { const size_t Nparams=JKQTMathTextBoxInstructionNode::countParametersOfInstruction(currentInstructionName); bool foundError=false; diff --git a/lib/jkqtmathtext/jkqtmathtext.h b/lib/jkqtmathtext/jkqtmathtext.h index ba168aed82..41b5cc7e58 100644 --- a/lib/jkqtmathtext/jkqtmathtext.h +++ b/lib/jkqtmathtext/jkqtmathtext.h @@ -133,6 +133,7 @@ class JKQTMathTextNode; // forward - \c \\fcolorbox{bordercolor}{backgroundcolor}{...} : draw a colored, filled box \image html jkqtmathtext/jkqtmathtext_fcolorbox.png - \c \\colorbox{color}{...} : draw a colored box around text \image html jkqtmathtext/jkqtmathtext_colorbox.png - \c \\alpha ... : display the according greek letter \image html jkqtmathtext/jkqtmathtext_greek.png + - \c \\unicode{HEX} : draws a unicode character \image html jkqtmathtext/jkqtmathtext_unicode.png (generated by star: \\unicode{2605}, circonflex: \\unicode{109}) - \c ^{...} \c _{...} : display the contents of braces in superscript/subscript \image html jkqtmathtext/jkqtmathtext_supersub.png
    Special subscript/superscript typesetting applies, when the sub/super follows \c \\sum \c \\Prod ...: \image html jkqtmathtext/jkqtmathtext_specialsubsuper.png - \c \\{ / \\} : display opening/closing brace diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.cpp b/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.cpp index 85b81ad830..1e25d5f2b6 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.cpp +++ b/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.cpp @@ -58,6 +58,136 @@ const QStringList &JKQTMathTextInstruction1Node::getParameters() const { + +JKQTMathTextSimpleInstructionNode::JKQTMathTextSimpleInstructionNode(JKQTMathText *_parent, const QString &_name, const QStringList &_parameters): + JKQTMathTextNode(_parent), + instructionName(_name), + parameters(_parameters) +{ + fillInstructions(); + +} + +JKQTMathTextSimpleInstructionNode::~JKQTMathTextSimpleInstructionNode() +{ + +} + +QString JKQTMathTextSimpleInstructionNode::getTypeName() const +{ + return QLatin1String("JKQTMathTextSimpleInstructionNode(")+instructionName+")"; +} + +double JKQTMathTextSimpleInstructionNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize *prevNodeSize) +{ + doDrawBoxes(painter, x, y, currentEv); + fillInstructions(); + QFont f=currentEv.getFont(parentMathText); + f.setStyleStrategy(QFont::PreferDefault); + const QFontMetricsF fm(f); + const QString txt=executeInstruction(); + const QRectF bb=fm.boundingRect(txt); + + painter.setFont(f); + painter.drawText(x,y,txt); + + return x+bb.width(); +} + +bool JKQTMathTextSimpleInstructionNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) +{ + fillInstructions(); + const QString txt=executeInstruction(); + html+=txt; + return true; +} + +const QString &JKQTMathTextSimpleInstructionNode::getInstructionName() const +{ + return instructionName; +} + +const QStringList &JKQTMathTextSimpleInstructionNode::getParameters() const +{ + return parameters; +} + +bool JKQTMathTextSimpleInstructionNode::supportsInstructionName(const QString &instructionName) +{ + fillInstructions(); + return instructions.contains(instructionName); +} + +size_t JKQTMathTextSimpleInstructionNode::countParametersOfInstruction(const QString &instructionName) +{ + fillInstructions(); + if (instructions.contains(instructionName)) return instructions[instructionName].NParams; + return 0; +} + +void JKQTMathTextSimpleInstructionNode::getSizeInternal(QPainter &painter, JKQTMathTextEnvironment currentEv, double &width, double &baselineHeight, double &overallHeight, double &strikeoutPos, const JKQTMathTextNodeSize */*prevNodeSize*/) +{ + fillInstructions(); + QFont f=currentEv.getFont(parentMathText); + f.setStyleStrategy(QFont::PreferDefault); + const QFontMetricsF fm(f); + const QString txt=executeInstruction(); + const QRectF bb=fm.boundingRect(txt); + width=bb.width(); + baselineHeight=bb.height()+bb.y(); + overallHeight=bb.height(); + strikeoutPos=fm.strikeOutPos(); +} + +QHash JKQTMathTextSimpleInstructionNode::instructions; + +void JKQTMathTextSimpleInstructionNode::fillInstructions() +{ + { + InstructionProperties i([](const QStringList& parameters) -> QString { + bool ok=false; + const int code=parameters.value(0, "0").toInt(&ok, 16); + ok=ok&&(code>=0); + if (ok&&(code<=0xFFFF)) return QChar(code); + else if (ok&&(code>0xFFFF && code<0xFFFFFFFF)) { + const char16_t unicodeSmile[] = { char16_t((code&0xFFFF0000)>>16), char16_t(code&0xFFFF), 0 }; + return QString::fromUtf16(unicodeSmile); + } + return QChar(0); + }, 1); + instructions["unicode"]= i; + } + +} + +QString JKQTMathTextSimpleInstructionNode::executeInstruction() const +{ + fillInstructions(); + return instructions.value(getInstructionName(), InstructionProperties()).evaluator(getParameters()); +} + +JKQTMathTextSimpleInstructionNode::InstructionProperties::InstructionProperties(): + NParams(0), + evaluator([](const QStringList&) { return QString(); }) + +{ + +} + +JKQTMathTextSimpleInstructionNode::InstructionProperties::InstructionProperties(const EvaluateInstructionFunctor &_evaluator, size_t _NParams): + NParams(_NParams), + evaluator(_evaluator) + +{ + +} + + + + + + + JKQTMathTextModifiedTextPropsInstructionNode::JKQTMathTextModifiedTextPropsInstructionNode(JKQTMathText* _parent, const QString& name, JKQTMathTextNode* child, const QStringList& parameters): JKQTMathTextInstruction1Node(_parent, name, child, parameters) { diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.h b/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.h index 7a7e04aa95..912a247c6a 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.h +++ b/lib/jkqtmathtext/nodes/jkqtmathtextinstructionnode.h @@ -59,6 +59,67 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextInstruction1Node: public JKQTMathTextS +/** \brief subclass representing a simple instruction node which only accepts string arguments, not LaTeX arguments + * i.e. it represents instructions like \c \\unicode{...}, ... + * \ingroup jkqtmathtext_items + */ +class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextSimpleInstructionNode: public JKQTMathTextNode { + public: + explicit JKQTMathTextSimpleInstructionNode(JKQTMathText* parent, const QString& name, const QStringList& parameters=QStringList()); + virtual ~JKQTMathTextSimpleInstructionNode() 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 instructionName */ + const QString& getInstructionName() const; + /** \copydoc parameters */ + const QStringList& getParameters() const; + + /** \brief returns true, if the given \a instructionName can be represented by this node + * \see instructions + */ + static bool supportsInstructionName(const QString& instructionName); + /** \brief returns the number of additional string parameters, required for the given \a instructionName + * \see instructions + */ + static size_t countParametersOfInstruction(const QString& instructionName); + + protected: + /** \copydoc JKQTMathTextNode::getSizeInternal() */ + virtual void getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; + /** \brief defines the implementation of an instruction represented by JKQTMathTextModifiedTextPropsInstructionNode */ + struct InstructionProperties { + /** \brief this functor implements the instruction */ + typedef std::function EvaluateInstructionFunctor; + /** \brief default constructor, creates a NOP-instruction that does nothing */ + InstructionProperties(); + /** \brief constructor which gets a functor \a _modifier and a number of required parameters \a _NParams */ + InstructionProperties(const EvaluateInstructionFunctor& _evaluator, size_t _NParams=0); + /** \brief number of parameters for this node */ + size_t NParams; + /** \brief output of the instruction */ + EvaluateInstructionFunctor evaluator; + }; + + /** \brief fills instructions + * + * \note this is the customization point for new instructions! + */ + static void fillInstructions(); + /** \brief defines all implemented instructions in this node */ + static QHash instructions; + /** \brief executes the instruction on \a ev */ + QString executeInstruction() const; + /** \brief instruction name */ + QString instructionName; + /** \brief additional string-parameters */ + QStringList parameters; +}; + + /** \brief subclass representing an instruction node which modifies the current font (as defined in JKQTMathTextEnvironment), * i.e. it represents instructions like \c \\textbf{...}, \c \\ul{underlinedText}, ... * \ingroup jkqtmathtext_items @@ -71,7 +132,6 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextModifiedTextPropsInstructionNode: publ virtual QString getTypeName() const override; /** \copydoc JKQTMathTextNode::draw() */ virtual double draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; - /** \brief convert node to HTML and returns \c true on success */ /** \copydoc JKQTMathTextNode::toHtml() */ virtual bool toHtml(QString& html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) override; @@ -129,7 +189,6 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBoxInstructionNode: public JKQTMathTex virtual QString getTypeName() const override; /** \copydoc JKQTMathTextNode::draw() */ virtual double draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; - /** \brief convert node to HTML and returns \c true on success */ /** \copydoc JKQTMathTextNode::toHtml() */ virtual bool toHtml(QString& html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) override;