JKQTMathText:

- NEW: JKQTMathTextVerticalListNode allows to typeset a vertical list of lines
- NEW: added \substack[lcr]{...\\...}, \lsubstack{...\\...}, \rsubstack{...\\...} instructions
This commit is contained in:
jkriege2 2022-07-30 23:30:47 +02:00
parent edd7784d47
commit 326ba7313c
20 changed files with 546 additions and 49 deletions

View File

@ -46,7 +46,6 @@ This page lists several todos and wishes for future version of JKQTPlotter
<li>explore options to make font-environment-modifying commands avails, like "{blacktext\\color{red}redtext}", today only commands like "\\textcolor{red}{redtext}" work</li> <li>explore options to make font-environment-modifying commands avails, like "{blacktext\\color{red}redtext}", today only commands like "\\textcolor{red}{redtext}" work</li>
<li>maybe: add support for text with linebreaks by adding a JKQTMathTextVerticalListNode in addition to JKQTMathTextListNode</li> <li>maybe: add support for text with linebreaks by adding a JKQTMathTextVerticalListNode in addition to JKQTMathTextListNode</li>
<li>maybe: add tool programs to auto-generate some example images</li> <li>maybe: add tool programs to auto-generate some example images</li>
<li>add support for \\substack command below \\sum etc.</li>
<li>improve support for array-environment with limited support for formatting string like l|r|c and maybe add support for \\hline command, possibly also \\cellcolor etz.</li> <li>improve support for array-environment with limited support for formatting string like l|r|c and maybe add support for \\hline command, possibly also \\cellcolor etz.</li>
<li></li> <li></li>
</ul></li> </ul></li>

View File

@ -68,6 +68,8 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>NEW: added functions to set the font-size in pixels (as alternative to the existing functions that set them in points), implements request <a href="https://github.com/jkriege2/JKQtPlotter/issues/76">#76</a> from <a href="https://github.com/igormironchik">user:igormironchik</a> </li> <li>NEW: added functions to set the font-size in pixels (as alternative to the existing functions that set them in points), implements request <a href="https://github.com/jkriege2/JKQtPlotter/issues/76">#76</a> from <a href="https://github.com/igormironchik">user:igormironchik</a> </li>
<li>NEW: added \c \\userfont{SystemFontName}{Text} instruction</li> <li>NEW: added \c \\userfont{SystemFontName}{Text} instruction</li>
<li>NEW: added \c \\unicode{HEX} and \c \\utfeight{HEX} instruction to draw unicide characters by code</li> <li>NEW: added \c \\unicode{HEX} and \c \\utfeight{HEX} instruction to draw unicide characters by code</li>
<li>NEW: JKQTMathTextVerticalListNode allows to typeset a vertical list of lines</li>
<li>NEW: added \c \\substack[lcr]{...\\\\...} , \c \\lsubstack{...\\\\...} , \c \\rsubstack{...\\\\...} instructions</li>
</ul></li> </ul></li>
</ul> </ul>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -178,28 +178,22 @@ TestForm::TestForm(QWidget *parent) :
ui->cmbTestset->addItem("text/math: sub-, superscript test", "text: r^{1234}_{321} r_{321}^{1234} -- math: $r^{1234}_{321} r_{321}^{1234} -- \\kappa^2 -- \\kappa_2 -- \\kappa_2^2$"); ui->cmbTestset->addItem("text/math: sub-, superscript test", "text: r^{1234}_{321} r_{321}^{1234} -- math: $r^{1234}_{321} r_{321}^{1234} -- \\kappa^2 -- \\kappa_2 -- \\kappa_2^2$");
ui->cmbTestset->addItem("text/math: super-, subscript test", "text: r^{123}_{4321} r_{4321}^{123} -- math: $r^{123}_{4321} r_{4321}^{123} -- \\kappa^2 -- \\kappa_2 -- \\kappa_2^2$"); ui->cmbTestset->addItem("text/math: super-, subscript test", "text: r^{123}_{4321} r_{4321}^{123} -- math: $r^{123}_{4321} r_{4321}^{123} -- \\kappa^2 -- \\kappa_2 -- \\kappa_2^2$");
//ui->cmbTestset->addItem("", ""); //ui->cmbTestset->addItem("", "");
ui->cmbTestset->addItem("math 1", "$f(x)=\\int_{-\\infty}^xe^{-t^2}\\;\\mathrm{d}t$"); ui->cmbTestset->addItem("math: nested sqrt", "$\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+x}}}}}}$");
ui->cmbTestset->addItem("math 2", "$\\sum_{i=1}^\\infty\\frac{-e^{i\\pi}}{2^n}$"); ui->cmbTestset->addItem("math: nested cbrt", "$\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+x}}}}}}$");
ui->cmbTestset->addItem("math 3", "$\\mbox{det} \\begin{pmatrix} 1 & x_1 & \\ldots & x_1^{n-1} \\\\ 1 & x_2 & \\ldots & x_2^{n-1} \\\\ \\vdots & \\vdots & \\ddots & \\vdots \\\\ 1 & x_n & \\ldots & x_n^{n-1} \\end{pmatrix} = \\prod_{1 \\leq i < j \\leq n} (x_j - x_i) $"); ui->cmbTestset->addItem("math: nested sqrt, high contents", "$\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+x}}}}}}$");
ui->cmbTestset->addItem("math: nestes sqrt", "$\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+x}}}}}}$"); ui->cmbTestset->addItem("math: frac+stackrel", "$\\left(\\stackrel{p}{2}\\right)=x^2y^{p-2}-\\frac{1}{1-x}\\frac{1}{1-x^2}$");
ui->cmbTestset->addItem("math: nestes cbrt", "$\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+x}}}}}}$"); ui->cmbTestset->addItem("math: nested frac", "$a_0+\\frac{1}{a_1+\\frac{1}{a_2+\\frac{1}{a_3+\\frac{1}{a_4}}}}$");
ui->cmbTestset->addItem("math: nestes sqrt, high contents", "$\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+x}}}}}}$"); ui->cmbTestset->addItem("math: partial derivatives", "$\\left(\\frac{\\partial^2}{\\partial x^2}+\\frac{\\partial^2}{\\partial y^2}\\right)\\left|\\varphi(x+\\mathrm{i}y)\\right|^2=0$");
ui->cmbTestset->addItem("math 5 (frac+stackrel)", "$\\left(\\stackrel{p}{2}\\right)=x^2y^{p-2}-\\frac{1}{1-x}\\frac{1}{1-x^2}$"); ui->cmbTestset->addItem("math: powers of powers", "$2^{2^{2^{x}}}$");
ui->cmbTestset->addItem("math 6 (nested frac)", "$a_0+\\frac{1}{a_1+\\frac{1}{a_2+\\frac{1}{a_3+\\frac{1}{a_4}}}}$"); ui->cmbTestset->addItem("math: double-integral", "$\\iint_Df(x,y)\\;\\mathrm{d}x\\;\\mathrm{d}y$");
ui->cmbTestset->addItem("math 7 (partial derivatives)", "$\\left(\\frac{\\partial^2}{\\partial x^2}+\\frac{\\partial^2}{\\partial y^2}\\right)\\left|\\varphi(x+\\mathrm{i}y)\\right|^2=0$"); ui->cmbTestset->addItem("math: overbrace+overbracket", "$\\overbrace{x+x+...+x}{k\\ \\mathrm{times}}\\ \\ \\ \\overbracket{x+x+...+x}{k\\ \\mathrm{times}}$");
ui->cmbTestset->addItem("math 8 (powers of powers)", "$2^{2^{2^{x}}}$"); ui->cmbTestset->addItem("math: underbrace+underbracket", "$\\underbrace{x+x+...+x}{k\\ \\mathrm{times}}\\ \\ \\ \\underbracket{x+x+...+x}{k\\ \\mathrm{times}}$");
ui->cmbTestset->addItem("math 9 (integral)", "$\\iint_Df(x,y)\\;\\mathrm{d}x\\;\\mathrm{d}y$"); ui->cmbTestset->addItem("math: under/overbrace+under/overbracket", "$\\underbrace{\\overbrace{x+x+...+x}{k\\ \\mathrm{times}} \\overbrace{x+x+...+x}{k\\ \\mathrm{times}}}{2k\\ \\mathrm{times}}\\ \\ \\ \\underbracket{\\overbracket{x+x+...+x}{k\\ \\mathrm{times}} \\overbracket{x+x+...+x}{k\\ \\mathrm{times}}}{2k\\ \\mathrm{times}}$");
ui->cmbTestset->addItem("math 10 (overbrace+overbracket)", "$\\overbrace{x+x+...+x}{k\\ \\mathrm{times}}\\ \\ \\ \\overbracket{x+x+...+x}{k\\ \\mathrm{times}}$"); ui->cmbTestset->addItem("math: apostrophy/prime derivatives", "$y_1'\\ y_2''\\ y_3'''\\ \\ \\ --\\ \\ \\ y_1^\\prime\\ y_2^\\dprime\\ y_3^\\trprime\\ \\ \\ --\\ \\ \\ y_1^\\prime\\ y_2^{\\prime\\prime}\\ y_3^{\\prime\\prime\\prime}$");
ui->cmbTestset->addItem("math 11 (underbrace+underbracket)", "$\\underbrace{x+x+...+x}{k\\ \\mathrm{times}}\\ \\ \\ \\underbracket{x+x+...+x}{k\\ \\mathrm{times}}$"); ui->cmbTestset->addItem("math: cases", "$f(x)=\\begin{cases} 1/3 & \\mathrm{if}\\ 0\\leq x\\leq1 \\\\ 2/3 & \\mathrm{if}\\ 3\\leq x\\leq4 \\\\0 & \\mathrm{elsewhere} \\end{cases}$");
ui->cmbTestset->addItem("math 12 (under/overbrace+under/overbracket)", "$\\underbrace{\\overbrace{x+x+...+x}{k\\ \\mathrm{times}} \\overbrace{x+x+...+x}{k\\ \\mathrm{times}}}{2k\\ \\mathrm{times}}\\ \\ \\ \\underbracket{\\overbracket{x+x+...+x}{k\\ \\mathrm{times}} \\overbracket{x+x+...+x}{k\\ \\mathrm{times}}}{2k\\ \\mathrm{times}}$"); ui->cmbTestset->addItem("math: overset", "$X \\overset{=}{def} Y$\\ \\ \\ \\ \\ $X \\overset{=}{!} Y$\\ \\ \\ \\ \\ $X \\overset{\\rightarrow}{f} Y$\\ \\ \\ \\ \\ $\\frac{f(x+\\Delta x)-f(x)}{\\Delta x}\\overset{\\longrightarrow}{\\Delta x\\to 0}f'(x)$");
ui->cmbTestset->addItem("math 13", "$y_1''\\ \\ \\ y_2'''$"); ui->cmbTestset->addItem("math: underset", "$X \\underset{=}{\\text{def (5)}} Y$\\ \\ \\ \\ \\ $X \\underset{\\rightarrow}{f} Y$\\ \\ \\ \\ \\ $\\frac{f(x+\\Delta x)-f(x)}{\\Delta x}\\underset{\\longrightarrow}{\\Delta x\\to 0}f'(x)$");
ui->cmbTestset->addItem("math 14", "$f(x)=\\begin{cases} 1/3 & \\mathrm{if}\\ 0\\leq x\\leq1 \\\\ 2/3 & \\mathrm{if}\\ 3\\leq x\\leq4 \\\\0 & \\mathrm{elsewhere} \\end{cases}$"); ui->cmbTestset->addItem("math: substack", "substack: $\\substack{i=0\\\\\\sin(x)\\equiv\\pi\\\\a=a\\\\a=b}$\\ \\ \\ substack[l]: $\\substack[l]{i=0\\\\\\sin(x)\\equiv\\pi\\\\a=a\\\\a=b}$\\ \\ \\ lsubstack: $\\lsubstack{i=0\\\\\\sin(x)\\equiv\\pi\\\\a=a\\\\a=b}$\\ \\ \\ rsubstack: $\\rsubstack{i=0\\\\\\sin(x)\\equiv\\pi\\\\a=a\\\\a=b}$\\ \\ \\ comma: $\\sum\\limits_{0\\leq i\\leq 10, -5\\leq j\\leq100}f_{i,j}$\\ \\ \\ substack: $\\sum\\limits_\\substack{0\\leq i\\leq 10\\\\ -5\\leq j\\leq100}f_{i,j}$\\ \\ \\ rsubstack: $\\sum\\limits_\\rsubstack{0\\leq i\\leq 10\\\\ -5\\leq j\\leq100}f_{i,j}$");
ui->cmbTestset->addItem("math 15", "$\\Re(z) =\\frac{n\\pi \\dfrac{\\theta +\\psi}{2}}{\\left(\\dfrac{\\theta +\\psi}{2}\\right)^2 + \\left( \\dfrac{1}{2}\\log \\left\\lvert\\dfrac{B}{A}\\right\\rvert\\right)^2}.$");
ui->cmbTestset->addItem("math 16", "$\\sum_{m=1}^\\infty\\sum_{n=1}^\\infty\\frac{m^2\\,n}{3^m\\left(m\\,3^n+n\\,3^m\\right)}$");
ui->cmbTestset->addItem("math 17", "$\\phi_n(\\kappa) =\\frac{1}{4\\pi^2\\kappa^2} \\int_0^\\infty\\frac{\\sin(\\kappa R)}{\\kappa R}\\frac{\\partial}{\\partial R}\\left[R^2\\frac{\\partial D_n(R)}{\\partial R}\\right]\\,dR$");
ui->cmbTestset->addItem("math 18", "${}_pF_q(a_1,\\dots,a_p;c_1,\\dots,c_q;z)= \\sum_{n=0}^\\infty\\frac{(a_1)_n\\cdots(a_p)_n}{(c_1)_n\\cdots(c_q)_n}\\frac{z^n}{n!}$");
ui->cmbTestset->addItem("math 19 (overset)", "$X \\overset{=}{def} Y$\\ \\ \\ \\ \\ $X \\overset{=}{!} Y$\\ \\ \\ \\ \\ $X \\overset{\\rightarrow}{f} Y$\\ \\ \\ \\ \\ $\\frac{f(x+\\Delta x)-f(x)}{\\Delta x}\\overset{\\longrightarrow}{\\Delta x\\to 0}f'(x)$");
ui->cmbTestset->addItem("math 20 (underset)", "$X \\underset{=}{\\text{def (5)}} Y$\\ \\ \\ \\ \\ $X \\underset{\\rightarrow}{f} Y$\\ \\ \\ \\ \\ $\\frac{f(x+\\Delta x)-f(x)}{\\Delta x}\\underset{\\longrightarrow}{\\Delta x\\to 0}f'(x)$");
ui->cmbTestset->addItem("math: Jacobi Matrix and VarCov matrix", "$J_{ij}= \\left.\\frac{\\partial f(x,\\vec{p})}{\\partial p_i}\\right|_{\\vec{p},x=x_j}\\ \\ \\ \\ \\ \\mat{C}=\\left(\\mat{J}^\\mathrm{T}\\ J\\right)^{-1}\\ \\ \\ \\ \\ test: \\left|\\frac{\\partial f(x,\\vec{p})}{\\partial p_i}\\right|_{\\vec{p},x=x_j}^2$"); ui->cmbTestset->addItem("math: Jacobi Matrix and VarCov matrix", "$J_{ij}= \\left.\\frac{\\partial f(x,\\vec{p})}{\\partial p_i}\\right|_{\\vec{p},x=x_j}\\ \\ \\ \\ \\ \\mat{C}=\\left(\\mat{J}^\\mathrm{T}\\ J\\right)^{-1}\\ \\ \\ \\ \\ test: \\left|\\frac{\\partial f(x,\\vec{p})}{\\partial p_i}\\right|_{\\vec{p},x=x_j}^2$");
ui->cmbTestset->addItem("math: operator test (textmode)", "x=0\\ \\ y>0\\ \\ x+y\\ \\ -1\\ \\ x-2\\ \\ x\\cdot y\\ \\ x\\geq 4\\ \\ x~4"); ui->cmbTestset->addItem("math: operator test (textmode)", "x=0\\ \\ y>0\\ \\ x+y\\ \\ -1\\ \\ x-2\\ \\ x\\cdot y\\ \\ x\\geq 4\\ \\ x~4");
ui->cmbTestset->addItem("math: operator test (mathmode)", "$x=0\\ \\ y>0\\ \\ x+y\\ \\ -1\\ \\ x-2\\ \\ x\\cdot y\\ \\ x\\geq 4\\ \\ x~4$"); ui->cmbTestset->addItem("math: operator test (mathmode)", "$x=0\\ \\ y>0\\ \\ x+y\\ \\ -1\\ \\ x-2\\ \\ x\\cdot y\\ \\ x\\geq 4\\ \\ x~4$");
@ -229,6 +223,13 @@ TestForm::TestForm(QWidget *parent) :
ui->cmbTestset->addItem("math: Fokker-Planck Equation", "$\\frac{\\partial}{\\partial t}P(y,t)=-\\frac{\\partial}{\\partial y}\\left[ A(y,t)P(y,t)\\right] +\\frac{\\Gamma}{2}\\frac{\\partial^2}{\\partial y^2}\\left[ P(y,t)\\right]$"); ui->cmbTestset->addItem("math: Fokker-Planck Equation", "$\\frac{\\partial}{\\partial t}P(y,t)=-\\frac{\\partial}{\\partial y}\\left[ A(y,t)P(y,t)\\right] +\\frac{\\Gamma}{2}\\frac{\\partial^2}{\\partial y^2}\\left[ P(y,t)\\right]$");
ui->cmbTestset->addItem("math: Hamilton Equations of motion", "$\\mathcal{H}(\\mathbf{q},\\mathbf{p})=\\frac{\\mathbf{p}^2}{2\\,m}+V(\\mathbf{q})\\ \\ \\ \\text{and}\\ \\ \\ \\dot{q}_k =\\frac{p_k}{m}\\ ,\\ \\dot{p}_k = - \\frac{\\partial V}{\\partial q_k}$"); ui->cmbTestset->addItem("math: Hamilton Equations of motion", "$\\mathcal{H}(\\mathbf{q},\\mathbf{p})=\\frac{\\mathbf{p}^2}{2\\,m}+V(\\mathbf{q})\\ \\ \\ \\text{and}\\ \\ \\ \\dot{q}_k =\\frac{p_k}{m}\\ ,\\ \\dot{p}_k = - \\frac{\\partial V}{\\partial q_k}$");
ui->cmbTestset->addItem("math: Gaussian Distrubution", "$f(x | \\mu,\\sigma^2)=\\frac{1}{\\sqrt{2\\pi\\sigma^2}}\\operatorname{exp}\\left(-\\frac{(x-\\mu)^2}{2\\sigma^2}\\right)=\\frac{1}{\\sqrt{2\\pi\\sigma^2}} e^{-\\frac{(x-\\mu)^2}{2\\sigma^2}}\\quad -\\infty<x<\\infty$"); ui->cmbTestset->addItem("math: Gaussian Distrubution", "$f(x | \\mu,\\sigma^2)=\\frac{1}{\\sqrt{2\\pi\\sigma^2}}\\operatorname{exp}\\left(-\\frac{(x-\\mu)^2}{2\\sigma^2}\\right)=\\frac{1}{\\sqrt{2\\pi\\sigma^2}} e^{-\\frac{(x-\\mu)^2}{2\\sigma^2}}\\quad -\\infty<x<\\infty$");
ui->cmbTestset->addItem("math 1", "$f(x)=\\int_{-\\infty}^xe^{-t^2}\\;\\mathrm{d}t$");
ui->cmbTestset->addItem("math 2", "$\\sum_{i=1}^\\infty\\frac{-e^{i\\pi}}{2^n}$");
ui->cmbTestset->addItem("math 3", "$\\mbox{det} \\begin{pmatrix} 1 & x_1 & \\ldots & x_1^{n-1} \\\\ 1 & x_2 & \\ldots & x_2^{n-1} \\\\ \\vdots & \\vdots & \\ddots & \\vdots \\\\ 1 & x_n & \\ldots & x_n^{n-1} \\end{pmatrix} = \\prod_{1 \\leq i < j \\leq n} (x_j - x_i) $");
ui->cmbTestset->addItem("math 4", "$\\Re(z) =\\frac{n\\pi \\dfrac{\\theta +\\psi}{2}}{\\left(\\dfrac{\\theta +\\psi}{2}\\right)^2 + \\left( \\dfrac{1}{2}\\log \\left\\lvert\\dfrac{B}{A}\\right\\rvert\\right)^2}.$");
ui->cmbTestset->addItem("math 5", "$\\sum_{m=1}^\\infty\\sum_{n=1}^\\infty\\frac{m^2\\,n}{3^m\\left(m\\,3^n+n\\,3^m\\right)}$");
ui->cmbTestset->addItem("math 6", "$\\phi_n(\\kappa) =\\frac{1}{4\\pi^2\\kappa^2} \\int_0^\\infty\\frac{\\sin(\\kappa R)}{\\kappa R}\\frac{\\partial}{\\partial R}\\left[R^2\\frac{\\partial D_n(R)}{\\partial R}\\right]\\,dR$");
ui->cmbTestset->addItem("math 7", "${}_pF_q(a_1,\\dots,a_p;c_1,\\dots,c_q;z)= \\sum_{n=0}^\\infty\\frac{(a_1)_n\\cdots(a_p)_n}{(c_1)_n\\cdots(c_q)_n}\\frac{z^n}{n!}$");
ui->cmbTestset->addItem("User-Editable Text"); ui->cmbTestset->addItem("User-Editable Text");
// //
//ui->cmbTestset->addItem("", "$$"); //ui->cmbTestset->addItem("", "$$");
@ -429,7 +430,8 @@ QTreeWidgetItem *TestForm::createTree(JKQTMathTextNode *node, QTreeWidgetItem* p
JKQTMathTextTextNode* txtN=dynamic_cast<JKQTMathTextTextNode*>(node); JKQTMathTextTextNode* txtN=dynamic_cast<JKQTMathTextTextNode*>(node);
JKQTMathTextWhitespaceNode* spN=dynamic_cast<JKQTMathTextWhitespaceNode*>(node); JKQTMathTextWhitespaceNode* spN=dynamic_cast<JKQTMathTextWhitespaceNode*>(node);
JKQTMathTextSymbolNode* symN=dynamic_cast<JKQTMathTextSymbolNode*>(node); JKQTMathTextSymbolNode* symN=dynamic_cast<JKQTMathTextSymbolNode*>(node);
JKQTMathTextListNode* lstN=dynamic_cast<JKQTMathTextListNode*>(node); JKQTMathTextHorizontalListNode* lstN=dynamic_cast<JKQTMathTextHorizontalListNode*>(node);
JKQTMathTextVerticalListNode* lstNV=dynamic_cast<JKQTMathTextVerticalListNode*>(node);
JKQTMathTextModifiedTextPropsInstructionNode* inst1N=dynamic_cast<JKQTMathTextModifiedTextPropsInstructionNode*>(node); JKQTMathTextModifiedTextPropsInstructionNode* inst1N=dynamic_cast<JKQTMathTextModifiedTextPropsInstructionNode*>(node);
JKQTMathTextBoxInstructionNode* inst1B=dynamic_cast<JKQTMathTextBoxInstructionNode*>(node); JKQTMathTextBoxInstructionNode* inst1B=dynamic_cast<JKQTMathTextBoxInstructionNode*>(node);
JKQTMathTextSimpleInstructionNode* instS=dynamic_cast<JKQTMathTextSimpleInstructionNode*>(node); JKQTMathTextSimpleInstructionNode* instS=dynamic_cast<JKQTMathTextSimpleInstructionNode*>(node);
@ -488,11 +490,17 @@ QTreeWidgetItem *TestForm::createTree(JKQTMathTextNode *node, QTreeWidgetItem* p
name=QString("BoxInstructionNode: \'%1\' (subsuper=%2, params=%3)").arg(inst1B->getInstructionName()).arg(inst1B->isSubSuperscriptAboveBelowNode()).arg(inst1B->getParameters().join("/")); name=QString("BoxInstructionNode: \'%1\' (subsuper=%2, params=%3)").arg(inst1B->getInstructionName()).arg(inst1B->isSubSuperscriptAboveBelowNode()).arg(inst1B->getParameters().join("/"));
if (inst1B->getChild()) ti->addChild(createTree(inst1B->getChild(), ti)); if (inst1B->getChild()) ti->addChild(createTree(inst1B->getChild(), ti));
} else if (lstN) { } else if (lstN) {
name=QString("MTlistNode"); name=QString("HListNode");
QList<JKQTMathTextNode*> list=lstN->getChildren(); QList<JKQTMathTextNode*> list=lstN->getChildren();
for (int i=0; i<list.size(); i++) { for (int i=0; i<list.size(); i++) {
ti->addChild(createTree(list[i], ti)); ti->addChild(createTree(list[i], ti));
} }
} else if (lstNV) {
name=QString("VListNode (align=%1, spacingFactor=%2x, spacingMode=%3, verticalOrientation=%4)").arg(JKQTMathTextHorizontalAlignment2String(lstNV->getAlignment())).arg(lstNV->getLineSpacingFactor()).arg(lstNV->SpacingMode2String(lstNV->getSpacingMode())).arg(JKQTMathTextVerticalOrientation2String(lstNV->getVerticalOrientation()));
QList<JKQTMathTextNode*> list=lstNV->getChildren();
for (int i=0; i<list.size(); i++) {
ti->addChild(createTree(list[i], ti));
}
} else if (symN) { } else if (symN) {
name=QString("MTSymbolNode: \'%1\' (subsuper=%3)").arg(symN->getSymbolName()).arg(symN->isSubSuperscriptAboveBelowNode()); name=QString("MTSymbolNode: \'%1\' (subsuper=%3)").arg(symN->getSymbolName()).arg(symN->isSubSuperscriptAboveBelowNode());
} else if (spN) { } else if (spN) {

View File

@ -1300,6 +1300,13 @@ JKQTMathText::tokenType JKQTMathText::getToken() {
if (currentTokenID>=parseString.size()-1) return currentToken=MTTnone; if (currentTokenID>=parseString.size()-1) return currentToken=MTTnone;
c=parseString[currentTokenID]; c=parseString[currentTokenID];
//---------------------------------------------------------- //----------------------------------------------------------
// recognize linebreak "\\"
if (c=='\\') {
currentTokenName=c; // parse one-symbol instructions like \\, \& ...
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTinstructionNewline;
}
//----------------------------------------------------------
// parsing single-character instruction // parsing single-character instruction
if (SingleCharInstructions.contains(c)) { if (SingleCharInstructions.contains(c)) {
currentTokenName=c; // parse one-symbol instructions like \\, \& ... currentTokenName=c; // parse one-symbol instructions like \\, \& ...
@ -1318,6 +1325,8 @@ JKQTMathText::tokenType JKQTMathText::getToken() {
} }
//std::cout<<"found instruction node '"<<currentTokenName.toStdString()<<"'\n"; //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.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;
return currentToken=MTTinstruction; return currentToken=MTTinstruction;
//---------------------------------------------------------- //----------------------------------------------------------
// check for $ character // check for $ character
@ -1425,7 +1434,7 @@ JKQTMathText::tokenType JKQTMathText::getToken() {
JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, JKQTMathTextBraceType quitOnClosingBrace, const QString& quitOnEnvironmentEnd, bool quitOnClosingBracket) { JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, JKQTMathTextBraceType quitOnClosingBrace, const QString& quitOnEnvironmentEnd, bool quitOnClosingBracket) {
//std::cout<<" entering parseLatexString()\n"; //std::cout<<" entering parseLatexString()\n";
JKQTMathTextListNode* nl=new JKQTMathTextListNode(this); JKQTMathTextHorizontalListNode* nl=new JKQTMathTextHorizontalListNode(this);
if (get) getToken(); if (get) getToken();
//---------------------------------------------------------- //----------------------------------------------------------
@ -1469,6 +1478,8 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, JKQTMathTextBraceType
} else { } else {
nl->addChild(new JKQTMathTextTextNode(this, text, addWhite, parsingMathEnvironment)); nl->addChild(new JKQTMathTextTextNode(this, text, addWhite, parsingMathEnvironment));
} }
} else if (currentToken==MTTinstructionNewline) {
break;
} else if (currentToken==MTTwhitespace) { } else if (currentToken==MTTwhitespace) {
if (!parsingMathEnvironment) nl->addChild(new JKQTMathTextWhitespaceNode(this)); if (!parsingMathEnvironment) nl->addChild(new JKQTMathTextWhitespaceNode(this));
} else if (currentToken==MTTinstruction) { } else if (currentToken==MTTinstruction) {
@ -1489,7 +1500,7 @@ JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, JKQTMathTextBraceType
bool first=true; bool first=true;
QVector<JKQTMathTextNode*> line; QVector<JKQTMathTextNode*> line;
//std::cout<<"found \\begin{matrix}\n"; //std::cout<<"found \\begin{matrix}\n";
while (first || currentToken==MTTampersand || (currentToken==MTTinstruction && currentTokenName=="\\")) { while (first || currentToken==MTTampersand || currentToken==MTTinstructionNewline) {
JKQTMathTextNode* it=parseLatexString(true, MTBTAny, envname); JKQTMathTextNode* it=parseLatexString(true, MTBTAny, envname);
if (currentToken==MTTampersand) { if (currentToken==MTTampersand) {
//std::cout<<" appending item\n"; //std::cout<<" appending item\n";
@ -1736,6 +1747,31 @@ JKQTMathTextNode* JKQTMathText::parseInstruction(bool *_foundError, bool* getNew
if (foundError){ if (foundError){
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(Nparams+1)); error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(Nparams+1));
} }
} else if (currentInstructionName=="substack" || currentInstructionName=="rsubstack" || currentInstructionName=="lsubstack") {
getToken();
JKQTMathTextHorizontalAlignment alignment=MTHACentered;
if (currentInstructionName=="rsubstack") alignment=MTHARight;
if (currentInstructionName=="lsubstack") alignment=MTHALeft;
if (currentToken==MTTopenbracket) {
alignment=String2JKQTMathTextHorizontalAlignment(parseSingleString(true));
if (currentToken!=MTTclosebracket) {
error_list.append(tr("error @ ch. %1: didn't find closing brace ']' after '\\%2[]{}' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
getToken();
}
if (currentToken==MTTopenbrace) {
JKQTMathTextVerticalListNode* vlist = new JKQTMathTextVerticalListNode(this, alignment, 1.0, JKQTMathTextVerticalListNode::SMMinimal, MTVOFirstLine );
child=vlist;
bool first=true;
while (first || currentToken==MTTinstructionNewline) {
vlist->addChild(parseLatexString(true));
first=false;
}
if (currentToken!=MTTclosebrace) error_list.append(tr("error @ ch. %1: didn't find closing brace '}' after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
} else {
error_list.append(tr("error @ ch. %1: expected one argument in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else if (currentInstructionName=="sqrt") { } else if (currentInstructionName=="sqrt") {
getToken(); getToken();
if (currentToken==MTTopenbrace) { if (currentToken==MTTopenbrace) {
@ -1850,6 +1886,25 @@ QStringList JKQTMathText::parseStringParams(bool get, size_t Nparams, bool *foun
} }
} }
QString JKQTMathText::parseSingleString(bool get) {
const bool old_parsingMathEnvironment=parsingMathEnvironment;
auto reset_parsingMathEnvironment=JKQTPFinally([&]() { parsingMathEnvironment=old_parsingMathEnvironment; });
bool ok=true;
QString thisparam="";
while (ok) {
if (get) getToken();
get=true;
if (currentToken==MTTtext) {
thisparam+=currentTokenName;
} else if (currentToken==MTTwhitespace) {
thisparam+=" ";
} else {
ok=false;
}
}
return thisparam;
}
JKQTMathTextNode *JKQTMathText::getParsedNode() const { JKQTMathTextNode *JKQTMathText::getParsedNode() const {
return this->parsedNode; return this->parsedNode;

View File

@ -802,6 +802,7 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
MTTnone, /*!< \brief no token */ MTTnone, /*!< \brief no token */
MTTtext, /*!< \brief a piece of general text */ MTTtext, /*!< \brief a piece of general text */
MTTinstruction, /*!< \brief an instruction, started by \c "\\", e.g. \c "\\textbf", ... */ MTTinstruction, /*!< \brief an instruction, started by \c "\\", e.g. \c "\\textbf", ... */
MTTinstructionNewline, /*!< \brief a newline instruction \c "\\\\" */
MTTunderscore, /*!< \brief the character \c "_" */ MTTunderscore, /*!< \brief the character \c "_" */
MTThat, /*!< \brief the character \c "^" */ MTThat, /*!< \brief the character \c "^" */
MTTdollar, /*!< \brief the character \c "$" */ MTTdollar, /*!< \brief the character \c "$" */
@ -810,7 +811,7 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
MTTopenbracket, /*!< \brief the character \c "[" */ MTTopenbracket, /*!< \brief the character \c "[" */
MTTclosebracket, /*!< \brief the character \c "]" */ MTTclosebracket, /*!< \brief the character \c "]" */
MTTwhitespace, /*!< \brief some whitespace */ MTTwhitespace, /*!< \brief some whitespace */
MTTampersand /*!< \brief the character \c "&" */ MTTampersand, /*!< \brief the character \c "&" */
}; };
/** \brief tokenizer for the LaTeX parser */ /** \brief tokenizer for the LaTeX parser */
@ -831,6 +832,8 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
* \return the list of parameter strings with Nparam entries or an empty or partial list on error * \return the list of parameter strings with Nparam entries or an empty or partial list on error
*/ */
QStringList parseStringParams(bool get, size_t Nparams, bool *foundError=nullptr); 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 parses a single instruction (including it's parameters) /** \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 * \param[out] _foundError will be set to \c true if an error occured (unexpected token) or \c false otherwise

View File

@ -767,3 +767,45 @@ JKQTMathTextFontEncoding estimateJKQTMathTextFontEncoding(QFont font)
if (fm.inFont(QChar(0x2208))) return JKQTMathTextFontEncoding::MTFEUnicode; // element if (fm.inFont(QChar(0x2208))) return JKQTMathTextFontEncoding::MTFEUnicode; // element
return JKQTMathTextFontEncoding::MTFELatin1; return JKQTMathTextFontEncoding::MTFELatin1;
} }
QString JKQTMathTextHorizontalAlignment2String(JKQTMathTextHorizontalAlignment type)
{
switch(type) {
case MTHALeft: return "left";
case MTHARight: return "right";
default:
case MTHACentered: return "centered";
}
}
JKQTMathTextHorizontalAlignment String2JKQTMathTextHorizontalAlignment(QString tokenName)
{
tokenName=tokenName.toLower().trimmed();
if (tokenName=="l" || tokenName=="left") return MTHALeft;
if (tokenName=="r" || tokenName=="right") return MTHARight;
if (tokenName=="c" || tokenName=="center" || tokenName=="centered") return MTHACentered;
return MTHACentered;
}
QString JKQTMathTextVerticalOrientation2String(JKQTMathTextVerticalOrientation mode)
{
switch(mode) {
case MTVOTop: return "top";
case MTVOCentered: return "centered";
case MTVOLastLine: return "last_line";
case MTVOBottom: return "bottom";
default:
case MTVOFirstLine: return "first_line";
}
}
JKQTMathTextVerticalOrientation String2JKQTMathTextVerticalOrientation(QString tokenName)
{
tokenName=tokenName.toLower().trimmed();
if (tokenName=="p" || tokenName=="first_line" || tokenName=="first-line" || tokenName=="firstline" || tokenName=="line1") return MTVOFirstLine;
if (tokenName=="last_line" || tokenName=="last-line" || tokenName=="lastline" || tokenName=="linen") return MTVOLastLine;
if (tokenName=="t" || tokenName=="top") return MTVOTop;
if (tokenName=="b" || tokenName=="bottom") return MTVOBottom;
if (tokenName=="c" || tokenName=="center" || tokenName=="centered") return MTVOCentered;
return MTVOCentered;
}

View File

@ -385,6 +385,52 @@ JKQTMATHTEXT_LIB_EXPORT QRectF JKQTMathTextGetTightBoundingRect(const QFont &fm,
JKQTMATHTEXT_LIB_EXPORT QFont JKQTMathTextGetNonItalic(const QFont& f); JKQTMATHTEXT_LIB_EXPORT QFont JKQTMathTextGetNonItalic(const QFont& f);
/** \brief types of horizontal alignment
* \ingroup jkqtmathtext_tools
*
* \image html jkqtmathtext_horizontalalignment.png
*
* \see JKQTMathTextVerticalOrientation2String(), String2JKQTMathTextVerticalOrientation(), JKQTMathTextVerticalListNode
*/
enum JKQTMathTextHorizontalAlignment {
MTHALeft, /*!< \brief align left */
MTHACentered, /*!< \brief align centered */
MTHARight, /*!< \brief align right */
};
/** \brief convert a JKQTMathTextHorizontalAlignment into a string
* \ingroup jkqtmathtext_tools
*/
JKQTMATHTEXT_LIB_EXPORT QString JKQTMathTextHorizontalAlignment2String(JKQTMathTextHorizontalAlignment type);
/** \brief convert a string \a tokenName into a JKQTMathTextHorizontalAlignment
* \ingroup jkqtmathtext_tools
*/
JKQTMATHTEXT_LIB_EXPORT JKQTMathTextHorizontalAlignment String2JKQTMathTextHorizontalAlignment(QString tokenName);
/** \brief type of ffractions represented by JKQTMathTextFracNode
* \ingroup jkqtmathtext_tools
*
* \image html jkqtmathtext_verticalorientation.png
*
* \see JKQTMathTextVerticalOrientation2String(), String2JKQTMathTextVerticalOrientation(), JKQTMathTextVerticalListNode
*/
enum JKQTMathTextVerticalOrientation {
MTVOTop, /*!< \brief baseline of the whole block is at the top of the first */
MTVOFirstLine, /*!< \brief baseline of the whole block is at the baseline of the first line */
MTVOCentered, /*!< \brief baseline of the whole block is at the center of all lines */
MTVOLastLine, /*!< \brief baseline of the whole block is at the baseline of the last line */
MTVOBottom, /*!< \brief baseline of the whole block is at the bottom of the last line */
};
/** \brief convert a JKQTMathTextVerticalOrientation into a QString
* \ingroup jkqtmathtext_tools
*/
JKQTMATHTEXT_LIB_EXPORT QString JKQTMathTextVerticalOrientation2String(JKQTMathTextVerticalOrientation mode);
/** \brief returns the JKQTMathTextVerticalOrientation corresponding to \a instructionName
* \ingroup jkqtmathtext_tools
*/
JKQTMATHTEXT_LIB_EXPORT JKQTMathTextVerticalOrientation String2JKQTMathTextVerticalOrientation(QString mode);
#endif // JKQTMATHTEXTTOOLS_H #endif // JKQTMATHTEXTTOOLS_H

View File

@ -36,23 +36,23 @@
#include <QFont> #include <QFont>
JKQTMathTextListNode::JKQTMathTextListNode(JKQTMathText* _parent): JKQTMathTextHorizontalListNode::JKQTMathTextHorizontalListNode(JKQTMathText* _parent):
JKQTMathTextMultiChildNode(_parent) JKQTMathTextMultiChildNode(_parent)
{ {
nodes.clear(); nodes.clear();
// these operations cause sub/sup script to be typeset over/under the operator, not right besides! // these operations cause sub/sup script to be typeset over/under the operator, not right besides!
} }
JKQTMathTextListNode::~JKQTMathTextListNode() { JKQTMathTextHorizontalListNode::~JKQTMathTextHorizontalListNode() {
clearChildrenImpl(true); clearChildrenImpl(true);
} }
QString JKQTMathTextListNode::getTypeName() const QString JKQTMathTextHorizontalListNode::getTypeName() const
{ {
return "MTlistNode"; return "MTHorizontalListNode";
} }
void JKQTMathTextListNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* /*prevNodeSize*/) { void JKQTMathTextHorizontalListNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* /*prevNodeSize*/) {
width=0; width=0;
overallHeight=0; overallHeight=0;
baselineHeight=0; baselineHeight=0;
@ -326,7 +326,7 @@ void JKQTMathTextListNode::getSizeInternal(QPainter& painter, JKQTMathTextEnviro
width=xnew; width=xnew;
} }
double JKQTMathTextListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* /*prevNodeSize*/) { double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv); doDrawBoxes(painter, x, y, currentEv);
double ynew=y; double ynew=y;
double xnew=x; double xnew=x;
@ -512,12 +512,12 @@ double JKQTMathTextListNode::draw(QPainter& painter, double x, double y, JKQTMat
return xnew; return xnew;
} }
void JKQTMathTextListNode::addChild(JKQTMathTextNode *n) { void JKQTMathTextHorizontalListNode::addChild(JKQTMathTextNode *n) {
n->setParentNode(this); n->setParentNode(this);
nodes.append(n); nodes.append(n);
} }
bool JKQTMathTextListNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) { bool JKQTMathTextHorizontalListNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) {
bool ok=true; bool ok=true;
for (int i=0; i<nodes.size(); i++) { for (int i=0; i<nodes.size(); i++) {
QString h=""; QString h="";
@ -527,18 +527,18 @@ bool JKQTMathTextListNode::toHtml(QString &html, JKQTMathTextEnvironment current
return ok; return ok;
} }
QList<JKQTMathTextNode *> JKQTMathTextListNode::getChildren() { QList<JKQTMathTextNode *> JKQTMathTextHorizontalListNode::getChildren() {
return this->nodes; return this->nodes;
} }
int JKQTMathTextListNode::childCount() const int JKQTMathTextHorizontalListNode::childCount() const
{ {
return nodes.size(); return nodes.size();
} }
void JKQTMathTextListNode::clearChildrenImpl(bool deleteChildren) void JKQTMathTextHorizontalListNode::clearChildrenImpl(bool deleteChildren)
{ {
if (deleteChildren) { if (deleteChildren) {
for (int i=0; i<nodes.size(); i++) { for (int i=0; i<nodes.size(); i++) {
@ -548,22 +548,22 @@ void JKQTMathTextListNode::clearChildrenImpl(bool deleteChildren)
nodes.clear(); nodes.clear();
} }
void JKQTMathTextListNode::clearChildren(bool deleteChildren) void JKQTMathTextHorizontalListNode::clearChildren(bool deleteChildren)
{ {
clearChildrenImpl(deleteChildren); clearChildrenImpl(deleteChildren);
} }
JKQTMathTextNode *JKQTMathTextListNode::getChild(int i) JKQTMathTextNode *JKQTMathTextHorizontalListNode::getChild(int i)
{ {
return nodes[i]; return nodes[i];
} }
const JKQTMathTextNode *JKQTMathTextListNode::getChild(int i) const const JKQTMathTextNode *JKQTMathTextHorizontalListNode::getChild(int i) const
{ {
return nodes[i]; return nodes[i];
} }
JKQTMathTextNode *JKQTMathTextListNode::replaceChild(int i, JKQTMathTextNode *newChild) JKQTMathTextNode *JKQTMathTextHorizontalListNode::replaceChild(int i, JKQTMathTextNode *newChild)
{ {
JKQTMathTextNode* c=nodes[i]; JKQTMathTextNode* c=nodes[i];
nodes[i]=newChild; nodes[i]=newChild;
@ -571,3 +571,229 @@ JKQTMathTextNode *JKQTMathTextListNode::replaceChild(int i, JKQTMathTextNode *ne
return c; return c;
} }
QString JKQTMathTextVerticalListNode::SpacingMode2String(SpacingMode mode)
{
switch(mode) {
case SMMinimal: return "minimal";
default:
case SMDefault: return "default";
}
}
JKQTMathTextVerticalListNode::SpacingMode JKQTMathTextVerticalListNode::String2SpacingMode(QString tokenName)
{
tokenName=tokenName.toLower().trimmed();
if (tokenName=="default") return SMDefault;
if (tokenName=="minimal" || tokenName=="min" || tokenName=="minimum") return SMMinimal;
return SMDefault;
}
JKQTMathTextVerticalListNode::JKQTMathTextVerticalListNode(JKQTMathText *_parent, JKQTMathTextHorizontalAlignment _alignment, double _linespacingFactor, SpacingMode spacingMode_, JKQTMathTextVerticalOrientation _verticalOrientation):
JKQTMathTextMultiChildNode(_parent),
alignment(_alignment),
lineSpacingFactor(_linespacingFactor),
verticalOrientation(_verticalOrientation),
spacingMode(spacingMode_)
{
nodes.clear();
// these operations cause sub/sup script to be typeset over/under the operator, not right besides!
}
JKQTMathTextVerticalListNode::~JKQTMathTextVerticalListNode() {
clearChildrenImpl(true);
}
QString JKQTMathTextVerticalListNode::getTypeName() const
{
return "MTVerticalListNode";
}
void JKQTMathTextVerticalListNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* prevNodeSize) {
const LayoutInfo l=calcLayout(painter, currentEv);
width=l.width;
overallHeight=l.overallHeight;
baselineHeight=l.baselineHeight;
strikeoutPos=l.strikeoutPos;
}
JKQTMathTextVerticalListNode::LayoutInfo JKQTMathTextVerticalListNode::calcLayout(QPainter &painter, JKQTMathTextEnvironment currentEv)
{
LayoutInfo l;
const QFontMetricsF fm(currentEv.getFont(parentMathText));
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 (nodes.size()<=0) {
return l;
}
// 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<nodes.size(); i++) {
double locWidth=0, locOverallHeight=0, locBaselineHeight=0, locStrikeoutPos=0;
nodes[i]->getSize(painter, currentEv, locWidth, locBaselineHeight, locOverallHeight, locStrikeoutPos);
if (i==0) {
heightSum=locBaselineHeight;
} else if (i>0) {
double deltaLine=0;
if (spacingMode==SMMinimal) {
deltaLine=descents.last()+lineLeading+locBaselineHeight;
} else if (spacingMode==SMDefault) {
deltaLine=qMax(linespacing, descents.last()+lineLeading+locBaselineHeight);
}
heightSum=heightSum+deltaLine;
y=y+deltaLine;
}
widths<<locWidth;
l.width=qMax(l.width, locWidth);
heights<<locOverallHeight;
ascents<<locBaselineHeight;
descents<<(locOverallHeight-locBaselineHeight);
strikeouts<<locStrikeoutPos;
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<nodes.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;
}
double JKQTMathTextVerticalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
const LayoutInfo l=calcLayout(painter, currentEv);
for (int i=0; i<nodes.size(); i++) {
nodes[i]->draw(painter, x+l.X.at(i).x(), y+l.X.at(i).y(), currentEv);
}
return x+l.width;
}
void JKQTMathTextVerticalListNode::addChild(JKQTMathTextNode *n) {
n->setParentNode(this);
nodes.append(n);
}
bool JKQTMathTextVerticalListNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) {
bool ok=true;
if (alignment==MTHALeft) {
html+="<div align=\"left\">";
} else if (alignment==MTHACentered) {
html+="<div align=\"center\">";
} else if (alignment==MTHARight) {
html+="<div align=\"right\">";
}
for (int i=0; i<nodes.size(); i++) {
QString h="";
ok = ok && nodes[i]->toHtml(h, currentEv, defaultEv);
if (i==0) html=html+h;
else html=html+"<br/>"+h;
}
html+="</div>";
return ok;
}
QList<JKQTMathTextNode *> JKQTMathTextVerticalListNode::getChildren() {
return this->nodes;
}
int JKQTMathTextVerticalListNode::childCount() const
{
return nodes.size();
}
void JKQTMathTextVerticalListNode::clearChildrenImpl(bool deleteChildren)
{
if (deleteChildren) {
for (int i=0; i<nodes.size(); i++) {
delete nodes[i];
}
}
nodes.clear();
}
void JKQTMathTextVerticalListNode::clearChildren(bool deleteChildren)
{
clearChildrenImpl(deleteChildren);
}
JKQTMathTextNode *JKQTMathTextVerticalListNode::getChild(int i)
{
return nodes[i];
}
const JKQTMathTextNode *JKQTMathTextVerticalListNode::getChild(int i) const
{
return nodes[i];
}
JKQTMathTextNode *JKQTMathTextVerticalListNode::replaceChild(int i, JKQTMathTextNode *newChild)
{
JKQTMathTextNode* c=nodes[i];
nodes[i]=newChild;
newChild->setParentNode(this);
return c;
}
JKQTMathTextHorizontalAlignment JKQTMathTextVerticalListNode::getAlignment() const
{
return alignment;
}
JKQTMathTextVerticalOrientation JKQTMathTextVerticalListNode::getVerticalOrientation() const
{
return verticalOrientation;
}
double JKQTMathTextVerticalListNode::getLineSpacingFactor() const
{
return lineSpacingFactor;
}
JKQTMathTextVerticalListNode::SpacingMode JKQTMathTextVerticalListNode::getSpacingMode() const
{
return spacingMode;
}
JKQTMathTextVerticalListNode::LayoutInfo::LayoutInfo():
width(0),
baselineHeight(0),
overallHeight(0),
strikeoutPos(0)
{}

View File

@ -27,22 +27,25 @@
#include "jkqtmathtext/jkqtmathtexttools.h" #include "jkqtmathtext/jkqtmathtexttools.h"
#include "jkqtmathtext/nodes/jkqtmathtextnode.h" #include "jkqtmathtext/nodes/jkqtmathtextnode.h"
#include <QPainter> #include <QPainter>
#include <QFontMetricsF>
class JKQTMathText; // forward class JKQTMathText; // forward
// JKQTMATHTEXT_LIB_EXPORT // JKQTMATHTEXT_LIB_EXPORT
/** \brief subclass representing a list of nodes in the syntax tree /** \brief subclass representing a list of nodes in the syntax tree, layed out horizontally
* \ingroup jkqtmathtext_items * \ingroup jkqtmathtext_items
* *
* \note This type of node also implements typesetting sub-/superscript above/below the previous node (if * \note This type of node also implements typesetting sub-/superscript above/below the previous node (if
* JKQTMathTextNode::is() is \c true for that previus node. The drawing is done as defined in the * JKQTMathTextNode::is() is \c true for that previus node. The drawing is done as defined in the
* following image \image html jkqtmathtext_subsuper_with_limits.png * following image \image html jkqtmathtext_subsuper_with_limits.png
*
* \see JKQTMathTextVerticalListNode
*/ */
class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextListNode: public JKQTMathTextMultiChildNode { class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextHorizontalListNode: public JKQTMathTextMultiChildNode {
public: public:
explicit JKQTMathTextListNode(JKQTMathText* parent); explicit JKQTMathTextHorizontalListNode(JKQTMathText* parent);
virtual ~JKQTMathTextListNode() override; virtual ~JKQTMathTextHorizontalListNode() override;
/** \copydoc JKQTMathTextNode::getTypeName() */ /** \copydoc JKQTMathTextNode::getTypeName() */
virtual QString getTypeName() const override; virtual QString getTypeName() const override;
/** \copydoc JKQTMathTextNode::draw() */ /** \copydoc JKQTMathTextNode::draw() */
@ -72,6 +75,119 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextListNode: public JKQTMathTextMultiChil
void clearChildrenImpl(bool deleteChildren); void clearChildrenImpl(bool deleteChildren);
}; };
/** \brief subclass representing a list of nodes in the syntax tree, layed out vertically
* \ingroup jkqtmathtext_items
*
* Each child can be thought of as a line, so this node represents a list of lines.
* 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
*
* \see JKQTMathTextHorizontalListNode
*/
class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextVerticalListNode: public JKQTMathTextMultiChildNode {
public:
/** \brief defines, how lines are beeing spaced by the node
*
* \image html jkqtmathtext_verticallist.png
*/
enum SpacingMode {
SMDefault, /*!< space the lines with equilibrated spacing, i.e. the baselines are at least \c QFontMetricsF::lineSpacing()*JKQTMathTextVerticalListNode::lineSpacingFactor apart, but even more, if the height of the text bloxk is larger than the the font's ascent+descent */
SMMinimal /*!< space the lines as tight as possible, i.e. each line is separated by \c QFontMetricsF::leading()*JKQTMathTextVerticalListNode::lineSpacingFactor from the next line. This is a s compact as possible */
};
/** \brief convert a SpacingMode to a String */
static QString SpacingMode2String(SpacingMode mode);
/** \brief convert a String to a SpacingMode */
static SpacingMode String2SpacingMode(QString mode);
explicit JKQTMathTextVerticalListNode(JKQTMathText* parent, JKQTMathTextHorizontalAlignment _alignment=MTHACentered, double _linespacingFactor=1.0, SpacingMode spacingMode_=SMDefault, JKQTMathTextVerticalOrientation _verticalOrientation=MTVOFirstLine);
virtual ~JKQTMathTextVerticalListNode() override;
/** \copydoc JKQTMathTextNode::getTypeName() */
virtual QString getTypeName() const 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;
/** \brief add a child node */
void addChild(JKQTMathTextNode* n);
/** \copydoc JKQTMathTextMultiChildNode::getChildren() */
virtual QList<JKQTMathTextNode*> getChildren() override;
/** \copydoc JKQTMathTextMultiChildNode::childCount() */
virtual int childCount() const override;
/** \copydoc JKQTMathTextMultiChildNode::clearChildren() */
virtual void clearChildren(bool deleteChildren=true) override;
/** \copydoc JKQTMathTextMultiChildNode::getChild() */
virtual JKQTMathTextNode* getChild(int i) override;
/** \copydoc JKQTMathTextMultiChildNode::getChild() */
virtual const JKQTMathTextNode* getChild(int i) const override;
/** \copydoc JKQTMathTextMultiChildNode::getChild() */
virtual JKQTMathTextNode* replaceChild(int i, JKQTMathTextNode* newChild) override;
/** \copydoc alignment */
JKQTMathTextHorizontalAlignment getAlignment() const;
/** \copydoc verticalOrientation */
JKQTMathTextVerticalOrientation getVerticalOrientation() const;
/** \copydoc lineSpacingFactor */
double getLineSpacingFactor() const;
/** \copydoc spacingMode */
SpacingMode getSpacingMode() const;
protected:
/** \copydoc JKQTMathTextNode::getSizeInternal() */
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 {
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);
/** \brief list of child nodes, each representing one line */
QList<JKQTMathTextNode*> nodes;
/** \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 defines how the layout algorithm (see calcLayout() ) lays out the single lines */
SpacingMode spacingMode;
private:
/** \brief internal implementation of clearChildren() that is non-virtual, so can be used in the destructor */
void clearChildrenImpl(bool deleteChildren);
};
#endif // JKQTMATHTEXTLISTNODE_H #endif // JKQTMATHTEXTLISTNODE_H

View File

@ -27,7 +27,7 @@
JKQTMathTextNode *simplifyJKQTMathTextNode(JKQTMathTextNode *node) JKQTMathTextNode *simplifyJKQTMathTextNode(JKQTMathTextNode *node)
{ {
JKQTMathTextListNode* nl=dynamic_cast<JKQTMathTextListNode*>(node); JKQTMathTextHorizontalListNode* nl=dynamic_cast<JKQTMathTextHorizontalListNode*>(node);
JKQTMathTextMultiChildNode* nmc=dynamic_cast<JKQTMathTextMultiChildNode*>(node); JKQTMathTextMultiChildNode* nmc=dynamic_cast<JKQTMathTextMultiChildNode*>(node);
JKQTMathTextSingleChildNode* nsc=dynamic_cast<JKQTMathTextSingleChildNode*>(node); JKQTMathTextSingleChildNode* nsc=dynamic_cast<JKQTMathTextSingleChildNode*>(node);
if (nl) { if (nl) {

View File

@ -32,7 +32,7 @@ class JKQTMathTextNode; // forward
* \ingroup jkqtmathtext_items * \ingroup jkqtmathtext_items
* *
* Basically this takes does the following steps (recursively): * Basically this takes does the following steps (recursively):
* - remove any JKQTMathTextListNode that has only one child * - remove any JKQTMathTextHorizontalListNode that has only one child
* . * .
*/ */
JKQTMATHTEXT_LIB_EXPORT JKQTMathTextNode* simplifyJKQTMathTextNode(JKQTMathTextNode* node); JKQTMATHTEXT_LIB_EXPORT JKQTMathTextNode* simplifyJKQTMathTextNode(JKQTMathTextNode* node);