mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-24 17:41:39 +08:00
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:
parent
c7ffdacfcc
commit
7d686f0c9a
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
BIN
doc/images/jkqtmathtext/jkqtmathtext_lstlisting.png
Normal file
BIN
doc/images/jkqtmathtext/jkqtmathtext_lstlisting.png
Normal file
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 |
BIN
doc/images/jkqtmathtext/jkqtmathtext_verbatim.png
Normal file
BIN
doc/images/jkqtmathtext/jkqtmathtext_verbatim.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png
Normal file
BIN
doc/images/jkqtmathtext/jkqtmathtext_verbatimast.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 "???";
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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()
|
||||
{}
|
||||
|
@ -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;
|
||||
|
@ -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 ¤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; 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 ¤tEv) 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 ¤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<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 ¤tEv) 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 ¤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<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
|
||||
|
||||
|
||||
|
@ -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 ...`:
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user