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*}
This commit is contained in:
jkriege2 2022-08-03 15:23:14 +02:00
parent c7ffdacfcc
commit 7d686f0c9a
17 changed files with 554 additions and 160 deletions

View File

@ -61,6 +61,14 @@
.
\section JKQTMathTextSuppoertedLaTeXVerbatim Verbatim Text
Sometimes it is necessary to typeset text withou interpreting it as LaTeX markup. These instructions are implemented for that:
- <code>\\verb!...!</code>: interpret enclosed text between \c ! as verbose. Instead of \ ! you can choose ANY character! \image html jkqtmathtext/jkqtmathtext_verb.png generated by <code>\\verb!\\LaTeX{} is not pares inside \\verb~..~! outside {\\backslash}verb</code>
- <code>\\begin{verbatim}...\\end{verbatim}</code>: interpret enclosed multi-line text as verbatim. \image html jkqtmathtext/jkqtmathtext_verbatim.png generated by <code>outside\\begin{verbatim}\ninside \\LaTeX verbatim\n 2nd verbaimline\n\t3rd line\n\\end{verbatim}</code>
- <code>\\begin{lstlisting}...\\end{lstlisting}</code>: 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 <code>outside\\begin{lstlisting}\nint main() {\n printf("Hello World\\n");\n}\n\\end{lstlisting}</code>
- <code>\\begin{verbatim*}...\\end{verbatim*}</code>: interpret enclosed multi-line text as verbatim. Print with visible whitespace and tab characters \image html jkqtmathtext/jkqtmathtext_verbatimast.png generated by <code>outside\\begin{verbatim*}\ninside \\LaTeX verbatim\n 2nd verbaimline\n\t3rd line\n\\end{verbatim*}</code>
.
\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
- <code>\\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} ...</code>: Decorations over/under symbols \image html jkqtmathtext/jkqtmathtext_mathdeco.png
- <code>\\verb{don't parse this _aaa\\LaTeX} </code>: interpret enclosed text as verbose \image html jkqtmathtext/jkqtmathtext_verb.png
.
\section JKQTMathTextSuppoertedLaTeXTextAlignment Environments for Multi-line text

View File

@ -53,6 +53,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>IMPROVED/NEW/breaking: refactored LaTeX parser in JKQTMathText</li>
<li>REMOVED/breaking: \c \\v[a-zA-Z] and shorthand for \c \\vec{a-zA-Z} was removed, implementation of \c \\bbR,\c \\bbC,... changed</li>
<li>IMPROVED/REWORKED rendering of text in text- and math-mode. Now it is more consistent with the output of LaTeX itself</li>
<li>BREAKING/REWORKED: The \\verb!...!-command now works the same as in LaTeX</li>
<li>NEW: now supports new decoration instructions: \c \\cancel, \c \\xcancel, \c \\bcancel, \c \\sout, \c \\ocirc, \c \\widetilde, \c \\widehat, \c \\breve</li>
<li>NEW: reworked drawing of decorations: improved appearance and positioning!</li>
<li>NEW: reworked code structure: broke up large, single CPP-files into several smaller files!</li>
@ -78,6 +79,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>NEW: added support for -- and --- for en- and em-dashes</li>
<li>NEW: added support for \c \\char"HEX , \c \\char'OCTAL and \c \\charDECIMAL for inserting any uicode character code</li>
<li>NEW: added support for \\bigl,\\bigr,\\Bigr,... commands for fixed-size but enlarged paramtheses</li>
<li>NEW: added support for \\begin{verbatim}...\\end{verbatim}, \\begin{verbatim*}...\\end{verbatim*}</li>
</ul></li>
</ul>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -2,6 +2,7 @@
#include "ui_testform.h"
#include <QDebug>
#include <sstream>
#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<JKQTMathTextMatrixNode*>(node);
JKQTMathTextDecoratedNode* decoN=dynamic_cast<JKQTMathTextDecoratedNode*>(node);
JKQTMathTextEmptyBoxNode* emptyN=dynamic_cast<JKQTMathTextEmptyBoxNode*>(node);
JKQTMathTextVerbatimNode* verbN=dynamic_cast<JKQTMathTextVerbatimNode*>(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; i<list.size(); i++) {
ti->addChild(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) {

View File

@ -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;
}

View File

@ -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<QVariant> to a string
\ingroup jkqtptools_string

View File

@ -1344,9 +1344,9 @@ JKQTMathText::tokenType JKQTMathText::getToken() {
}
//std::cout<<"found instruction node '"<<currentTokenName.toStdString()<<"'\n";
if (currentTokenName.size()==0) error_list.append(tr("error @ ch. %1: parser encountered empty istruction").arg(currentTokenID));
if (currentTokenName=="newline") return MTTinstructionNewline;
if (currentTokenName=="linebreak") return MTTinstructionNewline;
if (currentTokenName=="char") {
else if (currentTokenName=="newline") return MTTinstructionNewline;
else if (currentTokenName=="linebreak") return MTTinstructionNewline;
else if (currentTokenName=="char") {
QString num="";
currentTokenID++;
c=parseString[currentTokenID];
@ -1386,6 +1386,32 @@ JKQTMathText::tokenType JKQTMathText::getToken() {
return currentToken=MTTtext;
}
} else if (currentTokenName.startsWith("verb")) {
if (currentTokenName.size()>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<JKQTMathTextNode*> > items;
//int lines=0;
//int cols=0;
bool first=true;
QVector<JKQTMathTextNode*> 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 "<<line.size()<<" items.\n";
items.append(line);
line.clear();
}
first=false;
}
//std::cout<<" creating matrix-node with "<<items.size()<<" items.\n";
if (envname=="pmatrix") nl->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<<jkqtp_QColor2String(Qt::lightGray);
nl->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<JKQTMathTextNode*> > items;
//int lines=0;
//int cols=0;
bool first=true;
QVector<JKQTMathTextNode*> 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 "<<line.size()<<" items.\n";
items.append(line);
line.clear();
}
first=false;
}
//std::cout<<" creating matrix-node with "<<items.size()<<" items.\n";
if (envname=="pmatrix") nl->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<<jkqtp_QColor2String(Qt::lightGray);
nl->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 (currentTokenID<parseString.size() && !seq.endsWith(endsequence)) {
seq+=parseString[currentTokenID];
currentTokenID++;
}
currentTokenID--;
if (seq.endsWith(endsequence)) {
seq=seq.left(seq.size()-endsequence.size());
}
return seq;
}
JKQTMathTextNode *JKQTMathText::getParsedNode() const {
return this->parsedNode;
@ -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 "???";
}

View File

@ -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

View File

@ -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 <a href="https://doc.qt.io/qt-5/qfont.html">QFont</a> 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;
};

View File

@ -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()
{}

View File

@ -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<QPointF> 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<JKQTMathTextNode*> nodes;

View File

@ -34,24 +34,82 @@
#include <QFont>
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 &currentEv, 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 &currentEv, 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; i<textIn.size(); i++) {
if (!textIn[i].isSpace()) text+=textIn[i];
if (!textIn[i].isSpace()) textTransformed+=textIn[i];
}
}
this->text=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="<<text<<" addWhitespace="<<addWhitespace<<") [=> this->text="<<this->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="<<text<<" font="<<f;
const QPen p(currentEv.color, fm.lineWidth(), Qt::SolidLine);
painter.setPen(p);
auto drawString=[&](QPainter& painter, const QFont& f, double x, double y, const QString& txt) {
if (currentEv.font==MTEblackboard && parentMathText->isFontBlackboardSimulated()) {
QPainterPath path;
path.addText(QPointF(x, y), f, txt);
painter.drawPath(path);
} else {
painter.setFont(f);
painter.drawText(QPointF(x, y), txt);
}
};
for (int i=0; i<textpart.size(); i++) {
if (fontForcedUpright[i]) drawString(painter, fnonItalic, x+textpartXPos[i], y, textpart[i]);
else drawString(painter, f, x+textpartXPos[i], y, textpart[i]);
if (fontForcedUpright[i]) drawString(painter, currentEv, fnonItalic, x+textpartXPos[i], y, textpart[i]);
else drawString(painter, currentEv, f, x+textpartXPos[i], y, textpart[i]);
}
return x+width;
}
bool JKQTMathTextTextNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) {
html=html+currentEv.toHtmlStart(defaultEv, parentMathText)+text+currentEv.toHtmlAfter(defaultEv, parentMathText);
return true;
}
QString JKQTMathTextTextNode::getText() const {
return this->text;
}
QString JKQTMathTextTextNode::getTypeName() const
{
return QLatin1String("JKQTMathTextTextNode(")+text+")";
}
QString JKQTMathTextTextNode::textTransform(const QString &text, JKQTMathTextEnvironment currentEv, bool /*forSize*/)
QString JKQTMathTextTextNode::textTransform(const QString &text, const JKQTMathTextEnvironment &currentEv) const
{
QString txt=text;
auto fnt=parentMathText->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<text.size(); i++) {
QChar c=text[i];
switch(c.unicode()) {
case '-': txt+=QString(QString(" ")+QChar(0x2212)); break;
case '-':
if (fm.inFont(QChar(0x2212))) {
txt+=QString(QString(" ")+QChar(0x2212));
} else {
txt+=QString(QString(" -"));
}
break;
case '+': txt+=QString(QString(" +")); break;
case '<': txt+=QString(QString(" <")); break;
case '>': 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; i<l.lines.size(); i++) {
drawString(painter, currentEv, f, x+l.X.at(i).x(), y+l.X.at(i).y(), l.lines.at(i));
}
return x+l.width;
}
bool JKQTMathTextVerbatimNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv)
{
transformEnvironment(currentEv);
const bool isMultiLine=text.count('\n')>0;
html+=currentEv.toHtmlStart(defaultEv, parentMathText);
if (isMultiLine) {
if (alignment==MTHALeft) {
html+="<div align=\"left\">";
} else if (alignment==MTHACentered) {
html+="<div align=\"center\">";
} else if (alignment==MTHARight) {
html+="<div align=\"right\">";
}
}
html+="<pre>";
html+=textTransform(text, currentEv).toHtmlEscaped();
html+="</pre>";
if (isMultiLine) html+="</div>";
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 &currentEv) 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<double> widths, heights, ascents, descents, strikeouts;
double heightSum=0;
QList<double> 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; i<l.lines.size(); i++) {
if (i==0) {
heightSum=fm.ascent();
} else if (i>0) {
const double deltaLine=qMax(linespacing, descents.last()+lineLeading+fm.ascent());
heightSum=heightSum+deltaLine;
y=y+deltaLine;
}
widths<<fm.boundingRect(l.lines[i]).width();
l.width=qMax(l.width, widths.last());
heights<<fm.height();
ascents<<fm.ascent();
descents<<fm.descent();
strikeouts<<fm.strikeOutPos();
ysFromFirstLine<<y;
}
heightSum+=descents.last();
l.overallHeight=heightSum;
double y0=0;
if (verticalOrientation==MTVOTop) {
l.baselineHeight=0;
l.strikeoutPos=0;
y0=ascents.first();
} else if (verticalOrientation==MTVOFirstLine) {
l.baselineHeight=ascents.first();
l.strikeoutPos=strikeouts.first();
y0=0;
} else if (verticalOrientation==MTVOCentered) {
l.baselineHeight=heightSum/2.0;
l.strikeoutPos=heightSum/4.0;
y0=-heightSum/2.0+ascents.first();
} else if (verticalOrientation==MTVOLastLine) {
l.baselineHeight=heightSum-descents.last();
l.strikeoutPos=strikeouts.last();
y0=-(heightSum-ascents.first()-descents.last());
} else if (verticalOrientation==MTVOBottom) {
l.baselineHeight=heightSum;
l.strikeoutPos=0;
y0=-(heightSum-ascents.first());
}
for (int i=0; i<l.lines.size(); i++) {
double x=0;
if (alignment==MTHARight) x=l.width-widths[i];
else if (alignment==MTHACentered) x=(l.width-widths[i])/2.0;
l.X<<QPointF(x,ysFromFirstLine[i]+y0);
}
return l;
}
QString JKQTMathTextVerbatimNode::textTransform(const QString &text, const JKQTMathTextEnvironment &currentEv) const
{
QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault);
const QFontMetricsF fm(f);
QString spRep=QChar(0xB7);
if (!fm.inFont(spRep[0])) {
spRep=QChar(0x2423);
}
QString tabRep=QString(4,QChar(0x2192));
if (!fm.inFont(tabRep[0])) {
spRep=QString(4,QChar(0xAC));
}
QString res=JKQTMathTextTextBaseNode::textTransform(text, currentEv);
if (res.startsWith('\n')) res=res.right(res.size()-1);
if (res.endsWith('\n')) res=res.left(res.size()-1);
if (visibleWhitespace) {
res.replace(' ', spRep);
res.replace('\t', tabRep);
return res;
}
return res;
}
QString MTplainTextNode::textTransform(const QString &_text, JKQTMathTextEnvironment /*currentEv*/, bool /*forSize*/)
JKQTMathTextVerbatimNode::LayoutInfo::LayoutInfo():
JKQTMathTextNodeSize(), lines(), X()
{
return _text;
}

View File

@ -1,4 +1,4 @@
/*
/*
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
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 &currentEv, 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<bool>& fontForcedUpright, QList<double>& 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<bool>& 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<QPointF> 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

View File

@ -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 <a href="http://doc.qt.io/archives/qt-4.8/designer-using-custom-widgets.html">Promote QWidget"-feature</a> of the form designer. The steps you need to take are detailed below:
* For this to work you have to use the <a href="https://doc.qt.io/qt-6/designer-using-custom-widgets.html">Promote QWidget"-feature</a> of the form designer. The steps you need to take are detailed below:
* <ol>
* <li> add a new UI-file to your project and open it in the Form Editor. Then right-click the form and select `Promote Widgets ...`:
*