diff --git a/doc/dox/whatsnew.dox b/doc/dox/whatsnew.dox index b67d46f141..bfdfed6b96 100644 --- a/doc/dox/whatsnew.dox +++ b/doc/dox/whatsnew.dox @@ -39,6 +39,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
  • NEW: reworked node class tree: inserted base-class nodes for single-child, dual-child!
  • NEW: improved frac-rendering: font-scaling takes nesting-level into account, overall-rendering, sizes, if a brace surrounds a frac, the heights are equal above and below to center the brace , ...
  • NEW: shows strikeoutPos when drawing Debug-Boxes
  • +
  • NEW: LaTeX-Parser understands optional instruction parameters in [...] now
  • diff --git a/examples/jkqtmathtext_test/testform.cpp b/examples/jkqtmathtext_test/testform.cpp index 6f65577d07..08f334231b 100644 --- a/examples/jkqtmathtext_test/testform.cpp +++ b/examples/jkqtmathtext_test/testform.cpp @@ -355,7 +355,7 @@ QTreeWidgetItem *TestForm::createTree(JKQTMathTextNode *node, QTreeWidgetItem* p name=QString("MTsqrtNode: deg=%1").arg(sqrtN->getDegree()); if (sqrtN->getChild()) ti->addChild(createTree(sqrtN->getChild(), ti)); } else if (braceN) { - name=QString("MTbraceNode: l[showL=%3]='%1', r[showR=%4]='%2'").arg(braceN->getOpenbrace()).arg(braceN->getClosebrace()).arg(braceN->getShowOpeningBrace()).arg(braceN->getShowClosingBrace()); + name=QString("MTbraceNode: l='%1', r='%2'").arg(JKQTMathTextBraceType2String(braceN->getOpenbrace())).arg(JKQTMathTextBraceType2String(braceN->getClosebrace())); if (braceN->getChild()) ti->addChild(createTree(braceN->getChild(), ti)); } else if (superN) { name=QString("MTsuperscriptNode"); diff --git a/lib/jkqtmathtext/jkqtmathtext.cpp b/lib/jkqtmathtext/jkqtmathtext.cpp index 0d10efa371..3750c7749d 100644 --- a/lib/jkqtmathtext/jkqtmathtext.cpp +++ b/lib/jkqtmathtext/jkqtmathtext.cpp @@ -823,20 +823,33 @@ JKQTMathText::tokenType JKQTMathText::getToken() { if (currentTokenID>parseString.size()-1) return currentToken=MTTnone; QChar c=parseString[currentTokenID]; currentTokenName=""; - if (c=='\\') { // read an instruction name + //---------------------------------------------------------- + // define some static sets for easy character lookup/identificattion + static QSet TokenCharacters; + static QSet mathEnvironmentSpecialChars, mathEnvironmentSpecialEndChars; + static QSet SingleCharInstructions; + if (TokenCharacters.size()==0) { + mathEnvironmentSpecialChars<<'(' << '[' << '|' << ')' << ']' << '+' << '-' << '*' << '/' << '<' << '>' << '='; + mathEnvironmentSpecialEndChars<<'(' << '&' << '[' << '|' << ')' << ']' << '\\' << '$' << '{' << '}' << '_' << '^' << '+' << '-' << '/' << '*' << '=' << '<' << '>'; + TokenCharacters<<'_'<<'^'<<'\\'<<'$'<<'&'<<'}'<<'{'<<'['<<']'; + SingleCharInstructions<<'|'<<';'<<':'<<'!'<<','<<'_'<<'\\'<<'$'<<'%'<<'&'<<'#'<<'}'<<'{'<<' '<<'['<<']'; + } + + //---------------------------------------------------------- + // read an instruction name + if (c=='\\') { currentTokenID++; if (currentTokenID>=parseString.size()-1) return currentToken=MTTnone; c=parseString[currentTokenID]; - /*if (c=='_' || c=='\\' || c=='$' || c=='%' || c=='&' || c=='#' || c=='}' || c=='{') { - currentTokenName=c; // parse special one-symbol instructions like \\, \& ... - // that may be directly converted to text - return currentToken=MTTtext; - } else*/ if (c=='|' || c==';' || c==':' || c=='!' || c==',' || c=='_' || c=='\\' || c=='$' || - c=='%' || c=='&' || c=='#' || c=='}' || c=='{' || c==' ') { + //---------------------------------------------------------- + // parsing single-character instruction + if (SingleCharInstructions.contains(c)) { currentTokenName=c; // parse one-symbol instructions like \\, \& ... //std::cout<<"found text node '"< parse text if (parsingMathEnvironment) { // inside math environments we split texts at every brace {[(|)]} so that // braces form their own JKQTMathTextTextNode and may be formated accordingly - static QSet mathEnvironmentSpecialChars, mathEnvironmentSpecialEndChars; - if (mathEnvironmentSpecialChars.size()==0) { - mathEnvironmentSpecialChars<<'(' << '[' << '|' << ')' << ']' << '+' << '-' << '*' << '/' << '<' << '>' << '='; - mathEnvironmentSpecialEndChars<<'(' << '&' << '[' << '|' << ')' << ']' << '\\' << '$' << '{' << '}' << '_' << '^' << '+' << '-' << '/' << '*' << '=' << '<' << '>'; - } if (mathEnvironmentSpecialChars.contains(c)) { currentTokenName=c; //std::cout<<"found text node '"< mathEnvironmentSpecialText; + if (mathEnvironmentSpecialText.size()==0) { + mathEnvironmentSpecialText<<"+"<<"-"<<"="<<"*"<<"<"<<">"<<"|"<<"/"; + } + bool getNew=true; while (currentToken!=MTTnone) { getNew=true; @@ -935,10 +978,6 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn bool addWhite=(getToken()==MTTwhitespace) && (!parsingMathEnvironment); getNew=addWhite; if (parsingMathEnvironment) { - static QSet mathEnvironmentSpecialText; - if (mathEnvironmentSpecialText.size()==0) { - mathEnvironmentSpecialText<<"+"<<"-"<<"="<<"*"<<"<"<<">"<<"|"<<"/"; - } if (mathEnvironmentSpecialText.contains(text.trimmed())) { nl->addNode(new JKQTMathTextSymbolNode(this, text, addWhite)); } else { @@ -948,16 +987,16 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn nl->addNode(new JKQTMathTextTextNode(this, text, addWhite, parsingMathEnvironment)); } } else if (currentToken==MTTinstruction) { - QString name=currentTokenName; - if (name=="\\") break; // break on linebrak character + const QString currentInstructionName=currentTokenName; + if (currentInstructionName=="\\") break; // break on linebrak character getToken(); // look at next token if (currentToken==MTTopenbrace) { //std::cout<<"found '{' after '"<addNode(new JKQTMathTextSqrtNode(this, parseLatexString(true))); - } else if (name=="cbrt") { + } else if (currentInstructionName=="cbrt") { nl->addNode(new JKQTMathTextSqrtNode(this, parseLatexString(true), 3)); - } else if (name=="verb") { + } else if (currentInstructionName=="verb") { QString text=""; currentTokenID++; if (currentTokenID<=parseString.size()-1) { @@ -967,76 +1006,76 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn currentTokenID++; if (currentTokenIDaddNode(new JKQTMathTextTextNode(this, text, false)); } - } else if (name=="frac") { + } else if (currentInstructionName=="frac") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMfrac)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="dfrac" || name=="cfrac") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="dfrac" || currentInstructionName=="cfrac") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMdfrac)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="sfrac" || name=="slantfrac" || name=="xfrac") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="sfrac" || currentInstructionName=="slantfrac" || currentInstructionName=="xfrac") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMsfrac)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="stfrac" || name=="nicefrac" || name=="slanttextfrac" || name=="xtfrac") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="stfrac" || currentInstructionName=="nicefrac" || currentInstructionName=="slanttextfrac" || currentInstructionName=="xtfrac") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMstfrac)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="tfrac") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="tfrac") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMtfrac)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="stackrel") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="stackrel") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMstackrel)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="binom") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="binom") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); - if (n1 && n2) nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTParenthesis, JKQTMathTextBraceNode::MTBTParenthesis, new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMstackrel))); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="underbrace") { + if (n1 && n2) nl->addNode(new JKQTMathTextBraceNode(this, MTBTParenthesis, MTBTParenthesis, new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMstackrel))); + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="underbrace") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMunderbrace)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="underset") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="underset") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMunderset)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="overbrace") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="overbrace") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMoverbrace)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="overset") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="overset") { JKQTMathTextNode* n1=parseLatexString(true); JKQTMathTextNode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMoverset)); - else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - } else if (name=="begin") { + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else if (currentInstructionName=="begin") { if (getToken()==MTTtext) { QString envname=currentTokenName; while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name' @@ -1048,7 +1087,7 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn QVector line; //std::cout<<"found \\begin{matrix}\n"; while (first || currentToken==MTTampersand || (currentToken==MTTinstruction && currentTokenName=="\\")) { - JKQTMathTextNode* it=parseLatexString(true, "", envname); + JKQTMathTextNode* it=parseLatexString(true, MTBTAny, envname); if (currentToken==MTTampersand) { //std::cout<<" appending item\n"; line.append(it); @@ -1061,12 +1100,12 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn first=false; } //std::cout<<" creating matrix-node with "<addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTParenthesis, JKQTMathTextBraceNode::MTBTParenthesis, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="cases") nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTCurlyBracket, JKQTMathTextBraceNode::MTBTNone, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="bmatrix") nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTSquareBracket, JKQTMathTextBraceNode::MTBTSquareBracket, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="Bmatrix") nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTCurlyBracket, JKQTMathTextBraceNode::MTBTCurlyBracket, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="vmatrix") nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTSingleLine, JKQTMathTextBraceNode::MTBTSingleLine, new JKQTMathTextMatrixNode(this, items))); - else if (envname=="Vmatrix") nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTDoubleLine, JKQTMathTextBraceNode::MTBTDoubleLine, new JKQTMathTextMatrixNode(this, items))); + if (envname=="pmatrix") nl->addNode(new JKQTMathTextBraceNode(this, MTBTParenthesis, MTBTParenthesis, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="cases") nl->addNode(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTNone, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="bmatrix") nl->addNode(new JKQTMathTextBraceNode(this, MTBTSquareBracket, MTBTSquareBracket, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="Bmatrix") nl->addNode(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTCurlyBracket, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="vmatrix") nl->addNode(new JKQTMathTextBraceNode(this, MTBTSingleLine, MTBTSingleLine, new JKQTMathTextMatrixNode(this, items))); + else if (envname=="Vmatrix") nl->addNode(new JKQTMathTextBraceNode(this, MTBTDoubleLine, MTBTDoubleLine, new JKQTMathTextMatrixNode(this, items))); else nl->addNode(new JKQTMathTextMatrixNode(this, items)); //std::cout<<" creating matrix-node ... done!\n"; } else { @@ -1077,7 +1116,7 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn while (currentToken!=MTTclosebrace) getToken(); getNew=true; } - } else if (name=="end") { + } else if (currentInstructionName=="end") { if (getToken()==MTTtext) { QString envname=currentTokenName; while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name' @@ -1091,50 +1130,50 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn while (currentToken!=MTTclosebrace) getToken(); getNew=true; } - } else if (name=="vec") { + } else if (currentInstructionName=="vec") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDvec, parseLatexString(true))); - } else if (name=="overline"||name=="oline"||name=="ol") { + } else if (currentInstructionName=="overline"||currentInstructionName=="oline"||currentInstructionName=="ol") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDoverline, parseLatexString(true))); - } else if (name=="underline"||name=="uline"||name=="ul") { + } else if (currentInstructionName=="underline"||currentInstructionName=="uline"||currentInstructionName=="ul") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDunderline, parseLatexString(true))); - } else if (name=="uuline"||name=="uul") { + } else if (currentInstructionName=="uuline"||currentInstructionName=="uul") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDdoubleunderline, parseLatexString(true))); - } else if (name=="ooline"||name=="ool") { + } else if (currentInstructionName=="ooline"||currentInstructionName=="ool") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDdoubleoverline, parseLatexString(true))); - } else if (name=="arrow"||name=="overrightarrow"||name=="overarrow") { + } else if (currentInstructionName=="arrow"||currentInstructionName=="overrightarrow"||currentInstructionName=="overarrow") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDarrow, parseLatexString(true))); - } else if (name=="hat" || name=="^") { + } else if (currentInstructionName=="hat" || currentInstructionName=="^") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDhat, parseLatexString(true))); - } else if (name=="widehat") { + } else if (currentInstructionName=="widehat") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDwidehat, parseLatexString(true))); - } else if (name=="check" || name=="v") { + } else if (currentInstructionName=="check" || currentInstructionName=="v") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDcheck, parseLatexString(true))); - } else if (name=="widecheck") { + } else if (currentInstructionName=="widecheck") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDwidecheck, parseLatexString(true))); - } else if (name=="bar") { + } else if (currentInstructionName=="bar") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDbar, parseLatexString(true))); - } else if (name=="dot" || name==".") { + } else if (currentInstructionName=="dot" || currentInstructionName==".") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDdot, parseLatexString(true))); - } else if (name=="ocirc") { + } else if (currentInstructionName=="ocirc") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDocirc, parseLatexString(true))); - } else if (name=="tilde" || name=="~") { + } else if (currentInstructionName=="tilde" || currentInstructionName=="~") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDtilde, parseLatexString(true))); - } else if (name=="breve" || name=="u") { + } else if (currentInstructionName=="breve" || currentInstructionName=="u") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDbreve, parseLatexString(true))); - } else if (name=="widetilde") { + } else if (currentInstructionName=="widetilde") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDwidetilde, parseLatexString(true))); - } else if (name=="ddot") { + } else if (currentInstructionName=="ddot") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDddot, parseLatexString(true))); - } else if (name=="cancel") { + } else if (currentInstructionName=="cancel") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDcancel, parseLatexString(true))); - } else if (name=="xcancel") { + } else if (currentInstructionName=="xcancel") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDxcancel, parseLatexString(true))); - } else if (name=="bcancel") { + } else if (currentInstructionName=="bcancel") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDbcancel, parseLatexString(true))); - } else if (name=="strike" || name=="st" || name=="sout") { + } else if (currentInstructionName=="strike" || currentInstructionName=="st" || currentInstructionName=="sout") { nl->addNode(new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::MTDstrike, parseLatexString(true))); } else { - if (name=="textcolor" || name=="mathcolor" || name=="color" || name=="colorbox") { + if (currentInstructionName=="textcolor" || currentInstructionName=="mathcolor" || currentInstructionName=="color" || currentInstructionName=="colorbox") { bool foundError=true; QString col=""; if (getToken()==MTTtext) { @@ -1145,127 +1184,106 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn } } } - if (foundError) error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); - else nl->addNode(new JKQTMathTextInstruction1Node(this, name, parseLatexString(true), QStringList(col))); + if (foundError) error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + else nl->addNode(new JKQTMathTextInstruction1Node(this, currentInstructionName, parseLatexString(true), QStringList(col))); } else { - nl->addNode(new JKQTMathTextInstruction1Node(this, name, parseLatexString(true))); + nl->addNode(new JKQTMathTextInstruction1Node(this, currentInstructionName, parseLatexString(true))); } } + } else if (currentToken==MTTopenbracket && currentInstructionName!="left") { + //std::cout<<"found '[' after '"<(n1); + JKQTMathTextTextNode* n1txt=dynamic_cast(n1); + if (n1lst && n1lst->count()==1) { + n1txt=dynamic_cast(n1lst->child(0)); + } + int degree=2; + bool ok=false; + if (n1txt) degree=n1txt->getText().toInt(&ok); + if (!ok) { + degree=2; + error_list.append(tr("error @ ch. %1: an integer in [] after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } + + JKQTMathTextNode* n2=nullptr; + if (getToken()==MTTopenbrace) n2=parseLatexString(true); + else error_list.append(tr("error @ ch. %1: expected one argument in '{' braces after '%2' command with an optional argument in []").arg(currentTokenID).arg(currentInstructionName)); + + if (n1 && n2) nl->addNode(new JKQTMathTextSqrtNode(this, n2, degree)); + else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName)); + } else { + nl->addNode(new JKQTMathTextTextNode(this, "[", false)); + } } else { //std::cout<<"did not find '{' after '"<0) { - if (QString(currentTokenName[0])==quitOnClosingBrace || quitOnClosingBrace=="any" || QString(currentTokenName[0])==".") { + bool tokenWasNoBrace=false; + if (TokenNameMatchesJKQTMathTextBraceType(currentTokenName[0], quitOnClosingBrace, true, &tokenWasNoBrace)) { //std::cout<<"found \\right '"<" && (currentTokenName=="rangle" || QString(currentTokenName[0])==".")) { - showLeftBrace=true; - showRightBrace=(QString(currentTokenName[0])!="."); - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - break; - } else if (quitOnClosingBrace=="any") { - showLeftBrace=true; - showRightBrace=(QString(currentTokenName[0])!="."); - //currentTokenName=currentTokenName.right(currentTokenName.size()-1); - break; + if (InstructionNameMatchesJKQTMathTextBraceType(currentTokenName, quitOnClosingBrace, true)) { + currentTokenName=currentTokenName.right(currentTokenName.size()-1); + break; + } + } else if (currentToken==MTTclosebracket) { + if (quitOnClosingBrace==MTBTSquareBracket || quitOnClosingBrace==MTBTAny) { + currentTokenName=currentTokenName.right(currentTokenName.size()-1); + break; } } else { getNew=false; } - } else if (name=="left") { + } else if (currentInstructionName=="left") { if (currentToken==MTTtext) { if (currentTokenName.size()>0) { - if (currentTokenName[0]=='(') { + const JKQTMathTextBraceType bracetype=TokenName2JKQTMathTextBraceType(currentTokenName[0]); + if (bracetype==MTBTNone) { + currentTokenName=currentTokenName.right(currentTokenName.size()-1); + JKQTMathTextNode* cn=parseLatexString(currentTokenName.size()<=0, MTBTAny); + nl->addNode(new JKQTMathTextBraceNode(this, MTBTNone, bracetype, cn)); + } else if (isPrintableJKQTMathTextBraceType(bracetype)) { currentTokenName=currentTokenName.right(currentTokenName.size()-1); // we already used the first character from the text token! - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTParenthesis, JKQTMathTextBraceNode::MTBTParenthesis, parseLatexString(currentTokenName.size()<=0, ")"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='[') { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTSquareBracket, JKQTMathTextBraceNode::MTBTSquareBracket, parseLatexString(currentTokenName.size()<=0, "]"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='{') { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTCurlyBracket, JKQTMathTextBraceNode::MTBTCurlyBracket, parseLatexString(currentTokenName.size()<=0, "}"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='<') { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTAngleBracket, JKQTMathTextBraceNode::MTBTAngleBracket, parseLatexString(currentTokenName.size()<=0, ">"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='|') { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTSingleLine, JKQTMathTextBraceNode::MTBTSingleLine, parseLatexString(currentTokenName.size()<=0, "|"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='~') { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTCeilBracket, JKQTMathTextBraceNode::MTBTCeilBracket, parseLatexString(currentTokenName.size()<=0, "~"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='_') { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTFloorBracket, JKQTMathTextBraceNode::MTBTFloorBracket, parseLatexString(currentTokenName.size()<=0, "_"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='#') { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTDoubleLine, JKQTMathTextBraceNode::MTBTDoubleLine, parseLatexString(currentTokenName.size()<=0, "#"), showLeftBrace, showRightBrace)); - } else if (currentTokenName[0]=='.') { - showLeftBrace=false; - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - JKQTMathTextNode* cn=parseLatexString(currentTokenName.size()<=0, "any"); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTNone, JKQTMathTextBraceNode::TokenNameString2TokenType(currentTokenName), cn, showLeftBrace, showRightBrace)); + nl->addNode(new JKQTMathTextBraceNode(this, bracetype, bracetype, parseLatexString(currentTokenName.size()<=0, bracetype))); } else { getNew=false; } } - } else if (currentToken==MTTinstruction && currentTokenName=="langle") { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTAngleBracket, JKQTMathTextBraceNode::MTBTAngleBracket, parseLatexString(true, ">"), showLeftBrace, showRightBrace)); - } else if (currentToken==MTTinstruction && currentTokenName=="{") { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTCurlyBracket, JKQTMathTextBraceNode::MTBTCurlyBracket, parseLatexString(currentTokenName.size()<=0, "}"), showLeftBrace, showRightBrace)); - } else if (currentToken==MTTinstruction && currentTokenName=="lfloor") { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTFloorBracket, JKQTMathTextBraceNode::MTBTFloorBracket, parseLatexString(true, "_"), showLeftBrace, showRightBrace)); - } else if (currentToken==MTTinstruction && currentTokenName=="lceil") { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTCeilBracket, JKQTMathTextBraceNode::MTBTCeilBracket, parseLatexString(true, "~"), showLeftBrace, showRightBrace)); - } else if (currentToken==MTTinstruction && currentTokenName=="|") { - currentTokenName=currentTokenName.right(currentTokenName.size()-1); - nl->addNode(new JKQTMathTextBraceNode(this, JKQTMathTextBraceNode::MTBTDoubleLine, JKQTMathTextBraceNode::MTBTDoubleLine, parseLatexString(currentTokenName.size()<=0, "#"), showLeftBrace, showRightBrace)); - } else if (currentToken==MTTinstruction && currentTokenName==quitOnClosingBrace) { - break; + } else if (currentToken==MTTinstruction) { + const JKQTMathTextBraceType bracetypeopening=InstructionName2OpeningJKQTMathTextBraceType(currentTokenName); + if (bracetypeopening!=MTBTUnknown) { + nl->addNode(new JKQTMathTextBraceNode(this, bracetypeopening, bracetypeopening, parseLatexString(true, bracetypeopening))); + } else if (currentToken==MTTinstruction && TokenNameMatchesJKQTMathTextBraceType(currentTokenName, quitOnClosingBrace, true)) { + break; + } + } else if (currentToken==MTTopenbracket) { + nl->addNode(new JKQTMathTextBraceNode(this, MTBTSquareBracket, MTBTSquareBracket, parseLatexString(true, MTBTSquareBracket))); + } else { + error_list.append(tr("error @ ch. %1: unexpected token after \\left").arg(currentTokenID)); } + } else { //bool addWhite=(currentToken==MTTwhitespace); //getNew=addWhite; getNew=false; bool done=false; - if (name.size()==2) { - QChar n0=name[0]; - QChar n1=name[1]; + if (currentInstructionName.size()==2) { + QChar n0=currentInstructionName[0]; + QChar n1=currentInstructionName[1]; if (n0=='v' && n1.isLetter()) { done=true; //std::cout<<"found \\v... command\n"; @@ -1275,16 +1293,16 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn //std::cout<<"found \\v... command\n"; nl->addNode(new JKQTMathTextInstruction1Node(this, "mathcal", new JKQTMathTextTextNode(this, QString(n1), false, parsingMathEnvironment))); } - } else if (name.size()==3) { - QString n0=name.left(2); - QChar n1=name[name.size()-1]; + } else if (currentInstructionName.size()==3) { + QString n0=currentInstructionName.left(2); + QChar n1=currentInstructionName[currentInstructionName.size()-1]; if (n0=="bb" && n1.isLetter()) { done=true; //std::cout<<"found \\v... command\n"; nl->addNode(new JKQTMathTextInstruction1Node(this, "mathbb", new JKQTMathTextTextNode(this, QString(n1), false, parsingMathEnvironment))); } } - if (!done) nl->addNode(new JKQTMathTextSymbolNode(this, name, false));//, addWhite)); + if (!done) nl->addNode(new JKQTMathTextSymbolNode(this, currentInstructionName, false));//, addWhite)); } } @@ -1354,6 +1372,11 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn nl->addNode(parseLatexString(true)); } else if (currentToken==MTTclosebrace) { break; + } else if (currentToken==MTTopenbracket) { + nl->addNode(new JKQTMathTextTextNode(this, "[", false)); + } else if (currentToken==MTTclosebracket) { + if (quitOnClosingBracket) break; + else nl->addNode(new JKQTMathTextTextNode(this, "]", false)); } else if (currentToken==MTTampersand) { break; } else if (currentToken==MTTdollar) { @@ -1368,9 +1391,10 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, const QString& quitOn if (getNew) getToken(); } //std::cout<<" leaving parseLatexString()\n"; - return nl; + return JKQTMathTextListNode::simplyfyListNode(nl); } + JKQTMathTextNode *JKQTMathText::getParsedNode() const { return this->parsedNode; } diff --git a/lib/jkqtmathtext/jkqtmathtext.h b/lib/jkqtmathtext/jkqtmathtext.h index 9f7d043264..87519e6c95 100644 --- a/lib/jkqtmathtext/jkqtmathtext.h +++ b/lib/jkqtmathtext/jkqtmathtext.h @@ -589,22 +589,30 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject { /** \brief the token types that may arrise in the string */ enum tokenType { - MTTnone, - MTTtext, - MTTinstruction, - MTTunderscore, - MTThat, - MTTdollar, - MTTopenbrace, - MTTclosebrace, - MTTwhitespace, - MTTampersand + MTTnone, /*!< \brief no token */ + MTTtext, /*!< \brief a piece of general text */ + MTTinstruction, /*!< \brief an instruction, started by "\", e.g. "\textbf", ... */ + MTTunderscore, /*!< \brief the character "_" */ + MTThat, /*!< \brief the character "^" */ + MTTdollar, /*!< \brief the character "$" */ + MTTopenbrace, /*!< \brief the character "{" */ + MTTclosebrace, /*!< \brief the character "}" */ + MTTopenbracket, /*!< \brief the character "[" */ + MTTclosebracket, /*!< \brief the character "]" */ + MTTwhitespace, /*!< \brief some whitespace */ + MTTampersand /*!< \brief the character "&" */ }; /** \brief tokenizer for the LaTeX parser */ tokenType getToken(); - /** \brief parse a LaTeX string */ - JKQTMathTextNode* parseLatexString(bool get, const QString& quitOnClosingBrace=QString(""), const QString& quitOnEnvironmentEnd=QString("")); + /** \brief parse a LaTeX string + * + * \param get if \c true this calls getToken() + * \param quitOnClosingBrace if unequal MTBTAny, this returns if the given closing brace is found + * \param quitOnEnvironmentEnd wuit if \end{quitOnEnvironmentEnd} is found + * \param quitOnClosingBracket if \c true, quits on encountering a MTTclosebracket token + */ + JKQTMathTextNode* parseLatexString(bool get, JKQTMathTextBraceType quitOnClosingBrace=JKQTMathTextBraceType::MTBTAny, const QString& quitOnEnvironmentEnd=QString(""), bool quitOnClosingBracket=false); /** \brief parse a LaTeX math environment */ JKQTMathTextNode* parseMath(bool get); diff --git a/lib/jkqtmathtext/jkqtmathtexttools.cpp b/lib/jkqtmathtext/jkqtmathtexttools.cpp index 95a0a5c7c6..0559a886e7 100644 --- a/lib/jkqtmathtext/jkqtmathtexttools.cpp +++ b/lib/jkqtmathtext/jkqtmathtexttools.cpp @@ -325,6 +325,87 @@ QString JKQTMathTextFontEncoding2String(JKQTMathTextFontEncoding e) return "???"; } + + +QString JKQTMathTextBraceType2String(JKQTMathTextBraceType type) { + switch(type) { + case MTBTAngleBracket: + return "angle_bracket"; + case MTBTSquareBracket: + return "square_bracket"; + case MTBTCeilBracket: + return "ceil_bracket"; + case MTBTCurlyBracket: + return "curly_bracket"; + case MTBTDoubleLine: + return "double_line"; + case MTBTFloorBracket: + return "floor_bracket"; + case MTBTParenthesis: + return "parenhesis"; + case MTBTSingleLine: + return "single_line"; + case MTBTAny: + return "any"; + case MTBTNone: + return "none"; + } + return "unknown"; +} + +JKQTMathTextBraceType TokenName2JKQTMathTextBraceType(const QString &tokenName) +{ + if (tokenName=="(" || tokenName==")") return MTBTParenthesis; + if (tokenName=="[" || tokenName=="]") return MTBTSquareBracket; + if (tokenName=="{" || tokenName=="}") return MTBTCurlyBracket; + if (tokenName=="|") return MTBTSingleLine; + if (tokenName=="||" || tokenName=="#") return MTBTDoubleLine; + if (tokenName=="<" || tokenName==">" || tokenName=="langle" || tokenName=="rangle") return MTBTAngleBracket; + if (tokenName=="_" || tokenName=="lfloor" || tokenName=="rfloor") return MTBTFloorBracket; + if (tokenName=="~" || tokenName=="lceil" || tokenName=="rceil") return MTBTCeilBracket; + if (tokenName=="any") return MTBTAny; + if (tokenName=="." || tokenName=="" || tokenName=="none") return MTBTNone; + return MTBTUnknown; +} + +JKQTMathTextBraceType InstructionName2OpeningJKQTMathTextBraceType(const QString &tokenName) +{ + if (tokenName=="{") return MTBTCurlyBracket; + if (tokenName=="|") return MTBTDoubleLine; + if (tokenName=="langle") return MTBTAngleBracket; + if (tokenName=="lfloor") return MTBTFloorBracket; + if (tokenName=="lceil") return MTBTCeilBracket; + return MTBTUnknown; +} + +JKQTMathTextBraceType InstructionName2JKQTMathTextBraceType(const QString &tokenName) +{ + if (tokenName=="{" || tokenName=="}") return MTBTCurlyBracket; + if (tokenName=="|") return MTBTDoubleLine; + if (tokenName=="langle" || tokenName=="rangle") return MTBTAngleBracket; + if (tokenName=="lfloor" || tokenName=="rfloor") return MTBTFloorBracket; + if (tokenName=="lceil" || tokenName=="rceil") return MTBTCeilBracket; + return MTBTUnknown; +} + +bool TokenNameMatchesJKQTMathTextBraceType(const QString &token, JKQTMathTextBraceType type, bool acceptMTBTNone, bool* tokenEqualsNone) +{ + const JKQTMathTextBraceType bt=TokenName2JKQTMathTextBraceType(token); + if (tokenEqualsNone) *tokenEqualsNone=(bt==MTBTNone); + if (type==MTBTAny) return true; + if (acceptMTBTNone && bt==MTBTNone) return true; + return (bt==type); +} + +bool InstructionNameMatchesJKQTMathTextBraceType(const QString &token, JKQTMathTextBraceType type, bool acceptMTBTNone, bool* tokenEqualsNone) +{ + const JKQTMathTextBraceType bt=InstructionName2JKQTMathTextBraceType(token); + if (tokenEqualsNone) *tokenEqualsNone=(bt==MTBTNone); + if (type==MTBTAny) return true; + if (acceptMTBTNone && bt==MTBTNone) return true; + return (bt==type); +} + JKQTMathTextEnvironment::JKQTMathTextEnvironment() { color=QColor("black"); font=MTEroman; @@ -577,3 +658,8 @@ QFont JKQTMathTextGetNonItalic(const QFont &font) return f; } + +bool isPrintableJKQTMathTextBraceType(JKQTMathTextBraceType type) +{ + return (type!=MTBTAny) && (type!=MTBTUnknown); +} diff --git a/lib/jkqtmathtext/jkqtmathtexttools.h b/lib/jkqtmathtext/jkqtmathtexttools.h index 56a2de288b..c311685efb 100644 --- a/lib/jkqtmathtext/jkqtmathtexttools.h +++ b/lib/jkqtmathtext/jkqtmathtexttools.h @@ -137,6 +137,65 @@ enum JKQTMathTextFontEncoding { */ JKQTMATHTEXT_LIB_EXPORT QString JKQTMathTextFontEncoding2String(JKQTMathTextFontEncoding e); +/** \brief types of available braces + * \ingroup jkqtmathtext + */ +enum JKQTMathTextBraceType { + MTBTParenthesis=0, /*!< \brief parantheses () \image html jkqtmathtext/jkqtmathtext_brace_round.png */ + MTBTSquareBracket, /*!< \brief brackets [] \image html jkqtmathtext/jkqtmathtext_brace_rect.png */ + MTBTCurlyBracket, /*!< \brief curly braces {} \image html jkqtmathtext/jkqtmathtext_brace_curly.png */ + MTBTAngleBracket, /*!< \brief angle backets <> \image html jkqtmathtext/jkqtmathtext_brace_tri.png */ + MTBTCeilBracket, /*!< \brief ceil brackets \image html jkqtmathtext/jkqtmathtext_brace_ceil.png */ + MTBTFloorBracket, /*!< \brief floor brackets \image html jkqtmathtext/jkqtmathtext_brace_floor.png */ + MTBTDoubleLine, /*!< \brief double-line brackets (norm ||...||) \image html jkqtmathtext/jkqtmathtext_brace_dblline.png */ + MTBTSingleLine, /*!< \brief single-line brackets (abs |...|) \image html jkqtmathtext/jkqtmathtext_brace_oneline.png */ + MTBTNone, /*!< \brief no bracket */ + MTBTAny, /*!< \brief any bracket, used by JKQTMathText::parseLatexString() */ + MTBTUnknown /*!< \brief an unknown tokenName presented to TokenName2JKQTMathTextBraceType() */ +}; +/** \brief convert a JKQTMathTextBraceType into a string + * \ingroup jkqtmathtext + */ +JKQTMATHTEXT_LIB_EXPORT QString JKQTMathTextBraceType2String(JKQTMathTextBraceType type); +/** \brief convert a string \a tokenName describing a LaTeX Token or Instruction into an opening or closing JKQTMathTextBraceType + * \ingroup jkqtmathtext + */ +JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceType TokenName2JKQTMathTextBraceType(const QString& tokenName); +/** \brief convert a string \a tokenName describing a LaTeX Instruction into an opening JKQTMathTextBraceType + * \ingroup jkqtmathtext + * + * This returns a JKQTMathTextBraceType for which isPrintableJKQTMathTextBraceType() is \c true, or MTBTUnknown, + * never MTBTNone or MTBTAny. + */ +JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceType InstructionName2OpeningJKQTMathTextBraceType(const QString& tokenName); +/** \brief convert a string \a tokenName describing a LaTeX Instruction into an opening or closing JKQTMathTextBraceType + * \ingroup jkqtmathtext + * + * This returns a JKQTMathTextBraceType for which isPrintableJKQTMathTextBraceType() is \c true, or MTBTUnknown, + * never MTBTNone or MTBTAny. + */ +JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceType InstructionName2JKQTMathTextBraceType(const QString& tokenName); +/** \brief return \c true if \a type represents a printable type of brace (including MTBTNone), basically \c true + * for any JKQTMathTextBraceType that can be used as parameter to JKQTMathTextBraceNode + * \ingroup jkqtmathtext + */ +JKQTMATHTEXT_LIB_EXPORT bool isPrintableJKQTMathTextBraceType(JKQTMathTextBraceType type); +/** \brief returns true, if the given token/instruction-Name \a token ("{", "(", ..., "lceil", ".", ...) matches the given \a type (returns true, when \a type == MTBTAny ) + * \ingroup jkqtmathtext + * + * This accepts TokenName2JKQTMathTextBraceType(toke)==MTBTNone for any \a type, iff \a acceptMTBTNone \a ==true. + * + * Optionally returns in \a tokenEqualsNone whether \a token was encoding for MTBTNone . + */ +JKQTMATHTEXT_LIB_EXPORT bool TokenNameMatchesJKQTMathTextBraceType(const QString &token, JKQTMathTextBraceType type, bool acceptMTBTNone, bool *tokenEqualsNone=nullptr); +/** \brief returns true, if the given instruction-Name \a token ("|", "{", ..., "lceil", ".", ...) matches the given \a type (returns true, when \a type == MTBTAny ) + * \ingroup jkqtmathtext + * + * This accepts TokenName2JKQTMathTextBraceType(toke)==MTBTNone for any \a type, iff \a acceptMTBTNone \a ==true. + * + * Optionally returns in \a tokenEqualsNone whether \a token was encoding for MTBTNone . + */ +JKQTMATHTEXT_LIB_EXPORT bool InstructionNameMatchesJKQTMathTextBraceType(const QString &token, JKQTMathTextBraceType type, bool acceptMTBTNone, bool *tokenEqualsNone=nullptr); /** \brief the available logical fonts (default is MTEroman) * \ingroup jkqtmathtext diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.cpp b/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.cpp index 2a465d91f3..8992983ec7 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.cpp +++ b/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.cpp @@ -36,48 +36,11 @@ -QString JKQTMathTextBraceNode::BraceType2String(BraceType type) { - switch(type) { - case MTBTAngleBracket: - return "angle_bracket"; - case MTBTSquareBracket: - return "square_bracket"; - case MTBTCeilBracket: - return "ceil_bracket"; - case MTBTCurlyBracket: - return "curly_bracket"; - case MTBTDoubleLine: - return "double_line"; - case MTBTFloorBracket: - return "floor_bracket"; - case MTBTParenthesis: - return "parenhesis"; - case MTBTSingleLine: - return "single_line"; - } - return "unknown"; -} - -JKQTMathTextBraceNode::BraceType JKQTMathTextBraceNode::TokenNameString2TokenType(const QString &type) -{ - if (type=="(" || type==")") return MTBTParenthesis; - if (type=="[" || type=="]") return MTBTSquareBracket; - if (type=="{" || type=="}") return MTBTCurlyBracket; - if (type=="|") return MTBTSingleLine; - if (type=="||" || type=="#") return MTBTDoubleLine; - if (type=="<" || type==">" || type=="langle" || type=="rangle") return MTBTAngleBracket; - if (type=="_" || type=="lfloor" || type=="rfloor") return MTBTFloorBracket; - if (type=="~" || type=="lceil" || type=="rceil") return MTBTCeilBracket; - return MTBTNone; -} - -JKQTMathTextBraceNode::JKQTMathTextBraceNode(JKQTMathText* _parent, JKQTMathTextBraceNode::BraceType openbrace, JKQTMathTextBraceNode::BraceType closebrace, JKQTMathTextNode* child, bool showOpeningBrace, bool showClosingBrace): +JKQTMathTextBraceNode::JKQTMathTextBraceNode(JKQTMathText* _parent, JKQTMathTextBraceType openbrace, JKQTMathTextBraceType closebrace, JKQTMathTextNode* child): JKQTMathTextSingleChildNode(child, _parent) { this->openbrace=openbrace; this->closebrace=closebrace; - this->showClosingBrace=showClosingBrace; - this->showOpeningBrace=showOpeningBrace; } @@ -116,8 +79,8 @@ void JKQTMathTextBraceNode::getSizeInternalAndBrace(QPainter &painter, JKQTMathT bracewidth=bracewidth/parentMathText->getBraceShrinkFactor(); - if (showOpeningBrace) width+=bracewidth; - if (showClosingBrace) width+=bracewidth; + if (openbrace!=MTBTNone && openbrace!=MTBTAny) width+=bracewidth; + if (closebrace!=MTBTNone && closebrace!=MTBTAny) width+=bracewidth; } double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* /*prevNodeSize*/) { @@ -143,7 +106,8 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa painter.setPen(p); const double paren_fraction=0.85; const double brace_fraction=0.65; - if (showOpeningBrace) { + { + bool showOpeningBrace=true; const double xbrace1=xnew+lw; const double xbrace2=qMin(xnew+paren_fraction*bracewidth, xnew+bracewidth-lw/2.0); const double xbrace2s=qMin(xnew+brace_fraction*bracewidth, xnew+bracewidth-lw/2.0); @@ -154,7 +118,7 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.moveTo(xbrace2, y1); path.cubicTo(xbrace1, (y1+y2)/2.0+fabs(y1-y2)/6.0, xbrace1, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xbrace2, y2); painter.drawPath(path); - } else if (openbrace==JKQTMathTextBraceNode::MTBTSquareBracket) { + } else if (openbrace==MTBTSquareBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -163,14 +127,14 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace1, y2); path.lineTo(xbrace2s, y2); painter.drawPath(path); - } else if (openbrace==JKQTMathTextBraceNode::MTBTCurlyBracket) { + } else if (openbrace==MTBTCurlyBracket) { QPainterPath path=JKQTMathTextMakeHBracePath(0,0,nodeOverallHeight, bracewidth*brace_fraction); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.translate((xbrace1+xbrace2)/2.0, y-nodeBaselineHeight+nodeOverallHeight/2.0); painter.rotate(90); painter.drawPath(path); - } else if (openbrace==JKQTMathTextBraceNode::MTBTFloorBracket) { + } else if (openbrace==MTBTFloorBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -178,7 +142,7 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace1, y1); path.lineTo(xbrace1, y2); painter.drawPath(path); - } else if (openbrace==JKQTMathTextBraceNode::MTBTCeilBracket) { + } else if (openbrace==MTBTCeilBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -186,19 +150,19 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace1, y2); path.lineTo(xbrace2s, y2); painter.drawPath(path); - } else if (openbrace==JKQTMathTextBraceNode::MTBTSingleLine) { + } else if (openbrace==MTBTSingleLine) { const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; const QLineF l(xbrace1, y1, xbrace1, y2); if (l.length()>0) painter.drawLine(l); - } else if (openbrace==JKQTMathTextBraceNode::MTBTDoubleLine) { + } else if (openbrace==MTBTDoubleLine) { const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; const QLineF l(xbrace1, y1, xbrace1, y2); if (l.length()>0) painter.drawLine(l); const QLineF l2(xbrace1+1.5*lw, y1, xbrace1+1.5*lw, y2); if (l2.length()>0) painter.drawLine(l2); - } else if (openbrace==JKQTMathTextBraceNode::MTBTAngleBracket) { + } else if (openbrace==MTBTAngleBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -206,27 +170,32 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace1, (y2+y1)/2.0); path.lineTo(xbrace2, y2); painter.drawPath(path); + } else { + showOpeningBrace=false; + } + if (showOpeningBrace) { + xnew=xnew+bracewidth; } - xnew=xnew+bracewidth; } painter.setPen(pold); xnew= child->draw(painter, xnew, y, currentEv); - if (showClosingBrace) { + { + bool showClosingBrace=true; const double xbrace1=qMax(xnew+bracewidth-paren_fraction*bracewidth, xnew+lw/2.0); const double xbrace1s=qMax(xnew+bracewidth-brace_fraction*bracewidth, xnew+lw/2.0); const double xbrace2=xnew+bracewidth-lw; painter.setPen(p); - if (closebrace==JKQTMathTextBraceNode::MTBTParenthesis) { + if (closebrace==MTBTParenthesis) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; path.moveTo(xbrace1, y1); path.cubicTo(xbrace2, (y1+y2)/2.0+fabs(y1-y2)/6.0, xbrace2, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xbrace1, y2); painter.drawPath(path); - } else if (closebrace==JKQTMathTextBraceNode::MTBTSquareBracket) { + } else if (closebrace==MTBTSquareBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -235,14 +204,14 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace2, y2); path.lineTo(xbrace1s, y2); painter.drawPath(path); - } else if (closebrace==JKQTMathTextBraceNode::MTBTCurlyBracket) { + } else if (closebrace==MTBTCurlyBracket) { QPainterPath path=JKQTMathTextMakeHBracePath(0,0,nodeOverallHeight, bracewidth*brace_fraction); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.translate((xbrace1+xbrace2)/2.0, y-nodeBaselineHeight+nodeOverallHeight/2.0); painter.rotate(270); painter.drawPath(path); - } else if (closebrace==JKQTMathTextBraceNode::MTBTFloorBracket) { + } else if (closebrace==MTBTFloorBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -250,7 +219,7 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace2, y1); path.lineTo(xbrace2, y2); painter.drawPath(path); - } else if (closebrace==JKQTMathTextBraceNode::MTBTCeilBracket) { + } else if (closebrace==MTBTCeilBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -258,19 +227,19 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace2, y2); path.lineTo(xbrace1s, y2); painter.drawPath(path); - } else if (closebrace==JKQTMathTextBraceNode::MTBTSingleLine) { + } else if (closebrace==MTBTSingleLine) { const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; const QLineF l(xbrace2, y1, xbrace2, y2); if (l.length()>0) painter.drawLine(l); - } else if (closebrace==JKQTMathTextBraceNode::MTBTDoubleLine) { + } else if (closebrace==MTBTDoubleLine) { const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; const QLineF l(xbrace2, y1, xbrace2, y2); if (l.length()>0) painter.drawLine(l); const QLineF l2(xbrace2-1.5*lw, y1, xbrace2-1.5*lw, y2); if (l2.length()>0) painter.drawLine(l2); - } else if (closebrace==JKQTMathTextBraceNode::MTBTAngleBracket) { + } else if (closebrace==MTBTAngleBracket) { QPainterPath path; const double y1=y+(nodeOverallHeight-nodeBaselineHeight); const double y2=y-nodeBaselineHeight; @@ -278,9 +247,13 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa path.lineTo(xbrace2, (y2+y1)/2.0); path.lineTo(xbrace1, y2); painter.drawPath(path); + } else { + showClosingBrace=false; } painter.setPen(pold); - xnew=xnew+bracewidth; + if (showClosingBrace) { + xnew=xnew+bracewidth; + } } //qDebug()<<" ==> "<openbrace; } -JKQTMathTextBraceNode::BraceType JKQTMathTextBraceNode::getClosebrace() const { +JKQTMathTextBraceType JKQTMathTextBraceNode::getClosebrace() const { return this->closebrace; } -bool JKQTMathTextBraceNode::getShowClosingBrace() const { - return this->showClosingBrace; -} - -bool JKQTMathTextBraceNode::getShowOpeningBrace() const -{ - return showOpeningBrace; -} - void JKQTMathTextBraceNode::getBraceSize(QPainter &/*painter*/, JKQTMathTextEnvironment ev, double /*baselineHeight*/, double overallHeight, double &bracewidth, double &braceheight) const { const double lw=qMax(0.25,ceil(ev.fontSize/12.0)); braceheight=overallHeight*parentMathText->getBraceFactor(); bracewidth=0.6*pow(braceheight, 0.6); - if (openbrace==JKQTMathTextBraceNode::MTBTCurlyBracket || closebrace==JKQTMathTextBraceNode::MTBTCurlyBracket) bracewidth=qMax(bracewidth, lw*3.5); + if (openbrace==MTBTCurlyBracket || closebrace==MTBTCurlyBracket) bracewidth=qMax(bracewidth, lw*3.5); } diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.h b/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.h index e952854133..b66fb45106 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.h +++ b/lib/jkqtmathtext/nodes/jkqtmathtextbracenode.h @@ -36,26 +36,16 @@ class JKQTMathText; // forward * \ingroup jkqtmathtext_items * * \image html jkqtmathtext/jkqtmathtext_bracenode_geo.png - */ + * + * This node supports the brace-types encoded by JKQTMathTextBraceType: + * \copydetails JKQTMathTextBraceType + * + * In addition it is possible to switch the opening and the closing braces independently on and off. + */ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceNode: public JKQTMathTextSingleChildNode { public: - /** \brief types of available braces */ - enum BraceType { - MTBTParenthesis, /*!< \brief parantheses () \image html jkqtmathtext/jkqtmathtext_brace_round.png */ - MTBTSquareBracket, /*!< \brief brackets [] \image html jkqtmathtext/jkqtmathtext_brace_rect.png */ - MTBTCurlyBracket, /*!< \brief curly braces {} \image html jkqtmathtext/jkqtmathtext_brace_curly.png */ - MTBTAngleBracket, /*!< \brief angle backets <> \image html jkqtmathtext/jkqtmathtext_brace_tri.png */ - MTBTCeilBracket, /*!< \brief ceil brackets \image html jkqtmathtext/jkqtmathtext_brace_ceil.png */ - MTBTFloorBracket, /*!< \brief floor brackets \image html jkqtmathtext/jkqtmathtext_brace_floor.png */ - MTBTDoubleLine, /*!< \brief double-line brackets (norm ||...||) \image html jkqtmathtext/jkqtmathtext_brace_dblline.png */ - MTBTSingleLine, /*!< \brief single-line brackets (abs |...|) \image html jkqtmathtext/jkqtmathtext_brace_oneline.png */ - MTBTNone /*!< \brief no bracket */ - }; - /** \brief convert a BraceType into a string */ - static QString BraceType2String(BraceType type); - /** \brief convert a string describing a LaTeX Token into a BraceType */ - static BraceType TokenNameString2TokenType(const QString& type); - JKQTMathTextBraceNode(JKQTMathText* parent, BraceType openbrace, BraceType closebrace, JKQTMathTextNode* child, bool showOpeningBrace=true, bool showClosingBrace=true); + + JKQTMathTextBraceNode(JKQTMathText* parent, JKQTMathTextBraceType openbrace, JKQTMathTextBraceType closebrace, JKQTMathTextNode* child); virtual ~JKQTMathTextBraceNode() override; /** \copydoc JKQTMathTextNode::draw() */ virtual double draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override; @@ -64,13 +54,9 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceNode: public JKQTMathTextSingleCh /** \copydoc JKQTMathTextNode::getTypeName() */ virtual QString getTypeName() const override; /** \copydoc openbrace */ - BraceType getOpenbrace() const; + JKQTMathTextBraceType getOpenbrace() const; /** \copydoc closebrace */ - BraceType getClosebrace() const; - /** \copydoc showRightBrace */ - bool getShowClosingBrace() const; - /** \copydoc showOpeningBrace */ - bool getShowOpeningBrace() const; + JKQTMathTextBraceType getClosebrace() const; protected: /** \copydoc JKQTMathTextNode::getSizeInternal() * @@ -80,13 +66,9 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceNode: public JKQTMathTextSingleCh /** calculates the size of this node (also returned by getSizeInternal() ) and of the brace */ void getSizeInternalAndBrace(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, double& bracewidth, double&braceheight, const JKQTMathTextNodeSize* prevNodeSize=nullptr); /**\brief opening brace */ - BraceType openbrace; + JKQTMathTextBraceType openbrace; /**\brief closing brace */ - BraceType closebrace; - /**\brief if \c true, the closing (right hand side) brace is drawn */ - bool showClosingBrace; - /**\brief if \c true, the opening (left hand side) brace is drawn */ - bool showOpeningBrace; + JKQTMathTextBraceType closebrace; /** \brief calculate the width of the brace */ void getBraceSize(QPainter& painter, JKQTMathTextEnvironment currentEv, double baselineHeight, double overallHeight, double& bracewidth, double& braceheight) const; }; diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp index 5bd6fe1e39..fbed241144 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp +++ b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.cpp @@ -50,10 +50,7 @@ JKQTMathTextListNode::JKQTMathTextListNode(JKQTMathText* _parent): } JKQTMathTextListNode::~JKQTMathTextListNode() { - for (int i=0; i JKQTMathTextListNode::getNodes() const { return this->nodes; } +int JKQTMathTextListNode::count() const +{ + return nodes.size(); +} + +int JKQTMathTextListNode::size() const +{ + return nodes.size(); +} + +void JKQTMathTextListNode::clearChildren(bool deleteChildren) +{ + if (deleteChildren) { + for (int i=0; icount()==1) { + // if there was only a single node: simplify the syntax tree, by removing the outer list node + JKQTMathTextNode* ret= nl->child(0); + nl->clearChildren(false); + delete nl; + return ret; + } + return nl; +} + diff --git a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h index cc81b7af10..57ffb00cc4 100644 --- a/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h +++ b/lib/jkqtmathtext/nodes/jkqtmathtextlistnode.h @@ -51,6 +51,18 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextListNode: public JKQTMathTextNode { virtual void setDrawBoxes(bool draw) override; /** \copydoc nodes */ QList getNodes() const; + /** \brief return number of children */ + int count() const; + /** \brief return number of children */ + int size() const; + /** \brief clear all children, deleting them if \a deleteChildren==true */ + void clearChildren(bool deleteChildren=true); + /** \brief return i-th child node */ + JKQTMathTextNode* child(int i); + /** \brief return i-th child node */ + const JKQTMathTextNode* child(int i) const; + /** \brief simplifies the given list-node, i.e. if it contains one child only, the child is returned and the list node destroyed, otherwise the list node \a nl is returned */ + static JKQTMathTextNode* simplyfyListNode(JKQTMathTextListNode* nl); protected: /** \copydoc JKQTMathTextNode::getSizeInternal() */ virtual void getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* prevNodeSize=nullptr) override;