From 7d686f0c9aeb6f87fc85cc5a132533d17258123e Mon Sep 17 00:00:00 2001 From: jkriege2 Date: Wed, 3 Aug 2022 15:23:14 +0200 Subject: [PATCH] JKQTMathText: - BREAKING/REWORKED: The \\verb!...!-command now works the same as in LaTeX - NEW: added support for \\begin{verbatim}...\\end{verbatim}, \\begin{verbatim*}...\\end{verbatim*} --- doc/dox/jkqtmathtext_supportedlatex.dox | 9 +- doc/dox/whatsnew.dox | 2 + .../jkqtmathtext/jkqtmathtext_lstlisting.png | Bin 0 -> 2455 bytes doc/images/jkqtmathtext/jkqtmathtext_verb.png | Bin 3226 -> 2264 bytes .../jkqtmathtext/jkqtmathtext_verbatim.png | Bin 0 -> 2712 bytes .../jkqtmathtext/jkqtmathtext_verbatimast.png | Bin 0 -> 2720 bytes examples/jkqtmathtext_test/testform.cpp | 8 + lib/jkqtcommon/jkqtpstringtools.cpp | 14 + lib/jkqtcommon/jkqtpstringtools.h | 5 + lib/jkqtmathtext/jkqtmathtext.cpp | 199 ++++++----- lib/jkqtmathtext/jkqtmathtext.h | 12 + lib/jkqtmathtext/jkqtmathtexttools.h | 8 +- .../nodes/jkqtmathtextlistnode.cpp | 7 +- lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h | 12 +- .../nodes/jkqtmathtexttextnode.cpp | 316 +++++++++++++++--- lib/jkqtmathtext/nodes/jkqtmathtexttextnode.h | 120 ++++++- lib/jkqtplotter/jkqtplotter.h | 2 +- 17 files changed, 554 insertions(+), 160 deletions(-) create mode 100644 doc/images/jkqtmathtext/jkqtmathtext_lstlisting.png create mode 100644 doc/images/jkqtmathtext/jkqtmathtext_verbatim.png create mode 100644 doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png diff --git a/doc/dox/jkqtmathtext_supportedlatex.dox b/doc/dox/jkqtmathtext_supportedlatex.dox index d92a1299d1..563c53eee5 100644 --- a/doc/dox/jkqtmathtext_supportedlatex.dox +++ b/doc/dox/jkqtmathtext_supportedlatex.dox @@ -60,6 +60,14 @@ - \c \\colorbox{color}{...} : draw a colored box around text \image html jkqtmathtext/jkqtmathtext_colorbox.png . + + \section JKQTMathTextSuppoertedLaTeXVerbatim Verbatim Text + Sometimes it is necessary to typeset text withou interpreting it as LaTeX markup. These instructions are implemented for that: + - \\verb!...!: interpret enclosed text between \c ! as verbose. Instead of \ ! you can choose ANY character! \image html jkqtmathtext/jkqtmathtext_verb.png generated by \\verb!\\LaTeX{} is not pares inside \\verb~..~! outside {\\backslash}verb + - \\begin{verbatim}...\\end{verbatim}: interpret enclosed multi-line text as verbatim. \image html jkqtmathtext/jkqtmathtext_verbatim.png generated by outside\\begin{verbatim}\ninside \\LaTeX verbatim\n 2nd verbaimline\n\t3rd line\n\\end{verbatim} + - \\begin{lstlisting}...\\end{lstlisting}: actually menat for highlighted code, for now this is the same as \c \\begin{verbatim}...\\end{verbatim}. \image html jkqtmathtext/jkqtmathtext_lstlisting.png generated by outside\\begin{lstlisting}\nint main() {\n printf("Hello World\\n");\n}\n\\end{lstlisting} + - \\begin{verbatim*}...\\end{verbatim*}: interpret enclosed multi-line text as verbatim. Print with visible whitespace and tab characters \image html jkqtmathtext/jkqtmathtext_verbatimast.png generated by outside\\begin{verbatim*}\ninside \\LaTeX verbatim\n 2nd verbaimline\n\t3rd line\n\\end{verbatim*} + . \section JKQTMathTextSuppoertedLaTeXSymbols Symbols and special characters @@ -79,7 +87,6 @@ - \c -- : draw an en-dash \image html jkqtmathtext/jkqtmathtext_endash.png - \c --- : draw an em-dash \image html jkqtmathtext/jkqtmathtext_emdash.png - \\vec{x} \\dot{x} \\ddot{x} \\overline{x} \\underline{x} \\hat{x} \\tilde{x} \\uul{x} \\ool{x} \\bar{x} \\arrow{x} \\widehat{x} \\widetilde{x} ...: Decorations over/under symbols \image html jkqtmathtext/jkqtmathtext_mathdeco.png - - \\verb{don't parse this _aaa\\LaTeX} : interpret enclosed text as verbose \image html jkqtmathtext/jkqtmathtext_verb.png . \section JKQTMathTextSuppoertedLaTeXTextAlignment Environments for Multi-line text diff --git a/doc/dox/whatsnew.dox b/doc/dox/whatsnew.dox index 5f1229bab6..e742ee5c01 100644 --- a/doc/dox/whatsnew.dox +++ b/doc/dox/whatsnew.dox @@ -53,6 +53,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
  • IMPROVED/NEW/breaking: refactored LaTeX parser in JKQTMathText
  • REMOVED/breaking: \c \\v[a-zA-Z] and shorthand for \c \\vec{a-zA-Z} was removed, implementation of \c \\bbR,\c \\bbC,... changed
  • IMPROVED/REWORKED rendering of text in text- and math-mode. Now it is more consistent with the output of LaTeX itself
  • +
  • BREAKING/REWORKED: The \\verb!...!-command now works the same as in LaTeX
  • NEW: now supports new decoration instructions: \c \\cancel, \c \\xcancel, \c \\bcancel, \c \\sout, \c \\ocirc, \c \\widetilde, \c \\widehat, \c \\breve
  • NEW: reworked drawing of decorations: improved appearance and positioning!
  • NEW: reworked code structure: broke up large, single CPP-files into several smaller files!
  • @@ -78,6 +79,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
  • NEW: added support for -- and --- for en- and em-dashes
  • NEW: added support for \c \\char"HEX , \c \\char'OCTAL and \c \\charDECIMAL for inserting any uicode character code
  • NEW: added support for \\bigl,\\bigr,\\Bigr,... commands for fixed-size but enlarged paramtheses
  • +
  • NEW: added support for \\begin{verbatim}...\\end{verbatim}, \\begin{verbatim*}...\\end{verbatim*}
  • diff --git a/doc/images/jkqtmathtext/jkqtmathtext_lstlisting.png b/doc/images/jkqtmathtext/jkqtmathtext_lstlisting.png new file mode 100644 index 0000000000000000000000000000000000000000..866df880369205d32a7ddbeecb58d16f8e0021af GIT binary patch literal 2455 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 literal 3226 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 literal 0 HcmV?d00001 diff --git a/doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png b/doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png new file mode 100644 index 0000000000000000000000000000000000000000..f6d2850fc2e85b2afef963fa67c7986c3794bad3 GIT binary patch literal 2720 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 literal 0 HcmV?d00001 diff --git a/examples/jkqtmathtext_test/testform.cpp b/examples/jkqtmathtext_test/testform.cpp index 272039dd75..42127e9240 100644 --- a/examples/jkqtmathtext_test/testform.cpp +++ b/examples/jkqtmathtext_test/testform.cpp @@ -2,6 +2,7 @@ #include "ui_testform.h" #include #include +#include "jkqtcommon/jkqtpstringtools.h" #include "jkqtmathtext/nodes/jkqtmathtexttextnode.h" #include "jkqtmathtext/nodes/jkqtmathtextbracenode.h" #include "jkqtmathtext/nodes/jkqtmathtextdecoratednode.h" @@ -86,6 +87,10 @@ TestForm::TestForm(QWidget *parent) : 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}"); + ui->cmbTestset->addItem("text: \\verb", "\\verb!\\LaTeX{} is not pares inside \\verb~..~! outside {\\backslash}verb"); + ui->cmbTestset->addItem("text: \\begin{verbatim}", "outside\\begin{verbatim}\ninside \\LaTeX verbatim\n 2nd verbaimline\n\t3rd line\n\\end{verbatim}"); + ui->cmbTestset->addItem("text: \\begin{verbatim*}", "outside\\begin{verbatim*}\ninside \\LaTeX verbatim\n 2nd verbaimline\n\t3rd line\n\\end{verbatim*}"); + ui->cmbTestset->addItem("text: \\begin{lstlistings}", "outside\\begin{lstlisting}\nint main() {\n printf(\"Hello World\\n\");\n}\n\\end{lstlisting}"); ui->cmbTestset->addItem("text: flushleft", "\\begin{flushleft}text\\\\\\textbf{2^{nd} line of text}\\\\last \\textit{line!} $\\frac{1}{2}$\\end{flushleft}"); ui->cmbTestset->addItem("text: flushright", "\\begin{flushright}text\\\\\\textbf{2^{nd} line of text}\\\\last \\textit{line!} $\\frac{1}{2}$\\end{flushright}"); ui->cmbTestset->addItem("text: center", "\\begin{center}text\\\\\\textbf{2^{nd} line of text}\\\\last \\textit{line!} $\\frac{1}{2}$\\end{center}"); @@ -464,6 +469,7 @@ QTreeWidgetItem *TestForm::createTree(JKQTMathTextNode *node, QTreeWidgetItem* p JKQTMathTextMatrixNode* matrixN=dynamic_cast(node); JKQTMathTextDecoratedNode* decoN=dynamic_cast(node); JKQTMathTextEmptyBoxNode* emptyN=dynamic_cast(node); + JKQTMathTextVerbatimNode* verbN=dynamic_cast(node); QTreeWidgetItem* ti=nullptr; if (parent) ti=new QTreeWidgetItem(parent); @@ -523,6 +529,8 @@ QTreeWidgetItem *TestForm::createTree(JKQTMathTextNode *node, QTreeWidgetItem* p for (int i=0; iaddChild(createTree(list[i], ti)); } + } else if (verbN) { + name=QString("VerbatimTextNode (align=%1, spacingFactor=%2x, verticalOrientation=%3, text='%4')").arg(JKQTMathTextHorizontalAlignment2String(verbN->getAlignment())).arg(verbN->getLineSpacingFactor()).arg(JKQTMathTextVerticalOrientation2String(verbN->getVerticalOrientation())).arg(jkqtp_backslashEscape(verbN->getText())); } else if (symN) { name=QString("SymbolNode: \'%1\' (subsuper=%3)").arg(symN->getSymbolName()).arg(symN->isSubSuperscriptAboveBelowNode()); } else if (spN) { diff --git a/lib/jkqtcommon/jkqtpstringtools.cpp b/lib/jkqtcommon/jkqtpstringtools.cpp index e63a8c9951..95709ebaf1 100644 --- a/lib/jkqtcommon/jkqtpstringtools.cpp +++ b/lib/jkqtcommon/jkqtpstringtools.cpp @@ -864,3 +864,17 @@ std::string jkqtp_UnicodeToUTF8(uint32_t codepoint) } return out; } + +QString jkqtp_backslashEscape(const QString &txt) +{ + QString res; + for (const QChar c: txt) { + if (c=='\n') res+="\\n"; + else if (c=='\r') res+="\\r"; + else if (c=='\t') res+="\\t"; + else if (c=='\\') res+="\\\\"; + else if (c.unicode()<32) res+="\\x"+QString::number(c.unicode(), 16).toUpper(); + else res+=c; + } + return res; +} diff --git a/lib/jkqtcommon/jkqtpstringtools.h b/lib/jkqtcommon/jkqtpstringtools.h index e4f0662970..7fd0a8f096 100644 --- a/lib/jkqtcommon/jkqtpstringtools.h +++ b/lib/jkqtcommon/jkqtpstringtools.h @@ -244,6 +244,11 @@ JKQTCOMMON_LIB_EXPORT QString jkqtp_floattohtmlqstr(double data, int past_comma= */ JKQTCOMMON_LIB_EXPORT std::string jkqtp_chartostr(char data); +/** \brief replace all linebreaks by \c "\\n" , \c "\\r" ... + * \ingroup jkqtptools_string + */ +JKQTCOMMON_LIB_EXPORT QString jkqtp_backslashEscape(const QString& txt); + /*! \brief convert a QList to a string \ingroup jkqtptools_string diff --git a/lib/jkqtmathtext/jkqtmathtext.cpp b/lib/jkqtmathtext/jkqtmathtext.cpp index 8db92080e2..0fba7928b2 100644 --- a/lib/jkqtmathtext/jkqtmathtext.cpp +++ b/lib/jkqtmathtext/jkqtmathtext.cpp @@ -1344,9 +1344,9 @@ JKQTMathText::tokenType JKQTMathText::getToken() { } //std::cout<<"found instruction node '"<4) currentTokenID-=(currentTokenName.size()-4); + currentTokenID++; + const QString verbEndChar=parseString.mid(currentTokenID, 1); + currentTokenName=readUntil(true, verbEndChar); + return currentToken=MTTinstructionVerbatim; + } else if (currentTokenName.startsWith("begin")) { + currentTokenID++; + if (parseString[currentTokenID]!='{') error_list.append(tr("error @ ch. %1: didn't find '{' after '\\begin'").arg(currentTokenID)); // find closing brace '}' after '\\begin{name'); + currentTokenName=readUntil(true, "}"); + if (currentTokenName=="verbatim") { + currentTokenName=readUntil(true, "\\end{verbatim}"); + return currentToken=MTTinstructionVerbatim; + } else if (currentTokenName=="verbatim*") { + currentTokenName=readUntil(true, "\\end{verbatim*}"); + return currentToken=MTTinstructionVerbatimVisibleSpace; + } else if (currentTokenName=="lstlisting") { + currentTokenName=readUntil(true, "\\end{lstlisting}"); + return currentToken=MTTinstructionVerbatim; + } + return currentToken=MTTinstructionBegin; + } else if (currentTokenName.startsWith("end")) { + currentTokenID++; + if (parseString[currentTokenID]!='{') error_list.append(tr("error @ ch. %1: didn't find '{' after '\\end'").arg(currentTokenID)); // find closing brace '}' after '\\begin{name'); + currentTokenName=readUntil(true, "}"); + return currentToken=MTTinstructionEnd; } return currentToken=MTTinstruction; //---------------------------------------------------------- @@ -1560,84 +1586,6 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, JKQTMathTextBraceType if (nl->hasChildren()) nl->getLastChild()->setSubSuperscriptAboveBelowNode(true); } else if (currentInstructionName=="nolimits") { if (nl->hasChildren()) nl->getLastChild()->setSubSuperscriptAboveBelowNode(false); - } else if (currentInstructionName=="begin") { - if (getToken()==MTTopenbrace && getToken()==MTTtext) { - const QString envname=currentTokenName; - getToken(); - if (currentToken!=MTTclosebrace) error_list.append(tr("error @ ch. %1: didn't find '}' after environment start '\\begin{%2'").arg(currentTokenID).arg(envname)); // find closing brace '}' after '\\begin{name' - if (envname=="matrix" || envname=="array" || envname=="aligned" || envname=="align" || envname=="cases" || envname=="pmatrix"|| envname=="bmatrix"|| envname=="Bmatrix"|| envname=="vmatrix"|| envname=="Vmatrix") { - QVector< QVector > items; - //int lines=0; - //int cols=0; - bool first=true; - QVector line; - //std::cout<<"found \\begin{matrix}\n"; - while (first || currentToken==MTTampersand || currentToken==MTTinstructionNewline) { - JKQTMathTextNode* it=parseLatexString(true, MTBTAny, envname); - if (currentToken==MTTampersand) { - //std::cout<<" appending item\n"; - line.append(it); - } else { - line.append(it); - //std::cout<<" appending item and line with "<addChild(new JKQTMathTextBraceNode(this, MTBTParenthesis, MTBTParenthesis, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="cases") nl->addChild(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTNone, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="bmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTSquareBracket, MTBTSquareBracket, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="Bmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTCurlyBracket, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="vmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTSingleLine, MTBTSingleLine, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="Vmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTDoubleLine, MTBTDoubleLine, new JKQTMathTextMatrixNode(this, items))); - else nl->addChild(new JKQTMathTextMatrixNode(this, items)); - //std::cout<<" creating matrix-node ... done!\n"; - } else if (envname=="center" || envname=="document" || envname=="flushleft" || envname=="flushright") { - JKQTMathTextHorizontalAlignment alignment=MTHALeft; - if (envname=="document") alignment=MTHALeft; - else alignment=String2JKQTMathTextHorizontalAlignment(envname); - JKQTMathTextVerticalListNode* vlist = new JKQTMathTextVerticalListNode(this, alignment, 1.0, JKQTMathTextVerticalListNode::SMDefault, MTVOFirstLine ); - nl->addChild(vlist); - bool first=true; - while (first || currentToken==MTTinstructionNewline) { - vlist->addChild(parseLatexString(true, MTBTAny, envname)); - first=false; - } - } else if (envname=="framed" || envname=="shaded" || envname=="snugshade") { - JKQTMathTextHorizontalAlignment alignment=MTHALeft; - JKQTMathTextVerticalListNode* vlist = new JKQTMathTextVerticalListNode(this, alignment, 1.0, JKQTMathTextVerticalListNode::SMDefault, MTVOFirstLine ); - QStringList color; - color<addChild(new JKQTMathTextBoxInstructionNode(this, envname, vlist, color)); - bool first=true; - while (first || currentToken==MTTinstructionNewline) { - vlist->addChild(parseLatexString(true, MTBTAny, envname)); - first=false; - } - } else { - error_list.append(tr("error @ ch. %1: unknown environment '%2'").arg(currentTokenID).arg(envname)); - } - } else { // find next '}' - error_list.append(tr("error @ ch. %1: text after '\\begin{' expected!").arg(currentTokenID)); - while (currentToken!=MTTclosebrace) getToken(); - getNew=true; - } - } else if (currentInstructionName=="end") { - if (getToken()==MTTopenbrace && getToken()==MTTtext) { - QString envname=currentTokenName; - while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name' - if (envname==quitOnEnvironmentEnd) { - break; - } else { - error_list.append(tr("error @ ch. %1: '\\end{%2}' widthout preceding '\\begin{%3}'").arg(currentTokenID).arg(envname).arg(envname)); - } - } else { // find next '}' - error_list.append(tr("error @ ch. %1: text after '\\begin{' expected!").arg(currentTokenID)); - while (currentToken!=MTTclosebrace) getToken(); - getNew=true; - } } else if (currentInstructionName=="right") { getToken(); if (currentToken==MTTtext) { @@ -1755,6 +1703,74 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, JKQTMathTextBraceType break; } else if (currentToken==MTTopenbracket) { nl->addChild(new JKQTMathTextTextNode(this, "[", false)); + } else if (currentToken==MTTinstructionVerbatim) { + nl->addChild(new JKQTMathTextVerbatimNode(this, currentTokenName, false)); + } else if (currentToken==MTTinstructionVerbatimVisibleSpace) { + nl->addChild(new JKQTMathTextVerbatimNode(this, currentTokenName, true)); + + } else if (currentToken==MTTinstructionBegin) { + const QString envname=currentTokenName; + if (envname=="matrix" || envname=="array" || envname=="aligned" || envname=="align" || envname=="cases" || envname=="pmatrix"|| envname=="bmatrix"|| envname=="Bmatrix"|| envname=="vmatrix"|| envname=="Vmatrix") { + QVector< QVector > items; + //int lines=0; + //int cols=0; + bool first=true; + QVector line; + //std::cout<<"found \\begin{matrix}\n"; + while (first || currentToken==MTTampersand || currentToken==MTTinstructionNewline) { + JKQTMathTextNode* it=parseLatexString(true, MTBTAny, envname); + if (currentToken==MTTampersand) { + //std::cout<<" appending item\n"; + line.append(it); + } else { + line.append(it); + //std::cout<<" appending item and line with "<addChild(new JKQTMathTextBraceNode(this, MTBTParenthesis, MTBTParenthesis, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="cases") nl->addChild(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTNone, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="bmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTSquareBracket, MTBTSquareBracket, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="Bmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTCurlyBracket, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="vmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTSingleLine, MTBTSingleLine, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="Vmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTDoubleLine, MTBTDoubleLine, new JKQTMathTextMatrixNode(this, items))); + else nl->addChild(new JKQTMathTextMatrixNode(this, items)); + //std::cout<<" creating matrix-node ... done!\n"; + } else if (envname=="center" || envname=="document" || envname=="flushleft" || envname=="flushright") { + JKQTMathTextHorizontalAlignment alignment=MTHALeft; + if (envname=="document") alignment=MTHALeft; + else alignment=String2JKQTMathTextHorizontalAlignment(envname); + JKQTMathTextVerticalListNode* vlist = new JKQTMathTextVerticalListNode(this, alignment, 1.0, JKQTMathTextVerticalListNode::SMDefault, MTVOFirstLine ); + nl->addChild(vlist); + bool first=true; + while (first || currentToken==MTTinstructionNewline) { + vlist->addChild(parseLatexString(true, MTBTAny, envname)); + first=false; + } + } else if (envname=="framed" || envname=="shaded" || envname=="snugshade") { + JKQTMathTextHorizontalAlignment alignment=MTHALeft; + JKQTMathTextVerticalListNode* vlist = new JKQTMathTextVerticalListNode(this, alignment, 1.0, JKQTMathTextVerticalListNode::SMDefault, MTVOFirstLine ); + QStringList color; + color<addChild(new JKQTMathTextBoxInstructionNode(this, envname, vlist, color)); + bool first=true; + while (first || currentToken==MTTinstructionNewline) { + vlist->addChild(parseLatexString(true, MTBTAny, envname)); + first=false; + } + } else { + error_list.append(tr("error @ ch. %1: unknown environment '%2'").arg(currentTokenID).arg(envname)); + } + } else if (currentToken==MTTinstructionEnd) { + QString envname=currentTokenName; + if (envname==quitOnEnvironmentEnd) { + break; + } else { + error_list.append(tr("error @ ch. %1: '\\end{%2}' widthout preceding '\\begin{%3}'").arg(currentTokenID).arg(envname).arg(envname)); + } } else if (currentToken==MTTclosebracket) { if (quitOnClosingBracket) break; else nl->addChild(new JKQTMathTextTextNode(this, "]", false)); @@ -2057,6 +2073,21 @@ QString JKQTMathText::parseSingleString(bool get) { return thisparam; } +QString JKQTMathText::readUntil(bool get, const QString &endsequence) +{ + if (get) currentTokenID++; + QString seq; + while (currentTokenIDparsedNode; @@ -2083,7 +2114,7 @@ bool JKQTMathText::parse(const QString& text, bool addSpaceBeforeAndAfter){ parsingMathEnvironment=false; error_list.clear(); parsedNode=parseLatexString(true); - unparsedNode=new MTplainTextNode(this, text, false); + unparsedNode=new JKQTMathTextVerbatimNode(this, text); return (parsedNode!=nullptr); } @@ -2212,6 +2243,10 @@ QString JKQTMathText::tokenType2String(tokenType type) case MTThyphen: return "MTThyphen"; case MTTendash: return "MTTendash"; case MTTemdash: return "MTTemdash"; + case MTTinstructionVerbatim: return "MTTinstructionVerbatim"; + case MTTinstructionVerbatimVisibleSpace: return "MTTinstructionVerbatimVisibleSpace"; + case MTTinstructionBegin: return "MTTinstructionBegin"; + case MTTinstructionEnd: return "MTTinstructionEnd"; } return "???"; } diff --git a/lib/jkqtmathtext/jkqtmathtext.h b/lib/jkqtmathtext/jkqtmathtext.h index 84877bb8a6..60bb5843ce 100644 --- a/lib/jkqtmathtext/jkqtmathtext.h +++ b/lib/jkqtmathtext/jkqtmathtext.h @@ -716,6 +716,10 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject { MTTtext, /*!< \brief a piece of general text */ MTTinstruction, /*!< \brief an instruction, started by \c "\", e.g. \c "\\textbf", ... */ MTTinstructionNewline, /*!< \brief a newline instruction \c "\\" */ + MTTinstructionVerbatim, /*!< \brief a verbatim instruction, e.g. \c \\verb!verbatimtext! was found: currentTokenName will contain the text enclode by the verbatim delimiters */ + MTTinstructionVerbatimVisibleSpace, /*!< \brief a verbatim instruction that generates visible whitespaces, e.g. \c \\begin{verbatim}...\end{verbatim} was found: currentTokenName will contain the text enclode by the verbatim delimiters */ + MTTinstructionBegin, /*!< \brief a \c '\\begin{...}' instruction, currentTokenName is the name of the environment */ + MTTinstructionEnd, /*!< \brief a \c '\\end{...}' instruction, currentTokenName is the name of the environment */ MTTunderscore, /*!< \brief the character \c "_" */ MTThat, /*!< \brief the character \c "^" */ MTTdollar, /*!< \brief the character \c "$" */ @@ -728,6 +732,7 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject { MTThyphen, /*!< \brief the single hyphen character \c "-" in text-mode \note MTTendash and MTTemdash take precedence over MTThypen */ MTTendash, /*!< \brief the en-dash character sequence \c "--" in text-mode */ MTTemdash, /*!< \brief the em-dash character sequence \c "---" in text-mode */ + }; /** \biref convert a tokenType into a string, e.g. for debugging output */ static QString tokenType2String(tokenType type); @@ -754,6 +759,13 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject { QStringList parseStringParams(bool get, size_t Nparams, bool *foundError=nullptr); /** \brief parses a string, i.e. a sequence of text and whitespaces. returns after any other token was found */ QString parseSingleString(bool get); + /** \brief read all text without tokenizing, until the sequence \a endsequence is found. + * + * \param get if \c true the functions begins by reading a new character, otherwise the current character is used as first character + * \param endsequence the sequence, ending the read + * \return the read string, excluding the \a endsequence + */ + QString readUntil(bool get, const QString& endsequence); /** \brief parses a single instruction (including it's parameters) * * \param[out] _foundError will be set to \c true if an error occured (unexpected token) or \c false otherwise diff --git a/lib/jkqtmathtext/jkqtmathtexttools.h b/lib/jkqtmathtext/jkqtmathtexttools.h index 4e564107f3..2496d35412 100644 --- a/lib/jkqtmathtext/jkqtmathtexttools.h +++ b/lib/jkqtmathtext/jkqtmathtexttools.h @@ -274,7 +274,7 @@ struct JKQTMATHTEXT_LIB_EXPORT JKQTMathTextEnvironment { void endMathMode(); - /** \brief build a QFont object from the settings in this object */ + /** \brief build a QFont object from the settings in this object */ QFont getFont(JKQTMathText* parent) const; /** \brief return the encoding of the given Font */ JKQTMathTextFontEncoding getFontEncoding(JKQTMathText *parent) const; @@ -292,14 +292,18 @@ struct JKQTMATHTEXT_LIB_EXPORT JKQTMathTextEnvironment { QString toHtmlAfter(JKQTMathTextEnvironment defaultEv, JKQTMathText *parentMathText) const; }; -/** \brief beschreibt die Größe eines Knotens +/** \brief beschreibt die Größe(n) eines Knotens * \ingroup jkqtmathtext_tools */ struct JKQTMATHTEXT_LIB_EXPORT JKQTMathTextNodeSize { JKQTMathTextNodeSize(); + /** \brief width of whole block */ double width; + /** \brief baselineHeight of whole block */ double baselineHeight; + /** \brief overallHeight of whole block */ double overallHeight; + /** \brief strikeoutPos of whole block */ double strikeoutPos; }; diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp index 03751d42a9..38f030e734 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp +++ b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp @@ -617,7 +617,7 @@ void JKQTMathTextVerticalListNode::getSizeInternal(QPainter& painter, JKQTMathTe strikeoutPos=l.strikeoutPos; } -JKQTMathTextVerticalListNode::LayoutInfo JKQTMathTextVerticalListNode::calcLayout(QPainter &painter, JKQTMathTextEnvironment currentEv) +JKQTMathTextVerticalListNode::LayoutInfo JKQTMathTextVerticalListNode::calcLayout(QPainter &painter, JKQTMathTextEnvironment currentEv) const { LayoutInfo l; const QFontMetricsF fm(currentEv.getFont(parentMathText)); @@ -792,8 +792,5 @@ JKQTMathTextVerticalListNode::SpacingMode JKQTMathTextVerticalListNode::getSpaci } JKQTMathTextVerticalListNode::LayoutInfo::LayoutInfo(): - width(0), - baselineHeight(0), - overallHeight(0), - strikeoutPos(0) + JKQTMathTextNodeSize(), X() {} diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h index b03fe524c3..953bf7105a 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h +++ b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h @@ -141,21 +141,13 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextVerticalListNode: public JKQTMathTextM virtual void getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; /** \brief describes the layout of the whole node */ - struct LayoutInfo { + struct LayoutInfo: public JKQTMathTextNodeSize { LayoutInfo(); /** \brief drawing position for each line */ QList X; - /** \brief width of whole block */ - double width; - /** \brief baselineHeight of whole block */ - double baselineHeight; - /** \brief overallHeight of whole block */ - double overallHeight; - /** \brief strikeoutPos of whole block */ - double strikeoutPos; }; /** \brief calclates the layout of the whole block/node */ - LayoutInfo calcLayout(QPainter& painter, JKQTMathTextEnvironment currentEv); + LayoutInfo calcLayout(QPainter& painter, JKQTMathTextEnvironment currentEv) const; /** \brief list of child nodes, each representing one line */ QList nodes; diff --git a/lib/jkqtmathtext/nodes/jkqtmathtexttextnode.cpp b/lib/jkqtmathtext/nodes/jkqtmathtexttextnode.cpp index 2ce65ec2de..c3d5f50913 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtexttextnode.cpp +++ b/lib/jkqtmathtext/nodes/jkqtmathtexttextnode.cpp @@ -34,24 +34,82 @@ #include -JKQTMathTextTextNode::JKQTMathTextTextNode(JKQTMathText* _parent, const QString& textIn, bool addWhitespace, bool stripInnerWhitepace): - JKQTMathTextNode(_parent) + + + +JKQTMathTextTextBaseNode::JKQTMathTextTextBaseNode(JKQTMathText *parent, const QString &text_): + JKQTMathTextNode(parent), + text(text_) { - QString text=textIn; + +} + +JKQTMathTextTextBaseNode::~JKQTMathTextTextBaseNode() +{ + +} + +QString JKQTMathTextTextBaseNode::getText() const +{ + return text; +} + +void JKQTMathTextTextBaseNode::drawString(QPainter &painter, const JKQTMathTextEnvironment ¤tEv, double x, double y, const QString &txt) const { + const QFont f=currentEv.getFont(parentMathText); + drawString(painter, currentEv, f, x, y, txt); +} + +void JKQTMathTextTextBaseNode::drawString(QPainter &painter, const JKQTMathTextEnvironment ¤tEv, const QFont &f, double x, double y, const QString &txt) const +{ + const QFontMetricsF fm(f, painter.device()); + const QPen p(currentEv.color, fm.lineWidth(), Qt::SolidLine); + painter.setPen(p); + if (currentEv.font==MTEblackboard && parentMathText->isFontBlackboardSimulated()) { + QPainterPath path; + path.addText(QPointF(x, y), f, txt); + path.addText(QPointF(x+fm.lineWidth()/2.0, y), f, txt); + painter.drawPath(path); + } else { + painter.setFont(f); + painter.drawText(QPointF(x, y), txt); + } +} + +QString JKQTMathTextTextBaseNode::textTransform(const QString &text, const JKQTMathTextEnvironment &/*currentEv*/) const +{ + return text; +} + + +bool JKQTMathTextTextBaseNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) { + html=html + +currentEv.toHtmlStart(defaultEv, parentMathText) + +textTransform(text, currentEv).toHtmlEscaped() + +currentEv.toHtmlAfter(defaultEv, parentMathText); + return true; +} + + + + +JKQTMathTextTextNode::JKQTMathTextTextNode(JKQTMathText* _parent, const QString& textIn, bool addWhitespace, bool stripInnerWhitepace): + JKQTMathTextTextBaseNode(_parent, "") +{ + QString textTransformed=textIn; if (stripInnerWhitepace) { - text=""; + textTransformed=""; for (int i=0; itext=text; + text=textTransformed; // strip all whitespace from left - while (this->text.size()>1 && this->text[0].isSpace()) { - this->text=this->text.right(this->text.size()-1); + while (text.size()>1 && text[0].isSpace()) { + text=text.right(text.size()-1); } - if (addWhitespace && (this->text.size()>0) && (!this->text[this->text.size()-1].isSpace())) this->text=this->text+" "; + if (addWhitespace && (text.size()>0) && (!text[text.size()-1].isSpace())) text=text+" "; //qDebug()<<"JKQTMathTextTextNode( text="< this->text="<text<<"]"; } @@ -68,7 +126,7 @@ void JKQTMathTextTextNode::getSizeInternalAndData(QPainter &painter, JKQTMathTex { textpart.clear(); fontForcedUpright.clear(); - const QString txt=textTransform(text, currentEv, true); + const QString txt=textTransform(text, currentEv); if (currentEv.insideMath && currentEv.insideMathForceDigitsUpright) { splitTextForMathMode(txt, textpart, fontForcedUpright); } else { @@ -81,7 +139,11 @@ void JKQTMathTextTextNode::getSizeInternalAndData(QPainter &painter, JKQTMathTex const QFont fnonItalic=JKQTMathTextGetNonItalic(f); const QFontMetricsF fmNonItalic(fnonItalic, painter.device()); const QFontMetricsF fm(f, painter.device()); - +#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0)) + const double sp=fm.horizontalAdvance(' '); +#else + const double sp=fm.width(' '); +#endif width=0; double ascent=0; double descent=0; @@ -90,6 +152,10 @@ void JKQTMathTextTextNode::getSizeInternalAndData(QPainter &painter, JKQTMathTex const QRectF tbr=(fontForcedUpright[i]) ? JKQTMathTextGetTightBoundingRect(fnonItalic, textpart[i], painter.device()) : JKQTMathTextGetTightBoundingRect(f, textpart[i], painter.device()); textpartXPos.append(width); width+=br.width(); + if (textpart[i].size()>0 && textpart[i].at(textpart[i].size()-1).isSpace()) { + // this correction is necessary, because it seems that QFontMetricsF::boundingRect() ignores trailing spaces + width+=sp; + } const double thisAscent=-tbr.top(); const double thisDescent=tbr.bottom(); ascent=qMax(ascent, thisAscent); @@ -164,53 +230,40 @@ double JKQTMathTextTextNode::draw(QPainter& painter, double x, double y, JKQTMat //qDebug()<<"JKQTMathTextTextNode: text="<getFontData(currentEv.font, currentEv.insideMath); - if (fnt.second==MTFEUnicode || fnt.second==MTFEUnicode) { + const QFontMetricsF fm(currentEv.getFont(parentMathText)); + if (fnt.second==MTFELatin1 || fnt.second==MTFEUnicode) { if (currentEv.insideMath) { txt=""; for (int i=0; i': txt+=QString(QString(" >")); break; @@ -229,21 +282,196 @@ QString JKQTMathTextTextNode::textTransform(const QString &text, JKQTMathTextEnv -MTplainTextNode::MTplainTextNode(JKQTMathText *_parent, const QString& _text, bool addWhitespace, bool stripInnerWhitepace): - JKQTMathTextTextNode(_parent, _text, addWhitespace, stripInnerWhitepace) +JKQTMathTextVerbatimNode::JKQTMathTextVerbatimNode(JKQTMathText *_parent, const QString& _text, bool visibleWhitespace_, JKQTMathTextHorizontalAlignment _alignment, double _linespacingFactor, JKQTMathTextVerticalOrientation _verticalOrientation): + JKQTMathTextTextBaseNode(_parent, _text), + alignment(_alignment), + lineSpacingFactor(_linespacingFactor), + verticalOrientation(_verticalOrientation), + visibleWhitespace(visibleWhitespace_) { } -QString MTplainTextNode::getTypeName() const +QString JKQTMathTextVerbatimNode::getTypeName() const { - return QLatin1String("MTplainTextNode(")+text+")"; + return QLatin1String("JKQTMathTextVerbatimNode"); +} + +JKQTMathTextHorizontalAlignment JKQTMathTextVerbatimNode::getAlignment() const +{ + return alignment; +} + +JKQTMathTextVerticalOrientation JKQTMathTextVerbatimNode::getVerticalOrientation() const +{ + return verticalOrientation; +} + +double JKQTMathTextVerbatimNode::getLineSpacingFactor() const +{ + return lineSpacingFactor; +} + +bool JKQTMathTextVerbatimNode::getVisibleWhitespace() const +{ + return visibleWhitespace; +} + +double JKQTMathTextVerbatimNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize *prevNodeSize) +{ + doDrawBoxes(painter, x, y, currentEv); + transformEnvironment(currentEv); + const LayoutInfo l=calcLayout(painter, currentEv); + QFont f=currentEv.getFont(parentMathText); + f.setStyleStrategy(QFont::PreferDefault); + f.setFixedPitch(true); + painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); + for (int i=0; i0; + html+=currentEv.toHtmlStart(defaultEv, parentMathText); + if (isMultiLine) { + if (alignment==MTHALeft) { + html+="
    "; + } else if (alignment==MTHACentered) { + html+="
    "; + } else if (alignment==MTHARight) { + html+="
    "; + } + } + html+="
    ";
    +    html+=textTransform(text, currentEv).toHtmlEscaped();
    +    html+="
    "; + if (isMultiLine) html+="
    "; + html+=currentEv.toHtmlAfter(defaultEv, parentMathText); + return true; +} + +void JKQTMathTextVerbatimNode::getSizeInternal(QPainter &painter, JKQTMathTextEnvironment currentEv, double &width, double &baselineHeight, double &overallHeight, double &strikeoutPos, const JKQTMathTextNodeSize *prevNodeSize) +{ + transformEnvironment(currentEv); + const LayoutInfo l=calcLayout(painter, currentEv); + width=l.width; + overallHeight=l.overallHeight; + baselineHeight=l.baselineHeight; + strikeoutPos=l.strikeoutPos; +} + +void JKQTMathTextVerbatimNode::transformEnvironment(JKQTMathTextEnvironment ¤tEv) const +{ + currentEv.font=MTEtypewriter; +} + +JKQTMathTextVerbatimNode::LayoutInfo JKQTMathTextVerbatimNode::calcLayout(QPainter &painter, const JKQTMathTextEnvironment& currentEv) const +{ + LayoutInfo l; + QFont f=currentEv.getFont(parentMathText); + f.setStyleStrategy(QFont::PreferDefault); + f.setFixedPitch(true); + const QFontMetricsF fm(f); + const double linespacing=fm.lineSpacing()*lineSpacingFactor; + const double fleading=fm.leading(); + const double synLeading=fm.lineWidth(); + const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor; + + if (text.size()<=0) { + return l; + } + l.lines=textTransform(text, currentEv).split('\n'); + + // from now on we have at least one child node!!! + + QList widths, heights, ascents, descents, strikeouts; + double heightSum=0; + QList ysFromFirstLine; // y-position of each line, where the first line is always at y=0 (i.e. ysFromFirstLine[0]==0) + double y=0; + for (int i=0; i0) { + const double deltaLine=qMax(linespacing, descents.last()+lineLeading+fm.ascent()); + heightSum=heightSum+deltaLine; + y=y+deltaLine; + } + widths<) with contributions from: Razi Alavizadeh @@ -32,19 +32,50 @@ class JKQTMathText; // forward // JKQTMATHTEXT_LIB_EXPORT +/** \brief base class for nodes representing text in the syntax tree + * \ingroup jkqtmathtext_items + * + * This node is a collection of tools, necessary to draw text. It + * is the base for nodes, such as: + * - JKQTMathTextTextNode + * - JKQTMathTextVerbatimNode + * . + */ +class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTextBaseNode: public JKQTMathTextNode { + public: + explicit JKQTMathTextTextBaseNode(JKQTMathText* parent, const QString& text); + virtual ~JKQTMathTextTextBaseNode() override; + /** \copydoc JKQTMathTextNode::toHtml() */ + virtual bool toHtml(QString& html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) override; + /** \copydoc text */ + QString getText() const; + protected: + /** \brief text-contents of the node */ + QString text; + /** \brief draw a given \a txt in the font defined by \a currentEv at (\a x , \a y ) using the given \a painter + * + * This function implements drawing of synthesized fonts, e.g. MTEblackboard when JKQTMathText::isFontBlackboardSimulated() is \c true . + */ + void drawString(QPainter& painter, const JKQTMathTextEnvironment& currentEv, double x, double y, const QString& txt) const; + /** \brief draw a given \a txt in the font \a f using additional informaion (but not currentEv::getFont() ) from \a currentEv at (\a x , \a y ) using the given \a painter + * + * This function implements drawing of synthesized fonts, e.g. MTEblackboard when JKQTMathText::isFontBlackboardSimulated() is \c true . + */ + void drawString(QPainter& painter, const JKQTMathTextEnvironment ¤tEv, const QFont& f, double x, double y, const QString& txt) const; + /** \brief transforms the \a text before sizing/drawing (may e.g. exchange special letters for other unicode symbols etc.) */ + virtual QString textTransform(const QString& text, const JKQTMathTextEnvironment& currentEv) const; +}; + + /** \brief subclass representing one text node in the syntax tree * \ingroup jkqtmathtext_items */ -class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTextNode: public JKQTMathTextNode { +class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTextNode: public JKQTMathTextTextBaseNode { public: explicit JKQTMathTextTextNode(JKQTMathText* parent, const QString& text, bool addWhitespace, bool stripInnerWhitepace=false); virtual ~JKQTMathTextTextNode() 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 text */ - QString getText() const; /** \copydoc JKQTMathTextNode::getTypeName() */ virtual QString getTypeName() const override ; protected: @@ -52,27 +83,86 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTextNode: public JKQTMathTextNode { virtual void getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; /** \brief calculates the size of the node, much like JKQTMathTextNode::getSizeInternal(), but returns additional properties that can be reused for drawing */ void getSizeInternalAndData(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, QStringList& textpart, QList& fontForcedUpright, QList& textpartXPos) ; - /** \brief text-contents of the node */ - QString text; /** \brief split text for Math-Mode into section with "normal" text and "forced upright" text */ static void splitTextForMathMode(const QString& txt, QStringList& textpart, QList& fontForcedUpright); - /** \brief transforms the text before sizing/drawing (may e.g. exchange special letters for other unicode symbols etc.) */ - virtual QString textTransform(const QString& text, JKQTMathTextEnvironment currentEv, bool forSize=false); + /** \brief transforms the \a text before sizing/drawing (may e.g. exchange special letters for other unicode symbols etc.) */ + virtual QString textTransform(const QString& text, const JKQTMathTextEnvironment& currentEv) const override; }; -/** \brief subclass representing one text node in the syntax tree + +/** \brief subclass representing a verbatim (plain-text) node with support for line-breaks in the syntax tree * \ingroup jkqtmathtext_items + * + * The layout of the lines can left-aligned, right-aligned or centered. + * + * \image html jkqtmathtext_verticallist.png + * + * \image html jkqtmathtext_verticalalignment.png + * + * \image html jkqtmathtext_horizontalalignment.png */ -class JKQTMATHTEXT_LIB_EXPORT MTplainTextNode: public JKQTMathTextTextNode { +class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextVerbatimNode: public JKQTMathTextTextBaseNode { public: - explicit MTplainTextNode(JKQTMathText* parent, const QString& text, bool addWhitespace, bool stripInnerWhitepace=false); + explicit JKQTMathTextVerbatimNode(JKQTMathText* parent, const QString& text, bool visibleWhitespace=false, JKQTMathTextHorizontalAlignment _alignment=MTHALeft, double _linespacingFactor=1.0, JKQTMathTextVerticalOrientation _verticalOrientation=MTVOFirstLine); /** \copydoc JKQTMathTextNode::getTypeName() */ virtual QString getTypeName() const override; + /** \copydoc alignment */ + JKQTMathTextHorizontalAlignment getAlignment() const; + /** \copydoc verticalOrientation */ + JKQTMathTextVerticalOrientation getVerticalOrientation() const; + /** \copydoc lineSpacingFactor */ + double getLineSpacingFactor() const; + /** \copydoc visibleWhitespace */ + bool getVisibleWhitespace() const; + /** \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; protected: - /** \copydoc JKQTMathTextTextNode::textTransform() */ - virtual QString textTransform(const QString& text, JKQTMathTextEnvironment currentEv, bool forSize=false) override; + /** \brief alignment scheme used to lay out all lines + * + * \image html jkqtmathtext_horizontalalignment.png + */ + JKQTMathTextHorizontalAlignment alignment; + /** \brief spacing of the separate lines, as factor of the default line-spacing [Default: 1]. + * + * This property can be used to move the lines closer together or farther apart. + * + * \image html jkqtmathtext_verticallist.png + */ + double lineSpacingFactor; + /** \brief vertical orientation of the baseline of the whole block (with respect to the single lines) + * + * \image html jkqtmathtext_verticalorientation.png + */ + JKQTMathTextVerticalOrientation verticalOrientation; + /** \brief when \c true, whitespaces are displayed with a visible character */ + bool visibleWhitespace; + + /** \copydoc JKQTMathTextNode::getSizeInternal() */ + virtual void getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; + /** \brief sets all necessary settings in \a currentEv for drawing this node */ + virtual void transformEnvironment(JKQTMathTextEnvironment& currentEv) const; + + /** \brief describes the layout of the whole node */ + struct LayoutInfo: public JKQTMathTextNodeSize { + LayoutInfo(); + /** \brief the text from JKQTMathTextVerbatimNode::text, split into lines */ + QStringList lines; + /** \brief drawing position for each line */ + QList X; + }; + /** \brief calclates the layout of the whole block/node + * + * \note This function does NOT call transformEnvironment(); + * it has to be called before calling this! + */ + LayoutInfo calcLayout(QPainter& painter, const JKQTMathTextEnvironment& currentEv) const; + /** \brief transforms the \a text before sizing/drawing (may e.g. exchange special letters for other unicode symbols etc.) */ + virtual QString textTransform(const QString& text, const JKQTMathTextEnvironment& currentEv) const override; }; + #endif // JKQTMATHTEXTTEXTNODE_H diff --git a/lib/jkqtplotter/jkqtplotter.h b/lib/jkqtplotter/jkqtplotter.h index c966c10c88..1dcb49d702 100644 --- a/lib/jkqtplotter/jkqtplotter.h +++ b/lib/jkqtplotter/jkqtplotter.h @@ -419,7 +419,7 @@ JKQTPLOTTER_LIB_EXPORT void initJKQTPlotterResources(); * \section JKQTPLOTTER_USEQTCREATOR How to use JKQTPlotter in the Qt Form Designer * * As JKQTPlotter is a standard Qt widget, you can also use it in Qt UI-files designed with the Qt From Designer (e.g. from within QTCreator). - * For this to work you have to use the Promote QWidget"-feature of the form designer. The steps you need to take are detailed below: + * For this to work you have to use the Promote QWidget"-feature of the form designer. The steps you need to take are detailed below: *
      *
    1. add a new UI-file to your project and open it in the Form Editor. Then right-click the form and select `Promote Widgets ...`: *