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 0000000000..866df88036 Binary files /dev/null and b/doc/images/jkqtmathtext/jkqtmathtext_lstlisting.png differ diff --git a/doc/images/jkqtmathtext/jkqtmathtext_verb.png b/doc/images/jkqtmathtext/jkqtmathtext_verb.png index 4463dc8483..5e0a422ae7 100644 Binary files a/doc/images/jkqtmathtext/jkqtmathtext_verb.png and b/doc/images/jkqtmathtext/jkqtmathtext_verb.png differ diff --git a/doc/images/jkqtmathtext/jkqtmathtext_verbatim.png b/doc/images/jkqtmathtext/jkqtmathtext_verbatim.png new file mode 100644 index 0000000000..caa0b7c6d4 Binary files /dev/null and b/doc/images/jkqtmathtext/jkqtmathtext_verbatim.png differ diff --git a/doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png b/doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png new file mode 100644 index 0000000000..f6d2850fc2 Binary files /dev/null and b/doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png differ 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 ...`: *