JKQtPlotter/lib/jkqtmathtext/jkqtmathtext.cpp
jkriege2 356cc34349 new: Statistics library with functions to calculate histograms, regression, kernel density estimates, ... including a new example
new: iterator interface and improved documentation for JKQTPDatastore
reorganization of library (better separation of common code in jkqtpcommon and other code e.g. in jkqtplotter or jkqtmathtext)
2019-05-29 22:40:02 +02:00

4497 lines
203 KiB
C++

/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
#include <QFontDatabase>
#include <typeinfo>
#include <QApplication>
/**
* \brief saves the given property (for which also a default_property exists) into the given settings object
* \ingroup jkqtmathtext
* \internal
*/
#define JKQTMTPROPERTYsave(settings, group, var, varname) \
if (var!=default_##var) settings.setValue(group+varname, var);
/**
* \brief loads the given property from the given settings object
* \ingroup jkqtmathtext
* \internal
*/
#define JKQTMTPROPERTYload(settings, group, var, varname, varconvert) \
var=settings.value(group+varname, var).varconvert;
const double JKQTMathText::ABS_MIN_LINEWIDTH=0.02;
QPainterPath makeHBracePath(double x, double ybrace, double width, double bw, double cubicshrink=0.5, double cubiccontrolfac=0.3) {
double xl1=x-(width)*cubicshrink+bw*cubicshrink;
double xr2=x+(width)*cubicshrink-bw*cubicshrink;
double xl2=x-bw*cubicshrink;
double xr1=x+bw*cubicshrink;
QPainterPath path;
path.moveTo(xl1-bw*cubicshrink, ybrace-bw*cubicshrink);
path.cubicTo(xl1-bw*cubicshrink, ybrace-bw*cubicshrink+bw*cubiccontrolfac, xl1-bw*cubiccontrolfac, ybrace, xl1, ybrace);
path.lineTo(xl2, ybrace);
path.cubicTo(xl2+bw*cubiccontrolfac, ybrace, (xl2+xr1)/2.0, ybrace+bw*cubicshrink-bw*cubiccontrolfac, (xl2+xr1)/2.0, ybrace+bw*cubicshrink);
path.cubicTo((xl2+xr1)/2.0, ybrace+bw*cubicshrink-bw*cubiccontrolfac, xr1-bw*cubiccontrolfac, ybrace, xr1, ybrace);
path.lineTo(xr2, ybrace);
path.cubicTo(xr2+bw*cubiccontrolfac, ybrace, xr2+bw*cubicshrink, ybrace-bw*cubicshrink+bw*cubiccontrolfac, xr2+bw*cubicshrink, ybrace-bw*cubicshrink);
return path;
}
QPainterPath makeArrow(double x, double y, double width, double arrowW, bool left=false, bool right=true) {
double x1=x;
double x2=x+width;
double x3=x2-arrowW/2.0;
double y3u=y-arrowW/2.0;
double y3d=y+arrowW/2.0;
double x3l=x+arrowW/2.0;
QPainterPath path;
path.moveTo(x1, y);
path.lineTo(x2, y);
if (right) {
path.moveTo(x3, y3u);
path.lineTo(x2, y);
path.lineTo(x3, y3d);
}
if (left) {
path.moveTo(x3l, y3u);
path.lineTo(x1, y);
path.lineTo(x3l, y3d);
}
return path;
}
QPainterPath makeDArrow(double x, double y, double width, double arrowW, bool left=false, bool right=true) {
double x1=x;
double x2=x+width;
double dx=arrowW/4.0;
double y1=y-dx;
double y2=y+dx;
double x3=x2-arrowW/2.0;
double y3u=y-arrowW/2.0;
double y3d=y+arrowW/2.0;
double x3l=x+arrowW/2.0;
QPainterPath path;
path.moveTo(x1+dx, y1);
path.lineTo(x2-dx, y1);
path.moveTo(x1+dx, y2);
path.lineTo(x2-dx, y2);
if (right) {
path.moveTo(x3, y3u);
path.lineTo(x2, y);
path.lineTo(x3, y3d);
}
if (left) {
path.moveTo(x3l, y3u);
path.lineTo(x1, y);
path.lineTo(x3l, y3d);
}
return path;
}
// --------------------------------------------------------------------------------------------------
// -- implementation of the MTnode's methods
// --------------------------------------------------------------------------------------------------
JKQTMathText::MTenvironment::MTenvironment() {
color=QColor("black");
font=MTEroman;
fontSize=10;
bold=false;
italic=false;
smallCaps=false;
underlined=false;
overline=false;
strike=false;
insideMath=false;
}
QFont JKQTMathText::MTenvironment::getFont(JKQTMathText* parent) const {
QFont f;
switch (font) {
case MTEsans:
f.setFamily(parent->getFontSans());
break;
case MTEtypewriter: f.setFamily(parent->getFontTypewriter()); break;
case MTEscript: f.setFamily(parent->getFontScript()); break;
case MTEroman:
f.setFamily(parent->getFontRoman());
break;
case MTEcaligraphic: f.setFamily(parent->getFontCaligraphic()); break;
case MTEblackboard: f.setFamily(parent->getFontBlackboard()); break;
};
f.setBold(bold);
f.setItalic(italic);
f.setUnderline(underlined);
f.setOverline(overline);
f.setStrikeOut(strike);
f.setCapitalization(QFont::MixedCase);
if (smallCaps) f.setCapitalization(QFont::SmallCaps);
f.setPointSizeF(fontSize);
f.setStyleStrategy(QFont::NoFontMerging);
return f;
}
QString JKQTMathText::MTenvironment::toHtmlStart(MTenvironment defaultEv) const {
QString s;
s=s+"font-size: "+QLocale::c().toString(fontSize)+"pt; ";
if (insideMath) {
if (defaultEv.italic) {
if (!italic) s=s+"font-style: italic; ";
if (italic) s=s+"font-style: normal; ";
} else {
if (!italic) s=s+"font-style: italic; ";
}
} else {
if (!defaultEv.italic && italic) s=s+"font-style: italic; ";
}
if (bold && !defaultEv.bold) s=s+"font-weight: bold";
QStringList td;
if (underlined && !defaultEv.underlined) td<<"underline";
if (overline && !defaultEv.overline) td<<"overline";
if (strike && !defaultEv.strike) td<<"line-through";
if (td.size()>0) s=s+"text-decoration: "+td.join(", ");
return "<span style=\""+s+"\">";
}
QString JKQTMathText::MTenvironment::toHtmlAfter(JKQTMathText::MTenvironment /*defaultEv*/) const {
return "</span>";
}
JKQTMathText::MTnode::MTnode(JKQTMathText* parent) {
this->parent=parent;
drawBoxes=false;
}
JKQTMathText::MTnode::~MTnode()
= default;
void JKQTMathText::MTnode::getSize(QPainter &painter, JKQTMathText::MTenvironment currentEv, double &width, double &baselineHeight, double &overallHeight, double &strikeoutPos, const MTnodeSize* prevNodeSize)
{
double w=width, b=baselineHeight, o=overallHeight, s=strikeoutPos;
getSizeInternal(painter, currentEv, w, b, o, s, prevNodeSize);
if (w<1e5) width=w;
if (b<1e5) baselineHeight=b;
if (o<1e5) overallHeight=o;
if (s<1e5) strikeoutPos=s;
}
bool JKQTMathText::MTnode::toHtml(QString &/*html*/, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/) {
return false;
}
bool JKQTMathText::MTnode::getDrawBoxes() const {
return this->drawBoxes;
}
void JKQTMathText::MTnode::doDrawBoxes(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv) {
if (drawBoxes) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
double w, oh, bh, sp;
getSize(painter, currentEv, w, bh, oh, sp);
QPen p=painter.pen();
p.setColor("lightcoral");
p.setWidthF(0.5);
painter.setPen(p);
QRectF r(x, y-bh, w, oh);
painter.drawRect(r);
p.setColor("lightblue");
painter.setPen(p);
if (w>0) painter.drawLine(QLineF(x, y, x+w, y));
p.setColor("green");
painter.setPen(p);
painter.drawEllipse(QRectF(x-3.0,y-3.0,6.0,6.0));
p.setColor("lightgreen");
painter.setPen(p);
painter.drawLine(QLineF(x-2.0, y, x+2.0, y));
painter.drawLine(QLineF(x, y-2, x, y+2.0));
}
}
JKQTMathText::MTtextNode::MTtextNode(JKQTMathText* parent, const QString& textIn, bool addWhitespace, bool stripInnerWhitepace):
JKQTMathText::MTnode(parent)
{
QString text=textIn;
if (stripInnerWhitepace) {
text="";
for (int i=0; i<textIn.size(); i++) {
if (!textIn[i].isSpace()) text+=textIn[i];
}
}
this->text=text;
// strip all whitespace from left
while (this->text.size()>1 && this->text[0].isSpace()) {
this->text=this->text.right(this->text.size()-1);
}
if (addWhitespace /*&& (this->text.size()>0)*/ && (!this->text[this->text.size()-1].isSpace())) this->text=this->text+" ";
//qDebug()<<"MTtextNode( text="<<text<<" addWhitespace="<<addWhitespace<<") [=> this->text="<<this->text<<"]";
}
JKQTMathText::MTtextNode::~MTtextNode() = default;
void JKQTMathText::MTtextNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
QFont f=currentEv.getFont(parent);
if (currentEv.insideMath && (text=="(" || text=="[" || text=="|" || text=="]" || text==")" || text=="<" || text==">" ||
text==QString(QChar(0x2329)) || text==QString(QChar(0x232A)) || text==QString(QChar(0x2308)) ||
text==QString(QChar(0x2309)) || text==QString(QChar(0x230A)) || text==QString(QChar(0x230B)))) {
f.setItalic(false);
f.setFamily(parent->getFontBraces());
}
QString txt=textTransform(text, currentEv, true);
QFontMetricsF fm(f, painter.device());
QRectF br=fm.boundingRect(txt);
QRectF tbr=parent->getTightBoundingRect(f, txt, painter.device()); //fm.tightBoundingRect(txt);
if (txt=="|") {
br=fm.boundingRect("X");
tbr=QRectF(0,0,fm.width("X"), fm.ascent());//fm.boundingRect("X");
br.setWidth(0.7*br.width());
}
width=br.width();//width(text);
if (txt.size()>0) {
if (txt[0].isSpace() /*&& br.width()<=0*/) width=width+fm.boundingRect("I").width();
if (txt.size()>1 && txt[txt.size()-1].isSpace() /*&& (fm.boundingRect("a ").width()==fm.boundingRect("a").width())*/) width=width+fm.width("I");
}
//qDebug()<<"text: "<<text<<" "<<tbr.height()<<tbr.top()<<tbr.bottom();
overallHeight=tbr.height()*1.1; //fm.height();
baselineHeight=1.1*(tbr.height()-(tbr.height()+tbr.top()));//fm.ascent();
strikeoutPos=fm.strikeOutPos()*1.1;
}
double JKQTMathText::MTtextNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
double width=0;
double baselineHeight=0;
double overallHeight=0;
double sp=0;
getSize(painter, currentEv, width, baselineHeight, overallHeight, sp);
QString txt=textTransform(text, currentEv);
bool hasDigits=false;
bool onlyDigits=true;
for (int i=0; i<txt.size(); i++) {
if (txt[i].isDigit()) {
hasDigits=true;
}
if (!txt[i].isDigit() && !txt[i].isSpace()) {
onlyDigits=false;
}
}
QPen pold=painter.pen();
QFont fold=painter.font();
QFont f=currentEv.getFont(parent);
if (currentEv.insideMath && (text=="(" || text=="[" || text=="|" || text=="]" || text==")" || text=="<" || text==">" ||
text==QString(QChar(0x2329)) || text==QString(QChar(0x232A)) || text==QString(QChar(0x2308)) ||
text==QString(QChar(0x2309)) || text==QString(QChar(0x230A)) || text==QString(QChar(0x230B)))) {
f.setItalic(false);
f.setFamily(parent->getFontBraces());
}
if (onlyDigits && currentEv.insideMath) {
f.setItalic(false);
}
painter.setFont(f);
QPen p=painter.pen();
p.setColor(currentEv.color);
painter.setPen(p);
double dx=0;
QFontMetricsF fm(f, painter.device());
/*if (txt.size()>1 && txt[txt.size()-1].isSpace()) {
QFontMetricsF fm(f, painter.device());
//if ((fm.width("a ")==fm.width("a"))) dx=fm.boundingRect("I").width();
}*/
if (!hasDigits || !f.italic()) {
painter.drawText(QPointF(x+dx, y), txt);//.simplified());
} else {
int i=0;
double xx=x+dx;
QFont ff=f;
QFontMetricsF fmff(ff, painter.device());
ff.setItalic(false);
while (i<txt.size()) {
if (txt[i].isDigit()) {
painter.setFont(ff);
painter.drawText(QPointF(xx, y), QString(txt[i]));
xx=xx+fmff.width(txt[i]);
} else {
painter.setFont(f);
painter.drawText(QPointF(xx, y), QString(txt[i]));
xx=xx+fm.width(txt[i]);
}
i++;
}
}
painter.setPen(pold);
painter.setFont(fold);
return x+width;
}
bool JKQTMathText::MTtextNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) {
html=html+currentEv.toHtmlStart(defaultEv)+text+currentEv.toHtmlAfter(defaultEv);
return true;
}
QString JKQTMathText::MTtextNode::getTypeName() const
{
return QLatin1String("MTtextNode(")+text+")";
}
QString JKQTMathText::MTtextNode::textTransform(const QString &text, JKQTMathText::MTenvironment currentEv, bool /*forSize*/)
{
QString txt=text;
if (parent->getFontEncoding()==MTFEunicode || parent->getFontEncoding()==MTFEunicodeLimited) {
if (currentEv.insideMath) {
txt="";
for (int i=0; i<text.size(); i++) {
QChar c=text[i];
switch(c.unicode()) {
case '-': txt+=QString(QString(" ")+QChar(0x2212)); break;
case '+': txt+=QString(QString(" +")); break;
case '/': txt+=QString(QString(" / ")); break;
case '<': txt+=QString(QString(" < ")); break;
case '>': txt+=QString(QString(" > ")); break;
case '=': txt+=QString(QString(" = ")); break;
case ';': txt+=QString(QString("; ")); break;
default: txt+=c; break;
}
}
txt=txt.replace(" ", " ");
}
}
if (currentEv.font==MTEblackboard && parent->getFontEncoding()==MTFEunicode) {
txt="";
for (int i=0; i<text.size(); i++) {
QChar c=text[i];
switch(c.unicode()) {
case 'C': txt+=QChar(0x2102); break;
case 'H': txt+=QChar(0x210D); break;
case 'N': txt+=QChar(0x2115); break;
case 'P': txt+=QChar(0x2119); break;
case 'Q': txt+=QChar(0x211A); break;
case 'R': txt+=QChar(0x211D); break;
case 'Z': txt+=QChar(0x2124); break;
case 'd': txt+=QChar(0x2146); break;
case 'e': txt+=QChar(0x2147); break;
case 'i': txt+=QChar(0x2148); break;
case 'j': txt+=QChar(0x2149); break;
default: txt+=c; break;
}
}
}
return txt;
}
JKQTMathText::MTinstruction1Node::MTinstruction1Node(JKQTMathText* parent, const QString& name, MTnode* child, const QStringList& parameters):
JKQTMathText::MTnode(parent)
{
this->name=name;
this->child=child;
this->parameters=parameters;
JKQTMathText::MTenvironment ev;
if (!setupMTenvironment(ev)) {
parent->error_list.append(tr("unknown instruction '%1' found!").arg(name));
}
}
JKQTMathText::MTinstruction1Node::~MTinstruction1Node() {
if (child!=nullptr) delete child;
}
QString JKQTMathText::MTinstruction1Node::getTypeName() const
{
return QLatin1String("MTinstruction1Node(")+name+")";
}
void JKQTMathText::MTinstruction1Node::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
JKQTMathText::MTenvironment ev=currentEv;
setupMTenvironment(ev);
child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos);
if (name=="colorbox" || name=="fbox" || name=="boxed") {
QFontMetricsF fm(ev.getFont(parent));
double xw=fm.width("x");
width+=xw;
overallHeight+=xw;
baselineHeight+=xw/2.0;
}
}
double JKQTMathText::MTinstruction1Node::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
JKQTMathText::MTenvironment ev=currentEv;
setupMTenvironment(ev);
QPen oldPen=painter.pen();
double shiftX=0;
if (name=="colorbox" || name=="fbox" || name=="boxed") {
QColor fcol=currentEv.color;
if (name=="colorbox") fcol=QColor(parameters.value(0, ev.color.name()));
//qDebug()<<"COLOR="<<fcol;
double width, baselineHeight, overallHeight, strikeoutPos;
child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
QPen p=painter.pen();
QFontMetricsF fm(currentEv.getFont(parent));
double xw=fm.width("x");
p.setColor(fcol);
painter.setPen(p);
painter.drawRect(QRectF(x,y-baselineHeight-xw/2,width+xw,overallHeight+xw));
shiftX=xw/2.0;
}
double xnew= child->draw(painter, x+shiftX, y, ev);
painter.setPen(oldPen);
return xnew;
}
bool JKQTMathText::MTinstruction1Node::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) {
JKQTMathText::MTenvironment ev=currentEv;
setupMTenvironment(ev);
return child->toHtml(html, ev, defaultEv);
}
void JKQTMathText::MTinstruction1Node::setDrawBoxes(bool draw)
{
drawBoxes=draw;
child->setDrawBoxes(draw);
}
bool JKQTMathText::MTinstruction1Node::setupMTenvironment(JKQTMathText::MTenvironment &ev)
{
if (name=="bf" || name=="textbf" || name=="mathbf") ev.bold=true;
else if (name=="em") ev.italic=!ev.italic;
else if (name=="it" || name=="textit" || name=="mathit") ev.italic=true;
else if (name=="textcolor" || name=="mathcolor" || name=="color") ev.color=QColor(parameters.value(0, ev.color.name()));
else if (name=="ensuremath" || name=="equation") { ev.italic=true; ev.insideMath=true; }
else if (name=="sc" || name=="textsc" || name=="mathsc") ev.smallCaps=true;
else if (name=="ul" || name=="underline" || name=="underlined") ev.underlined=true;
else if (name=="ol" || name=="overline" || name=="overlined") ev.overline=true;
else if (name=="strike") ev.strike=true;
else if (name=="rm" || name=="textrm") { ev.font=JKQTMathText::MTEroman; }
else if (name=="mathrm" || name=="operatorname") { ev.font=JKQTMathText::MTEroman; ev.italic=false; }
else if (name=="text" || name=="mbox" || name=="ensuretext") { ev.insideMath=false; ev.font=JKQTMathText::MTEroman; ev.italic=false; }
else if (name=="mat") { ev.font=JKQTMathText::MTEroman; ev.italic=false; ev.bold=true; }
else if (name=="cal" || name=="textcal" || name=="mathcal") { ev.font=JKQTMathText::MTEcaligraphic; }
else if (name=="bb" || name=="textbb" || name=="mathbb") { ev.font=JKQTMathText::MTEblackboard; }
else if (name=="tt" || name=="texttt" || name=="mathtt") { ev.font=JKQTMathText::MTEtypewriter; }
else if (name=="sf" || name=="textsf" || name=="mathsf") { ev.font=JKQTMathText::MTEsans; }
else if (name=="script" || name=="textscript" || name=="mathscript") { ev.font=JKQTMathText::MTEscript; }
else if (name=="displaystyle") { ev.fontSize=ev.fontSize/0.8; }
else if (name=="scriptstyle") { ev.fontSize=ev.fontSize*0.8; }
else if (name=="scriptscriptstyle") { ev.fontSize=ev.fontSize*0.8*0.8; }
else {
return false;
}
return true;
}
JKQTMathText::MTsubscriptNode::MTsubscriptNode(JKQTMathText* parent, MTnode* child):
JKQTMathText::MTnode(parent)
{
this->child=child;
}
JKQTMathText::MTsubscriptNode::~MTsubscriptNode() {
if (child!=nullptr) delete child;
}
void JKQTMathText::MTsubscriptNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* prevNodeSize) {
JKQTMathText::MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor();
child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos);
QFontMetricsF fm(ev.getFont(parent), painter.device());
QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device());
double shift=parent->getSubShiftFactor()*tbr.height();
if (prevNodeSize!=nullptr && prevNodeSize->overallHeight-prevNodeSize->baselineHeight>shift) {
shift=-1.0*(prevNodeSize->overallHeight-prevNodeSize->baselineHeight-shift);
}
double yshift=baselineHeight-shift;
baselineHeight=shift;
strikeoutPos=fm.strikeOutPos()+yshift;
if (currentEv.italic && prevNodeSize==nullptr) width=width-double(fm.width(' '))*parent->getItalicCorrectionFactor();
}
double JKQTMathText::MTsubscriptNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* prevNodeSize) {
doDrawBoxes(painter, x, y, currentEv);
JKQTMathText::MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor();
QFontMetricsF fm(ev.getFont(parent), painter.device());
QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device());
double width=0, baselineHeight=0, overallHeight=0, strikeoutPos=0;
child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos);
double shift=parent->getSubShiftFactor()*tbr.height();
if (prevNodeSize!=nullptr && prevNodeSize->overallHeight-prevNodeSize->baselineHeight>shift) {
//qDebug()<<"oldshift="<<shift<<", prevNodeSize->overallHeight="<<prevNodeSize->overallHeight<<", prevNodeSize->baselineHeight="<<prevNodeSize->baselineHeight;
shift=-1.0*(prevNodeSize->overallHeight-prevNodeSize->baselineHeight-shift);
//qDebug()<<"newshift="<<shift;
}
double yshift=baselineHeight-shift;
//qDebug()<<"baselineHeight="<<baselineHeight<<", overallHeight="<<overallHeight<<", strikeoutPos="<<strikeoutPos;
//qDebug()<<"shift="<<shift<<", yshift="<<yshift;
double xx=x;
if (currentEv.italic && prevNodeSize==nullptr) xx=xx-double(fm.width(' '))*parent->getItalicCorrectionFactor();
return child->draw(painter, xx, y+yshift, ev);//+0.5*fm.boundingRect("A").width();
}
QString JKQTMathText::MTsubscriptNode::getTypeName() const
{
return "MTsubscriptNode";
}
bool JKQTMathText::MTsubscriptNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) {
html=html+"<sub>";
bool ok=child->toHtml(html, currentEv, defaultEv);
html=html+"</sub>";
return ok;
}
void JKQTMathText::MTsubscriptNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
child->setDrawBoxes(draw);
}
JKQTMathText::MTsqrtNode::MTsqrtNode(JKQTMathText* parent, MTnode* child, int degree):
JKQTMathText::MTnode(parent)
{
this->child=child;
this->degree=degree;
}
JKQTMathText::MTsqrtNode::~MTsqrtNode() {
if (child!=nullptr) delete child;
}
void JKQTMathText::MTsqrtNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
QFontMetricsF fm(currentEv.getFont(parent), painter.device());
child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
overallHeight=overallHeight*1.2;//+fm.ascent()*0.1;
baselineHeight=baselineHeight*1.2;//+fm.ascent()*0.1;
width=width+fm.boundingRect("A").width()*2; // 1.53
}
double JKQTMathText::MTsqrtNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
double width=0, baselineHeight=0, overallHeight=0, sp=0;
child->getSize(painter, currentEv, width, baselineHeight, overallHeight, sp);
QFont f=currentEv.getFont(parent);
QFont fsmall=f;
QFontMetricsF fm(f, painter.device());
double w=fm.boundingRect("A").width();
double a=baselineHeight*1.15;
double d=overallHeight-baselineHeight;
//painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=painter.pen();
p.setColor(currentEv.color);
p.setWidthF(qMax(JKQTMathText::ABS_MIN_LINEWIDTH,ceil(currentEv.fontSize/16.0)));
//painter.setPen(p);
QPainterPath path;
if (w>0) {
path.moveTo(x+0.1*w, y-0.4*a);
path.lineTo(x+0.33*w, y-0.4*a);
path.lineTo( x+0.66*w, y+0.5*d);
path.lineTo(x+w, y-a);
}
if (degree!=2) {
fsmall.setPointSizeF(fsmall.pointSizeF()/2.0);
fsmall.setItalic(false);
painter.setFont(fsmall);
painter.drawText(QPointF(x+0.33*w, y-0.55*a), QLocale::c().toString(degree));
}
//painter.restore();
double xnew=child->draw(painter, x+1.2*w, y, currentEv);
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(p);
if (w>0) {
path.lineTo( xnew+0.2*w, y-a);
path.lineTo(xnew+0.2*w, y-0.8*a);
painter.drawPath(path);
}
return xnew+0.33*w;
}
bool JKQTMathText::MTsqrtNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) {
html=html+"&radic;<span style=\"text-decoration:overline\">";
bool ok=child->toHtml(html, currentEv, defaultEv);
html=html+"&nbsp;</span>";
return ok;
}
void JKQTMathText::MTsqrtNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
child->setDrawBoxes(draw);
}
QString JKQTMathText::MTsqrtNode::getTypeName() const
{
return "MTsqrtNode";
}
JKQTMathText::MTfracNode::MTfracNode(JKQTMathText* parent, MTnode* child_top, MTnode* child_bottom, MTfracMode mode):
JKQTMathText::MTnode(parent)
{
this->child1=child_top;
this->child2=child_bottom;
this->mode=mode;
}
JKQTMathText::MTfracNode::~MTfracNode() {
if (child1!=nullptr) delete child1;
if (child2!=nullptr) delete child2;
}
QString JKQTMathText::MTfracNode::getTypeName() const
{
return "MTfracNode";
}
void JKQTMathText::MTfracNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
QFontMetricsF fm(currentEv.getFont(parent), painter.device());
JKQTMathText::MTenvironment ev1=currentEv;
JKQTMathText::MTenvironment ev2=currentEv;
double xh=fm.xHeight(); //tightBoundingRect("x").height();
double sp=xh;
double Ah=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device()).height();//fm.ascent();
double xw=fm.boundingRect("x").width();
if (mode==MTFMunderbrace || mode==MTFMoverbrace) {
ev2.fontSize=ev2.fontSize*parent->getUnderbraceFactor();
} else if (mode==MTFMunderset || mode==MTFMoverset) {
ev2.fontSize=ev2.fontSize*parent->getUndersetFactor();
} else if (mode==MTFMfrac || mode==MTFMsfrac) {
ev1.fontSize=ev1.fontSize*parent->getFracFactor();
ev2.fontSize=ev2.fontSize*parent->getFracFactor();
} else if (mode==MTFMtfrac || mode==MTFMstfrac) {
ev1.fontSize=ev1.fontSize*parent->getFracFactor()*0.7;
ev2.fontSize=ev2.fontSize*parent->getFracFactor()*0.7;
}
double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos1=0;
double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos2=0;
child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos1);
child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos2);
overallHeight=0;
baselineHeight=0;
width=0;
if (mode==MTFMfrac || mode==MTFMdfrac || mode==MTFMtfrac) {
//std::cout<<"\nxh="<<xh;
//std::cout<<"\n baselineHeight1="<<baselineHeight1<<", overallHeight1="<<overallHeight1;
//std::cout<<"\n baselineHeight2="<<baselineHeight2<<", overallHeight2="<<overallHeight2<<std::endl;
//overallHeight=overallHeight1+overallHeight2+sp*(2.0*parent->getFracShiftFactor());
//baselineHeight=overallHeight1+xh*(2.0*parent->getFracShiftFactor());
overallHeight=2.0*qMax(overallHeight1, overallHeight2)+sp*(2.0*parent->getFracShiftFactor());
baselineHeight=qMax(overallHeight1, overallHeight2)+xh*(2.0*parent->getFracShiftFactor());
//std::cout<<"=> baselineHeight="<<baselineHeight<<", overallHeight="<<overallHeight<<std::endl;
width=qMax(width1, width2)+ xw;
strikeoutPos=sp;
} else if (mode==MTFMstfrac || mode==MTFMsfrac) {
overallHeight=2.0*qMax(overallHeight1, overallHeight2)+sp*(2.0*parent->getFracShiftFactor());
baselineHeight=qMax(overallHeight1, overallHeight2)+xh*(2.0*parent->getFracShiftFactor());
width=width1+width2+xw;
strikeoutPos=sp;
} else if (mode==MTFMstackrel) {
//overallHeight=overallHeight1+overallHeight2+sp*(2.0*parent->getFracShiftFactor());
//baselineHeight=overallHeight1+xh*(2.0*parent->getFracShiftFactor());
overallHeight=2.0*qMax(overallHeight1, overallHeight2)+sp*(2.0*parent->getFracShiftFactor());
baselineHeight=qMax(overallHeight1, overallHeight2)+xh*(2.0*parent->getFracShiftFactor());
width=qMax(width1, width2)+ xw;
strikeoutPos=sp;
} else if (mode==MTFMunderbrace) {
overallHeight=overallHeight1+overallHeight2+Ah/2.0;
baselineHeight=baselineHeight1;
width=qMax(width1, width2)+xw;
strikeoutPos=sp;
} else if (mode==MTFMoverbrace) {
overallHeight=overallHeight1+overallHeight2+Ah/2.0;
baselineHeight=baselineHeight1+overallHeight2+Ah/2.0;
width=qMax(width1, width2)+xw;
strikeoutPos=sp;
} else if (mode==MTFMunderset) {
overallHeight=overallHeight1+overallHeight2+xh/6.0;
baselineHeight=baselineHeight1;
width=qMax(width1, width2)+xw;
strikeoutPos=sp;
} else if (mode==MTFMoverset) {
overallHeight=overallHeight1+overallHeight2+xh/6.0;
baselineHeight=baselineHeight1+overallHeight2+xh/6.0;
width=qMax(width1, width2)+xw;
strikeoutPos=sp;
}
}
double JKQTMathText::MTfracNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
QFont f=currentEv.getFont(parent);
QFontMetricsF fm(f, painter.device());
JKQTMathText::MTenvironment ev1=currentEv;
JKQTMathText::MTenvironment ev2=currentEv;
double xh=parent->getTightBoundingRect(f, "x", painter.device()).height(); //fm.xHeight();
double xw=fm.boundingRect("x").width();
double lw=qMax(0.0,ceil(currentEv.fontSize/16.0));//fm.lineWidth();
double Ah=parent->getTightBoundingRect(f, "M", painter.device()).height();//fm.ascent();
double bw=Ah/2.0;
if (mode==MTFMunderbrace || mode==MTFMoverbrace) {
ev2.fontSize=ev2.fontSize*parent->getUnderbraceFactor();
} else if (mode==MTFMunderset || mode==MTFMoverset) {
ev2.fontSize=ev2.fontSize*parent->getUndersetFactor();
} else if (mode==MTFMfrac || mode==MTFMsfrac) {
ev1.fontSize=ev1.fontSize*parent->getFracFactor();
ev2.fontSize=ev2.fontSize*parent->getFracFactor();
} else if (mode==MTFMtfrac || mode==MTFMstfrac) {
ev1.fontSize=ev1.fontSize*parent->getFracFactor()*0.7;
ev2.fontSize=ev2.fontSize*parent->getFracFactor()*0.7;
}
double width1=0, baselineHeight1=0, overallHeight1=0;//, strikeoutPos1=0;
double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos=0;
child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos);
child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos);
double ascent1=baselineHeight1;
double descent1=overallHeight1-baselineHeight1;
double ascent2=baselineHeight2;
double descent2=overallHeight2-baselineHeight2;
double yline=y-xh*0.5;
//double overallHeight=overallHeight1+overallHeight2+xh;
//double baselineHeight=3.0*xh/2.0+overallHeight1;
double width=qMax(width1, width2);
QPen p=painter.pen();
p.setColor(ev1.color);
p.setStyle(Qt::SolidLine);
p.setWidthF(qMax(JKQTMathText::ABS_MIN_LINEWIDTH, lw));
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(p);
if (mode==MTFMfrac || mode==MTFMdfrac || mode==MTFMtfrac) {
QLineF l(x+xw/4.0, yline, x+width+xw/2.0, yline);
if (l.length()>0) painter.drawLine(l);
child1->draw(painter, x+xw/2.0+(width-width1)/2.0, yline-xh*(parent->getFracShiftFactor())-descent1, ev1);
child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->getFracShiftFactor())+ascent2, ev2);
} else if (mode==MTFMstfrac || mode==MTFMsfrac) {
child1->draw(painter, x, yline-descent1, ev1);
child2->draw(painter, x+width+xw, yline+ascent2, ev2);
QLineF l(x+width+1.2*xw, yline-descent1-ascent1, x+width-0.2*xw, yline+ascent1+descent1);
if (l.length()>0) painter.drawLine(l);
} else if (mode==MTFMstackrel) {
child1->draw(painter, x+xw/2.0+(width-width1)/2.0, yline-xh*(parent->getFracShiftFactor())-descent1, ev1);
child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->getFracShiftFactor())+ascent2, ev2);
} else if (mode==MTFMunderset) {
child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1);
child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y+descent1+xh/6.0+ascent2, ev2);
} else if (mode==MTFMunderbrace) {
double ybrace=y+descent1+bw/2.0;
QPainterPath path=makeHBracePath(x+xw/2.0+(width1)/2.0, ybrace, width, bw);
painter.drawPath(path);
child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1);
child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y+descent1+bw+ascent2, ev2);
} else if (mode==MTFMoverset) {
child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1);
child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y-ascent1-xh/6.0-descent2, ev2);
} else if (mode==MTFMoverbrace) {
double ybrace=y-ascent1-bw/2.0;
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.translate(x+xw/2.0+(width1)/2.0, ybrace);
painter.rotate(180);
QPainterPath path=makeHBracePath(0,0, width, bw);
painter.drawPath(path);
}
child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1);
child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y-ascent1-bw-descent2, ev2);
}
if (mode==MTFMstackrel) return x+width+ xw;
else if (mode==MTFMstfrac || mode==MTFMsfrac) return x+width+width2+xw;
else return x+width+xw;
}
bool JKQTMathText::MTfracNode::toHtml(QString &/*html*/, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/) {
bool ok=false;
return ok;
}
void JKQTMathText::MTfracNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
child1->setDrawBoxes(draw);
child2->setDrawBoxes(draw);
}
JKQTMathText::MTmatrixNode::MTmatrixNode(JKQTMathText* parent, QVector<QVector<MTnode*> > children):
JKQTMathText::MTnode(parent)
{
this->lines=children.size();
this->columns=0;
for (int i=0; i<children.size(); i++) {
if (children[i].size()>this->columns) this->columns=children[i].size();
}
this->children=children;
}
JKQTMathText::MTmatrixNode::~MTmatrixNode() {
for (int i=0; i<children.size(); i++) {
for (int j=0; j<children[i].size(); j++) {
delete children[i].at(j);
}
}
children.clear();
}
QString JKQTMathText::MTmatrixNode::getTypeName() const
{
return "MTmatrixNode";
}
void JKQTMathText::MTmatrixNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
QFontMetricsF fm(currentEv.getFont(parent), painter.device());
JKQTMathText::MTenvironment ev1=currentEv;
double xh=fm.strikeOutPos();//fm.xHeight();
//double Ah=fm.ascent();
double xw=fm.boundingRect("x").width();
//ev1.fontSize=ev1.fontSize*parent->getFracFactor();
QVector<double> colwidth, rowheight;
//QVector<QVector<double> > widths, heights, baselines;
double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos1=0;
//widths.resize(lines);
colwidth.resize(columns); for (int i=0; i<columns; i++) colwidth[i]=0;
rowheight.resize(lines);
//heights=baselines=widths;
for (int i=0; i<lines; i++) {
rowheight[i]=0;
//widths[i].resize(columns);
//baselines[i]=heights[i]=widths[i];
for (int j=0; j<children[i].size(); j++) {
children[i].at(j)->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos1);
/*widths[i].operator[](j)=width1;
baselines[i].operator[](j)=baselineHeight;
heights[i].operator[](j)=overallHeight1;*/
if (overallHeight1>rowheight[i]) rowheight[i]=overallHeight1;
if (width1>colwidth[j]) colwidth[j]=width1;
}
}
overallHeight=(lines-1)*xw/2.0;
width=columns*xw;
for (int i=0; i<columns; i++) width=width+colwidth[i];
for (int i=0; i<lines; i++) overallHeight=overallHeight+rowheight[i];
baselineHeight=overallHeight/2.0+xh;
strikeoutPos=xh;
}
double JKQTMathText::MTmatrixNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
QFontMetricsF fm(currentEv.getFont(parent), painter.device());
JKQTMathText::MTenvironment ev1=currentEv;
double xh=fm.strikeOutPos();//fm.xHeight();
//double Ah=fm.ascent();
double xw=fm.boundingRect("x").width();
//ev1.fontSize=ev1.fontSize;*parent->getFracFactor();
QVector<double> colwidth, rowheight, rowascent;
//QVector<QVector<double> > widths, heights, baselines;
double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos=0;
//widths.resize(lines);
colwidth.resize(columns); for (int i=0; i<columns; i++) colwidth[i]=0;
rowheight.resize(lines);
rowascent.resize(lines);
//heights=baselines=widths;
for (int i=0; i<lines; i++) {
rowheight[i]=0;
rowascent[i]=0;
//widths[i].resize(columns);
//baselines[i]=heights[i]=widths[i];
for (int j=0; j<children[i].size(); j++) {
if (children[i].at(j)!=nullptr) children[i].at(j)->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos);
/*widths[i].operator[](j)=width1;
baselines[i].operator[](j)=baselineHeight;
heights[i].operator[](j)=overallHeight1;*/
if (overallHeight1>rowheight[i]) rowheight[i]=overallHeight1;
if (baselineHeight1>rowascent[i]) rowascent[i]=baselineHeight1;
if (width1>colwidth[j]) colwidth[j]=width1;
}
}
double overallHeight=(lines-1)*xw/2.0;
double width=(columns)*xw;
for (int i=0; i<columns; i++) width=width+colwidth[i];
for (int i=0; i<lines; i++) overallHeight=overallHeight+rowheight[i];
double baselineHeight=overallHeight/2.0+xh;
double xx=x;
double yy=y-baselineHeight;
if (lines>0) yy=yy+rowascent[0];
for (int i=0; i<lines; i++) {
xx=x;
for (int j=0; j<children[i].size(); j++) {
children[i].at(j)->draw(painter, xx, yy, ev1);
xx=xx+colwidth[j]+xw;
}
if (i<lines-1) yy=yy+(rowheight[i]-rowascent[i])+xw/2.0+rowascent[i+1];
}
return x+width;
}
bool JKQTMathText::MTmatrixNode::toHtml(QString &/*html*/, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/)
{
return false;
}
void JKQTMathText::MTmatrixNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
for (int i=0; i<lines; i++) {
for (int j=0; j<children[i].size(); j++) {
children[i].at(j)->setDrawBoxes(draw);
}
}
}
JKQTMathText::MTdecoratedNode::MTdecoratedNode(JKQTMathText* parent, MTdecoration decoration, MTnode* child):
JKQTMathText::MTnode(parent)
{
this->child=child;
this->decoration=decoration;
}
JKQTMathText::MTdecoratedNode::~MTdecoratedNode() {
if (child!=nullptr) delete child;
}
void JKQTMathText::MTdecoratedNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
QFontMetricsF fm(currentEv.getFont(parent), painter.device());
double wc=fm.boundingRect("A").width();
double dheightfactor=1.0+parent->getDecorationHeightFactor()*2.0;
child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
overallHeight=overallHeight*dheightfactor;
baselineHeight=baselineHeight*dheightfactor;
width=width+0.3*wc;
}
double JKQTMathText::MTdecoratedNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
MTenvironment ev=currentEv;
double width=0, baselineHeight=0, overallHeight=0, strikeoutPos=0;
child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos);
QFontMetricsF fm(ev.getFont(parent), painter.device());
double w=width;
double wc=fm.boundingRect("A").width();
//double ll=wc*0.8;
double a=baselineHeight;
//double d=overallHeight-baselineHeight;
double dheightfactor=parent->getDecorationHeightFactor();
double dpos=y-a*(1.0+dheightfactor);
double dposb=y+qMax((overallHeight-baselineHeight)*(1.0+dheightfactor), fm.xHeight()*dheightfactor);
double deltax=0;//(wc-ll)/2.0;
double dheight=dheightfactor*a;
if (ev.italic) deltax+=0.1*fm.boundingRect("A").width();
QPen pold=painter.pen();
QPen p=pold;
p.setColor(ev.color);
p.setWidthF(qMax(JKQTMathText::ABS_MIN_LINEWIDTH, fm.lineWidth()));//ceil(currentEv.fontSize/16.0));
if (decoration==MTDbar) ev.overline=true;
double xnew=child->draw(painter, x, y, ev);
if (decoration==MTDvec) {
painter.setPen(p);
QPolygonF poly;
poly<<QPointF(x+deltax, dpos)<<QPointF(xnew+deltax-0.2*wc, dpos)<<QPointF(xnew-0.4*wc+deltax, dpos-dheight/2.0);
painter.drawPolyline(poly);
painter.setPen(pold);
} else if (decoration==MTDoverline) {
painter.setPen(p);
QLineF l(x+deltax, dpos, xnew+deltax-0.2*wc, dpos);
if (l.length()>0) painter.drawLine(l);
painter.setPen(pold);
} else if (decoration==MTDdoubleoverline) {
painter.setPen(p);
QLineF l(x+deltax, dpos, xnew+deltax-0.2*wc, dpos);
if (l.length()>0) painter.drawLine(l);
l=QLineF(x+deltax, dpos-2.0*p.widthF(), xnew+deltax-0.2*wc, dpos-2.0*p.widthF());
if (l.length()>0) painter.drawLine(l);
painter.setPen(pold);
} else if (decoration==MTDunderline) {
painter.setPen(p);
QLineF l(x+deltax, dposb, xnew+deltax-0.2*wc, dposb);
if (l.length()>0) painter.drawLine(l);
painter.setPen(pold);
} else if (decoration==MTDdoubleunderline) {
painter.setPen(p);
QLineF l(x+deltax, dposb, xnew+deltax-0.2*wc, dposb);
if (l.length()>0) painter.drawLine(l);
l=QLineF(x+deltax, dposb+2.0*p.widthF(), xnew+deltax-0.2*wc, dposb+2.0*p.widthF());
if (l.length()>0) painter.drawLine(l);
painter.setPen(pold);
} else if (decoration==MTDarrow) {
painter.setPen(p);
QLineF l(x+deltax, dpos+dheight/2.0, xnew+deltax-0.2*wc, dpos+dheight/2.0);
if (l.length()>0) painter.drawLine(l);
QPolygonF poly;
poly<<QPointF(xnew+deltax-0.4*wc, dpos)<<QPointF(xnew+deltax-0.2*wc, dpos+dheight/2.0)<<QPointF(xnew+deltax-0.4*wc, dpos+dheight);
painter.drawPolyline(poly);
painter.setPen(pold);
/*} else if (decoration==MTDbar) {
painter.setPen(p);
painter.drawLine(QLineF(x+0.2*wc+deltax, dpos, xnew+0.2*wc+deltax, dpos);
painter.setPen(pold);*/
} else if (decoration==MTDhat) {
painter.setPen(p);
QPolygonF poly;
poly<<QPointF(x+w/2.0-0.35*wc+deltax, dpos+dheight/2.0)<<QPointF(x+w/2.0+deltax, dpos)<<QPointF(x+w/2.0+0.35*wc+deltax, dpos+dheight/2.0);
painter.drawPolyline(poly);
painter.setPen(pold);
} else if (decoration==MTDtilde) {
painter.setPen(p);
QPainterPath path;
double x0=x+deltax;
double x1=xnew+deltax-0.2*wc;
path.moveTo(x0, dpos);
path.cubicTo((x0+x1)/2.0, dpos+dheight, (x0+x1)/2.0, dpos-dheight , x1, dpos);
painter.drawPath(path);
painter.setPen(pold);
} else if (decoration==MTDdot) {
p.setWidthF(0.01);
painter.setPen(p);
QBrush b=painter.brush();
QBrush bold=b;
b.setColor(ev.color);
b.setStyle(Qt::SolidPattern);
painter.setBrush(b);
painter.drawEllipse(QPointF(x+w/2.0+deltax, dpos), wc/10.0, wc/10.0);
painter.setBrush(bold);
painter.setPen(pold);
} else if (decoration==MTDddot) {
p.setWidthF(0.01);
painter.setPen(p);
QBrush b=painter.brush();
QBrush bold=b;
b.setColor(ev.color);
b.setStyle(Qt::SolidPattern);
painter.setBrush(b);
painter.drawEllipse(QPointF(x+w/2.0-0.2*wc+deltax, dpos), wc/10.0, wc/10.0);
painter.drawEllipse(QPointF(x+w/2.0+0.2*wc+deltax, dpos), wc/10.0, wc/10.0);
painter.setBrush(bold);
painter.setPen(pold);
painter.setBrush(bold);
}
return xnew+0.3*wc;
}
bool JKQTMathText::MTdecoratedNode::toHtml(QString &/*html*/, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/) {
//QString f;
//JKQTMathText::MTenvironment ev=currentEv;
//bool ok=child->toHtml(html, ev, defaultEv);
return false;
}
void JKQTMathText::MTdecoratedNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
child->setDrawBoxes(draw);
}
QString JKQTMathText::MTdecoratedNode::getTypeName() const
{
return "MTdecoratedNode";
}
JKQTMathText::MTsuperscriptNode::MTsuperscriptNode(JKQTMathText* parent, MTnode* child):
JKQTMathText::MTnode(parent)
{
this->child=child;
}
JKQTMathText::MTsuperscriptNode::~MTsuperscriptNode() {
if (child!=nullptr) delete child;
}
void JKQTMathText::MTsuperscriptNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* prevNodeSize) {
JKQTMathText::MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor();
QFontMetricsF fm(currentEv.getFont(parent), painter.device());
QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device());
child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos);
double shift=parent->getSuperShiftFactor()*tbr.height();
if (prevNodeSize!=nullptr && prevNodeSize->baselineHeight>tbr.height()) {
shift=prevNodeSize->baselineHeight-(overallHeight-baselineHeight)-shift;
}
double yshift=shift+overallHeight-baselineHeight;
baselineHeight=overallHeight=overallHeight+shift;
strikeoutPos=strikeoutPos-yshift;
if (currentEv.italic && prevNodeSize==nullptr) width=width+double(fm.width(' '))*parent->getItalicCorrectionFactor();
}
double JKQTMathText::MTsuperscriptNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* prevNodeSize) {
doDrawBoxes(painter, x, y, currentEv);
JKQTMathText::MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor();
double cWidth, cBaselineHeight, cOverallHeight, cStrikeoutPos;
child->getSize(painter, ev, cWidth, cBaselineHeight, cOverallHeight, cStrikeoutPos);
QFontMetricsF fm(currentEv.getFont(parent), painter.device());
QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device());
double shift=parent->getSuperShiftFactor()*tbr.height();
if (prevNodeSize!=nullptr && prevNodeSize->baselineHeight>tbr.height()) {
shift=prevNodeSize->baselineHeight-(cOverallHeight-cBaselineHeight)-shift;
}
double yshift=shift+cOverallHeight-cBaselineHeight;
double xx=x;
if (currentEv.italic && prevNodeSize==nullptr) xx=xx+double(fm.width(' '))*parent->getItalicCorrectionFactor();
return child->draw(painter, xx, y-yshift, ev);//+0.5*fm.boundingRect("A").width();
}
QString JKQTMathText::MTsuperscriptNode::getTypeName() const
{
return "MTsuperscriptNode";
}
bool JKQTMathText::MTsuperscriptNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv)
{
html=html+"<sup>";
bool ok=child->toHtml(html, currentEv, defaultEv);
html=html+"</sup>";
return ok;
}
void JKQTMathText::MTsuperscriptNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
child->setDrawBoxes(draw);
}
JKQTMathText::MTbraceNode::MTbraceNode(JKQTMathText* parent, const QString& openbrace, const QString& closebrace, MTnode* child, bool showRightBrace):
JKQTMathText::MTnode(parent)
{
this->child=child;
this->openbrace=openbrace;
this->closebrace=closebrace;
this->showRightBrace=showRightBrace;
}
JKQTMathText::MTbraceNode::~MTbraceNode() {
if (child!=nullptr) delete child;
}
void JKQTMathText::MTbraceNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
JKQTMathText::MTenvironment ev=currentEv;
child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
double bracewidth=0, braceheight=0;
getBraceWidth(painter, ev, baselineHeight, overallHeight, bracewidth, braceheight);
bracewidth=bracewidth/parent->getBraceShrinkFactor();
baselineHeight=/*qMin(baselineHeight, braceheight)*/ baselineHeight*parent->getBraceFactor();
overallHeight=qMax(overallHeight, braceheight)*parent->getBraceFactor(); //fm.height();
width=width+bracewidth*2.0;
}
double JKQTMathText::MTbraceNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
//std::cout<<"drawing brace-node: '"<<openbrace.toStdString()<<"' ... '"<<closebrace.toStdString()<<"'\n";
doDrawBoxes(painter, x, y, currentEv);
JKQTMathText::MTenvironment ev=currentEv;
double width=0;
double baselineHeight=0;
double overallHeight=0, strikeoutPos=0;
child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
double bracewidth=0, braceheight=0;
getBraceWidth(painter, ev, baselineHeight, overallHeight, bracewidth, braceheight);
double cWidth=0;
double cBaselineHeight=0;
double cOverallHeight=0, cstrikeoutPos=0;
getSize(painter, currentEv, cWidth, cBaselineHeight, cOverallHeight, cstrikeoutPos);
double lw=qMax(0.25,ceil(currentEv.fontSize/12.0));//fm.lineWidth();
double xnew=x+lw;
QPen pold=painter.pen();
QPen p=pold;
p.setWidthF(lw);
p.setColor(currentEv.color);
painter.setPen(p);
double brace_fraction=0.85;
if (openbrace=="(") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+brace_fraction*bracewidth, y1);
path.cubicTo(xnew, (y1+y2)/2.0+fabs(y1-y2)/6.0, xnew, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xnew+brace_fraction*bracewidth, y2);
painter.drawPath(path);
} else if (openbrace=="[") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+brace_fraction*bracewidth, y1);
path.lineTo(xnew+lw/2.0, y1);
path.lineTo(xnew+lw/2.0, y2);
path.lineTo(xnew+brace_fraction*bracewidth, y2);
painter.drawPath(path);
} else if (openbrace=="{") {
QPainterPath path=makeHBracePath(0,0,cOverallHeight, bracewidth*brace_fraction);
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.translate(xnew+bracewidth*(1.0-brace_fraction), y-cBaselineHeight+cOverallHeight/2.0);
painter.rotate(90);
painter.drawPath(path);
} else if (openbrace=="_") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+brace_fraction*bracewidth, y1);
path.lineTo(xnew, y1);
path.lineTo(xnew, y2);
painter.drawPath(path);
} else if (openbrace=="~") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew, y1);
path.lineTo(xnew, y2);
path.lineTo(xnew+brace_fraction*bracewidth, y2);
painter.drawPath(path);
} else if (openbrace=="|") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
QLineF l(xnew+brace_fraction*bracewidth, y1, xnew+brace_fraction*bracewidth, y2);
if (l.length()>0) painter.drawLine(l);
painter.drawPath(path);
} else if (openbrace=="#" || openbrace=="||") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
QLineF l(xnew+brace_fraction*bracewidth, y1, xnew+brace_fraction*bracewidth, y2);
if (l.length()>0) painter.drawLine(l);
l=QLineF(xnew+brace_fraction*bracewidth-1.5*lw, y1, xnew+brace_fraction*bracewidth-1.5*lw, y2);
if (l.length()>0) painter.drawLine(l);
} else if (openbrace=="<") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+brace_fraction*bracewidth, y1);
path.lineTo(xnew, (y2+y1)/2.0);
path.lineTo(xnew+brace_fraction*bracewidth, y2);
painter.drawPath(path);
}
painter.setPen(pold);
xnew= child->draw(painter, xnew+bracewidth/parent->getBraceShrinkFactor()-lw, y, currentEv)+lw;
if (showRightBrace) {
painter.setPen(p);
if (closebrace==")") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1);
path.cubicTo(xnew+bracewidth, (y1+y2)/2.0+fabs(y1-y2)/6.0, xnew+bracewidth, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xnew+(1.0-brace_fraction)*bracewidth, y2);
painter.drawPath(path);
} else if (closebrace=="]") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1);
path.lineTo(xnew+bracewidth-lw/2.0, y1);
path.lineTo(xnew+bracewidth-lw/2.0, y2);
path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2);
painter.drawPath(path);
} else if (closebrace=="}") {
QPainterPath path=makeHBracePath(0,0,cOverallHeight, bracewidth*brace_fraction);
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.translate(xnew+bracewidth*brace_fraction, y-cBaselineHeight+cOverallHeight/2.0);
painter.rotate(270);
painter.drawPath(path);
} else if (closebrace=="_") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1);
path.lineTo(xnew+bracewidth, y1);
path.lineTo(xnew+bracewidth, y2);
painter.drawPath(path);
} else if (closebrace=="~") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+bracewidth, y1);
path.lineTo(xnew+bracewidth, y2);
path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2);
painter.drawPath(path);
} else if (closebrace=="|") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
QLineF l(xnew+(1.0-brace_fraction)*bracewidth, y1, xnew+(1.0-brace_fraction)*bracewidth, y2);
if (l.length()>0) painter.drawLine(l);
painter.drawPath(path);
} else if (closebrace=="#" || closebrace=="||") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
QLineF l(xnew+(1.0-brace_fraction)*bracewidth, y1, xnew+(1.0-brace_fraction)*bracewidth, y2);
if (l.length()>0) painter.drawLine(l);
l=QLineF(xnew+(1.0-brace_fraction)*bracewidth+1.5*lw, y1, xnew+(1.0-brace_fraction)*bracewidth+1.5*lw, y2);
if (l.length()>0) painter.drawLine(l);
} else if (closebrace==">") {
QPainterPath path;
double y1=y+(cOverallHeight-cBaselineHeight);
double y2=y-cBaselineHeight;
path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1);
path.lineTo(xnew+bracewidth, (y2+y1)/2.0);
path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2);
painter.drawPath(path);
}
painter.setPen(pold);
}
//qDebug()<<" ==> "<<bc<<fm.boundingRect(bc).width();
return xnew+bracewidth/parent->getBraceShrinkFactor()-lw;
}
bool JKQTMathText::MTbraceNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) {
QString ob=openbrace;
QString cb=closebrace;
if (ob=="<") ob="&lang;";
else if (ob=="_") ob="&lfloor;";
else if (ob=="~") ob="&lceil;";
else if (ob=="||" || ob=="#") ob="||";
if (cb=="<") cb="&rang;";
else if (cb=="_") cb="&rfloor;";
else if (cb=="~") cb="&rceil;";
else if (cb=="||" || cb=="#") cb="||";
html=html+ob;
bool ok=child->toHtml(html, currentEv, defaultEv);
html=html+cb;
return ok;
}
void JKQTMathText::MTbraceNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
child->setDrawBoxes(draw);
}
QString JKQTMathText::MTbraceNode::getTypeName() const
{
return QLatin1String("MTbraceNode(")+openbrace+" "+closebrace+")";
}
void JKQTMathText::MTbraceNode::getBraceWidth(QPainter &/*painter*/, JKQTMathText::MTenvironment ev, double /*baselineHeight*/, double overallHeight, double &bracewidth, double &braceheight)
{
/*QFont evf=ev.getFont(parent);
if (ev.insideMath) evf.setItalic(false);
ev.italic=false;
while (ev.fontSize<10*parent->getFontSize()) {
const QFontMetricsF fme(evf, painter.device());
if (fme.ascent()>overallHeight) break;
ev.fontSize+=0.5;
evf.setPointSizeF(ev.fontSize);
}
ev.fontSize=ev.fontSize*parent->getBraceFactor();
evf.setPointSizeF(ev.fontSize);
QFontMetricsF fm(evf, painter.device());
QString bc="_X";
bracewidth=fm.width("I")*parent->getBraceShrinkFactor();
braceheight=parent->getTBR(evf, bc, painter.device()).height();*/
double lw=qMax(0.25,ceil(ev.fontSize/12.0));
braceheight=overallHeight*parent->getBraceFactor();
bracewidth=0.6*pow(braceheight, 0.6);
if (openbrace=="{" || closebrace=="}") bracewidth=qMax(bracewidth, lw*3.5);
}
JKQTMathText::MTlistNode::MTlistNode(JKQTMathText* parent):
JKQTMathText::MTnode(parent)
{
nodes.clear();
// these operations cause sub/sup script to be typeset over/under the operator, not right besides!
subsupOperations<<"sum"<<"prod"<<"coprod"
<<"bigcap"<<"bigcup"<<"bigvee"<<"bighat"
<<"int"<<"iint"<<"iiint"<<"oint"<<"oiint"<<"oiiint"
<<"mod"<<"median"<<"max"<<"min"<<"argmax"<<"argmin"<<"sup"<<"inf"
<<"liminf"<<"limsup"<<"lim"<<"max"<<"min";
}
JKQTMathText::MTlistNode::~MTlistNode() {
for (int i=0; i<nodes.size(); i++) {
delete nodes[i];
}
nodes.clear();
}
QString JKQTMathText::MTlistNode::getTypeName() const
{
return "MTlistNode";
}
void JKQTMathText::MTlistNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
width=0;
overallHeight=0;
baselineHeight=0;
strikeoutPos=0;
QFontMetricsF fm(currentEv.getFont(parent));
//QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device());
double xnew=0;
bool wasBrace=false;
for (int i=0; i<nodes.size(); i++) {
MTnodeSize prevNodeSize;
MTnodeSize* prevNodeSizePtr=nullptr;
if (i>0 && wasBrace) {
nodes[i-1]->getSize(painter, currentEv, prevNodeSize.width, prevNodeSize.baselineHeight, prevNodeSize.overallHeight, prevNodeSize.strikeoutPos);
prevNodeSizePtr=&prevNodeSize;
}
bool doDraw=true;
MTsymbolNode* smb=dynamic_cast<MTsymbolNode*>(nodes[i]);
// if we find a subscript/superscript node we check whether the next node is super/subscript
// if so, we typeset them at the same x-psotion, so sub/superscripts appear correctly
if (dynamic_cast<MTsuperscriptNode*>(nodes[i])) {
if (i+1<nodes.size()) { // is there one mor node behind?
if (dynamic_cast<MTsubscriptNode*>(nodes[i+1])) { // is this subscript?
double w1, w2, oh, bh, sp;
nodes[i]->getSize(painter, currentEv, w1, bh, oh, sp, prevNodeSizePtr);
if (bh>baselineHeight) {
overallHeight=overallHeight+bh-baselineHeight;
baselineHeight=bh;
strikeoutPos=sp;
}
if (baselineHeight+oh-bh>overallHeight) {
overallHeight=baselineHeight+oh-bh;
strikeoutPos=sp;
}
i++;
nodes[i]->getSize(painter, currentEv, w2, bh, oh, sp, prevNodeSizePtr);
//qDebug()<<"super_sub: sub: "<<nodes[i]->getTypeName()<<" w2="<<w2<<" bh"<<bh<<" oh="<<oh<<" sp="<<sp;
if (bh>baselineHeight) {
overallHeight=overallHeight+bh-baselineHeight;
baselineHeight=bh;
strikeoutPos=sp;
}
if (baselineHeight+oh-bh>overallHeight) {
overallHeight=baselineHeight+oh-bh;
strikeoutPos=sp;
}
xnew+=qMax(w1+fm.width(" "), w2);
doDraw=false;
//qDebug()<<"### super+sub";
//qDebug()<<"### subsupop: super+sub overallHeight="<<overallHeight<<" baselineHeight="<<baselineHeight;
}
}
} else if (dynamic_cast<MTsubscriptNode*>(nodes[i])) {
if (i+1<nodes.size()) { // is there one mor node behind?
if (dynamic_cast<MTsuperscriptNode*>(nodes[i+1])) { // is this subscript?
double w1, w2, oh, bh, sp;
nodes[i]->getSize(painter, currentEv, w1, bh, oh, sp, prevNodeSizePtr);
if (bh>baselineHeight) {
overallHeight=overallHeight+bh-baselineHeight;
baselineHeight=bh;
strikeoutPos=sp;
}
if (baselineHeight+oh-bh>overallHeight) {
overallHeight=baselineHeight+oh-bh;
strikeoutPos=sp;
}
i++;
nodes[i]->getSize(painter, currentEv, w2, bh, oh, sp, prevNodeSizePtr);
if (bh>baselineHeight) {
overallHeight=overallHeight+bh-baselineHeight;
baselineHeight=bh;
strikeoutPos=sp;
}
if (baselineHeight+oh-bh>overallHeight) {
overallHeight=baselineHeight+oh-bh;
strikeoutPos=sp;
}
xnew+=qMax(w1, w2+fm.width(" "));
doDraw=false;
//qDebug()<<"### sub+super";
//qDebug()<<"### subsupop: sub+super1 overallHeight="<<overallHeight<<" baselineHeight="<<baselineHeight;
}
}
} else if (smb) {
QString s=smb->getSymbolName();
if (subsupOperations.contains(s)) {
MTsubscriptNode* subn=nullptr;
if (i+1<nodes.size()) subn=dynamic_cast<MTsubscriptNode*>(nodes[i+1]);
MTsuperscriptNode* supn=nullptr;
if (i+2<nodes.size()) supn=dynamic_cast<MTsuperscriptNode*>(nodes[i+2]);
//std::cout<<"symbol ='"<<s.toStdString()<<"' subn="<<subn<<" supn="<<supn<<"\n";
if (subn && supn) { // is this subscript and superscript?
MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor();
double w1=0, w2=0, w3=0;
double oh1=0, oh2=0, oh3=0;
double bh1=0, bh2=0, bh3=0;
double sp1=0, sp2=0, sp3=0;
nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp1);
//qDebug()<<"sub_super: node: "<<nodes[i]->getTypeName()<<" w1="<<w1<<" bh"<<bh1<<" oh="<<oh1<<" sp="<<sp1;
subn->getChild()->getSize(painter, ev, w2, bh2, oh2, sp2);
//qDebug()<<"sub_super: node: "<<subn->getTypeName()<<" w2="<<w2<<" bh2"<<bh2<<" oh2="<<oh2<<" sp2="<<sp2;
supn->getChild()->getSize(painter, ev, w3, bh3, oh3, sp3);
//qDebug()<<"sub_super: node: "<<supn->getTypeName()<<" w3="<<w3<<" bh3"<<bh3<<" oh3="<<oh3<<" sp3="<<sp3;
//double d1=oh1-bh1;
//double d2=oh2-bh2;
//double d3=oh3-bh3;
double w=qMax(qMax(w1, w2), w3)+fm.width(" ");
double oh=oh1+oh2+oh3;
double bh=bh1+oh3;
if (oh>overallHeight) overallHeight=oh;
if (bh>baselineHeight) { baselineHeight=bh; strikeoutPos=sp1; }
if (oh-bh>overallHeight-baselineHeight) {
overallHeight=baselineHeight+oh-bh;
}
i++;
i++;
doDraw=false;
xnew+=w;
//qDebug()<<"### subsupop: sub+super2 overallHeight="<<overallHeight<<" baselineHeight="<<baselineHeight;
/*} else if (subn && supn) { // is this subscript and superscript?
MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor();
double w1=0, w2=0, w3=0;
double oh1=0, oh2=0, oh3=0;
double bh1=0, bh2=0, bh3=0;
double sp1=0, sp2=0, sp3=0;
nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp1);
supn->getChild()->getSize(painter, ev, w3, bh3, oh3, sp3);
//double d1=oh1-bh1;
//double d2=oh2-bh2;
//double d3=oh3-bh3;
double w=qMax(w1, w3)+fm.width(" ");
double oh=oh1+oh3;
double bh=bh1+oh3;
if (oh>overallHeight) overallHeight=oh;
if (bh>baselineHeight) { baselineHeight=bh; strikeoutPos=sp1; }
if (oh-bh>overallHeight-baselineHeight) {
overallHeight=baselineHeight+oh-bh;
}
i++;
i++;
doDraw=false;
xnew+=w;
//qDebug()<<"### subsupop: sub+super";*/
} else if (subn) { // is this subscript?
MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor();
double w1=0, w2=0;
double oh1=0, oh2=0;
double bh1=0, bh2=0;
double sp1=0, sp2=0;//, sp3=0;
nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp1);
subn->getChild()->getSize(painter, ev, w2, bh2, oh2, sp2);
//double d1=oh1-bh1;
//double d2=oh2-bh2;
double oh=oh1+oh2;
double sh=oh1-bh1+oh2*1.1;
if (oh>overallHeight) overallHeight=oh;
if (bh1>baselineHeight) baselineHeight=bh1;
if (sh>overallHeight-baselineHeight) {
overallHeight=baselineHeight+sh;
}
double w=qMax(w1, w2)+fm.width(" ");
i++;
doDraw=false;
xnew+=w;
//qDebug()<<"### subsupop: sub overallHeight="<<overallHeight<<" baselineHeight="<<baselineHeight;
}
}
}
if (i<nodes.size() && doDraw) {
double w, oh, bh, sp;
nodes[i]->getSize(painter, currentEv, w, bh, oh, sp, prevNodeSizePtr);
//qDebug()<<"### else: bh="<<bh<<" baselineHeight="<<baselineHeight<<" oh="<<oh<<" overallHeight="<<overallHeight;
if (bh>baselineHeight) {
overallHeight=overallHeight+bh-baselineHeight;
baselineHeight=bh;
strikeoutPos=sp;
}
if (baselineHeight+oh-bh>overallHeight) {
overallHeight=baselineHeight+oh-bh;
strikeoutPos=sp;
}
//qDebug()<<"### subsupop: else overallHeight="<<overallHeight<<" baselineHeight="<<baselineHeight;
xnew+=w;
//qDebug()<<i<<xnew;
}
wasBrace=dynamic_cast<MTbraceNode*>(nodes[i]);
}
width=xnew;
}
double JKQTMathText::MTlistNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
double ynew=y;
double xnew=x;
//qDebug()<<"listNode: "<<currentEv.fontSize;
QFontMetricsF fm(currentEv.getFont(parent));
bool wasBrace=false;
for (int i=0; i<nodes.size(); i++) {
bool doDraw=true;
MTnodeSize prevNodeSize;
MTnodeSize* prevNodeSizePtr=nullptr;
if (i>0 && wasBrace) {
nodes[i-1]->getSize(painter, currentEv, prevNodeSize.width, prevNodeSize.baselineHeight, prevNodeSize.overallHeight, prevNodeSize.strikeoutPos);
prevNodeSizePtr=&prevNodeSize;
}
MTsymbolNode* smb=dynamic_cast<MTsymbolNode*>(nodes[i]);
// if we find a subscript/superscript node we check whether the next node is super/subscript
// if so, we typeset them at the same x-psotion, so sub/superscripts appear correctly
if (dynamic_cast<MTsuperscriptNode*>(nodes[i])) {
if (i+1<nodes.size()) { // is there one mor node behind?
if (dynamic_cast<MTsubscriptNode*>(nodes[i+1])) { // is this subscript?
//painter.setPen(QPen("red"));
//painter.drawEllipse(xnew-4,ynew+shift-(ccOverallHeight-ccBaselineHeight)-4,8,8);
double xnew1=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr);
i++;
//painter.setPen(QPen("magenta"));
//painter.drawEllipse(xnew-4,ynew-4,8,8);
double xnew2=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr);
//i++;
xnew=qMax(xnew1, xnew2);
doDraw=false;
}
}
} else if (dynamic_cast<MTsubscriptNode*>(nodes[i])) {
if (i+1<nodes.size()) { // is there one mor node behind?
if (dynamic_cast<MTsuperscriptNode*>(nodes[i+1])) { // is this subscript?
//painter.setPen(QPen("red"));
//painter.drawEllipse(xnew-4,ynew+shift-(ccOverallHeight-ccBaselineHeight)-4,8,8);
double xnew1=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr);
i++;
//painter.setPen(QPen("magenta"));
//painter.drawEllipse(xnew-4,ynew-4,8,8);
double xnew2=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr);
//i++;
xnew=qMax(xnew1, xnew2);
doDraw=false;
}
}
} else {
if (smb) {
QString s=smb->getSymbolName();
if (subsupOperations.contains(s)) {
MTsubscriptNode* subn=nullptr;
if (i+1<nodes.size()) subn=dynamic_cast<MTsubscriptNode*>(nodes[i+1]);
MTsuperscriptNode* supn=nullptr;
if (i+2<nodes.size()) supn=dynamic_cast<MTsuperscriptNode*>(nodes[i+2]);
//std::cout<<"symbol ='"<<s.toStdString()<<"' subn="<<subn<<" supn="<<supn<<"\n";
if (subn && supn) { // is this subscript and superscript?
MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor();
double w1=0, w2=0, w3=0;
double oh1=0, oh2=0, oh3=0;
double bh1=0, bh2=0, bh3=0, sp;
nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp);
subn->getChild()->getSize(painter, ev, w2, bh2, oh2, sp);
supn->getChild()->getSize(painter, ev, w3, bh3, oh3, sp);
double d1=oh1-bh1;
//double d2=oh2-bh2;
double d3=oh3-bh3;
double w=qMax(qMax(w1, w2), w3);
//double xnew1=
double xn1=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv);
i++;
//double xnew2=
double xn2=subn->getChild()->draw(painter, xnew+(w-w2)/2.0, ynew+bh2+d1, ev);
i++;
//double xnew3=
double xn3=supn->getChild()->draw(painter, xnew+(w-w3)/2.0, ynew-bh1-d3-fm.xHeight()/4.0, ev);
doDraw=false;
xnew=qMax(qMax(xn1, xn2), xn3)+fm.width(" ");
} else if (subn) { // is this subscript and not superscript?
MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor();
double w1=0, w2=0;
double oh1=0, oh2=0;
double bh1=0, bh2=0, sp=0;
nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp);
subn->getChild()->getSize(painter, ev, w2, bh2, oh2, sp);
double d1=oh1-bh1;
//double d2=oh2-bh2;
double w=qMax(w1, w2);
//double xnew1=
double xn2=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv);
i++;
//double xnew2=
double xn1=subn->getChild()->draw(painter, xnew+(w-w2)/2.0, ynew+bh2+d1, ev)+fm.width(" ");
doDraw=false;
//xnew+=w;
xnew=qMax(xn1, xn2);
} else if (supn) { // is this subscript and superscript?
MTenvironment ev=currentEv;
ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor();
double w1=0, w3=0;
double oh1=0, oh3=0;
double bh1=0, bh3=0, sp;
nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp);
supn->getChild()->getSize(painter, ev, w3, bh3, oh3, sp);
//double d1=oh1-bh1;
//double d2=oh2-bh2;
double d3=oh3-bh3;
double w=qMax(w1, w3);
//double xnew1=
double xn1=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv);
i++;
//double xnew3=
double xn3=supn->getChild()->draw(painter, xnew+(w-w3)/2.0, ynew-bh1-d3-fm.xHeight()/4.0, ev);
doDraw=false;
xnew=qMax(xn1, xn3)+fm.width(" ");
}
}
}
}
if (i<nodes.size() && doDraw) {
xnew=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr);
}
wasBrace=dynamic_cast<MTbraceNode*>(nodes[i]);
}
return xnew;
}
bool JKQTMathText::MTlistNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) {
bool ok=true;
for (int i=0; i<nodes.size(); i++) {
QString h="";
ok = ok && nodes[i]->toHtml(h, currentEv, defaultEv);
html=html+h;
}
return ok;
}
void JKQTMathText::MTlistNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
for (int i=0; i<nodes.size(); i++) {
nodes[i]->setDrawBoxes(draw);
}
}
JKQTMathText::MTsymbolNode::MTsymbolNode(JKQTMathText* parent, const QString& name, bool addWhitespace):
JKQTMathText::MTnode(parent)
{
double mathFontFactor=1.8;
symbol = "";
symbolName=name;
fontFactor=1.0;
bold=0;
italic=-1;
yfactor=0;
QString n=name;
drawBar=false;
font=MTSFdefault;
heightIsAscent=false;
exactAscent=false;
extendWidthInMathmode=false;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// statische Lookup-Tabellen vorbereiten
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static QStringList extendWInMM;
if (extendWInMM.isEmpty()) {
extendWInMM <<"ll"<<"gg"<<"leq"<<"geq"<<"leftrightarrow"<<"leftarrow"<<"rightarrow"<<"to"<<"uparrow"<<"downarrow"<<"updownarrow"<<"Leftrightarrow"
<<"iff"<<"Leftarrow"<<"Rightarrow"<<"Uparrow"<<"Downarrow"<<"Updownarrow"<<"pm"<<"mp"<<"nexists"<<"ni"<<"notni"<<"circ"<<"sim"<<"emptyset"<<"odot"<<"ominus"
<<"subsetnot"<<"bot"<<"leftharpoonup"<<"rightharpoonup"<<"upharpoonleft"<<"downharpoonleft"<<"leftrightharpoon"<<"rightleftharpoon"<<"coprod"<<"leftharpoondown"
<<"rightharpoondown"<<"upharpoonright"<<"downharpoonright"<<"nwarrow"<<"nearrow"<<"searrow"<<"swarrow"<<"mapsto"<<"div"<<"multimap"<<"maporiginal"<<"mapimage"
<<"times"<<"propto"<<"bullet"<<"neq"<<"ne"<<"equiv"<<"approx"<<"otimes"<<"oplus"<<"oslash"<<"cap"<<"land"<<"cup"<<"lor"<<"supset"<<"supseteq"<<"supsetnot"
<<"subset"<<"subseteq"<<"in"<<"notin"<<"cdot"<<"wedge"<<"vee"<<"cong"<<"bot"<<"mid";
}
if (extendWInMM.contains(n)) {
extendWidthInMathmode=true;
}
static QHash<QString, QString> simpleTranslations;
if (simpleTranslations.isEmpty()) {
simpleTranslations.insert("", " ");
simpleTranslations.insert("sin", "sin");
simpleTranslations.insert("cos", "cos");
simpleTranslations.insert("tan", "tan");
simpleTranslations.insert("sinh", "sinh");
simpleTranslations.insert("cosh", "cosh");
simpleTranslations.insert("tanh", "tanh");
simpleTranslations.insert("atan", "atan");
simpleTranslations.insert("acos", "acos");
simpleTranslations.insert("asin", "asin");
simpleTranslations.insert("arcsin", "arcsin");
simpleTranslations.insert("arccos", "arccos");
simpleTranslations.insert("arctan", "arctan");
simpleTranslations.insert("degree", QLatin1String("\xB0"));
simpleTranslations.insert("ii", "i");
simpleTranslations.insert("dd", "d");
simpleTranslations.insert("exp", "exp");
simpleTranslations.insert("log", "log");
simpleTranslations.insert("ln", "ln");
simpleTranslations.insert("ld", "ld");
simpleTranslations.insert("lb", "lb");
simpleTranslations.insert("argmin", "argmin");
simpleTranslations.insert("argmax", "argmax");
simpleTranslations.insert("max", "max");
simpleTranslations.insert("mod", "mod");
simpleTranslations.insert("min", "min");
simpleTranslations.insert("median", "median");
simpleTranslations.insert("sign", "sign");
simpleTranslations.insert("sgn", "sgn");
simpleTranslations.insert("sec", "sec");
simpleTranslations.insert("gcd", "gcd");
simpleTranslations.insert("hom", "hom");
simpleTranslations.insert("ker", "ker");
simpleTranslations.insert("dim", "dim");
simpleTranslations.insert("cot", "cot");
simpleTranslations.insert("arg", "arg");
simpleTranslations.insert("det", "det");
simpleTranslations.insert("deg", "deg");
simpleTranslations.insert("Pr", "Pr");
simpleTranslations.insert("coth", "coth");
}
static QHash<QString, QString> simpleTranslations_heightIsAscent;
if (simpleTranslations_heightIsAscent.isEmpty()) {
simpleTranslations_heightIsAscent.insert("erf", "erf");
simpleTranslations_heightIsAscent.insert("median", "median");
simpleTranslations_heightIsAscent.insert("min", "min");
simpleTranslations_heightIsAscent.insert("max", "max");
simpleTranslations_heightIsAscent.insert("inf", "inf");
simpleTranslations_heightIsAscent.insert("sup", "sup");
simpleTranslations_heightIsAscent.insert("liminf", "liminf");
simpleTranslations_heightIsAscent.insert("limsup", "limsup");
simpleTranslations_heightIsAscent.insert("lim", "lim");
}
static QHash<QString, QString> winSymbolGreek;
if (winSymbolGreek.isEmpty()) {
winSymbolGreek.insert("alpha", "a");
winSymbolGreek.insert("beta", "b");
winSymbolGreek.insert("gamma", "g");
winSymbolGreek.insert("delta", "d");
winSymbolGreek.insert("epsilon", "e");
winSymbolGreek.insert("varepsilon", "e");
winSymbolGreek.insert("zeta", "z");
winSymbolGreek.insert("eta", "h");
winSymbolGreek.insert("theta", "q");
winSymbolGreek.insert("vartheta", "J");
winSymbolGreek.insert("iota", "i");
winSymbolGreek.insert("kappa", "k");
winSymbolGreek.insert("lambda", "l");
winSymbolGreek.insert("mu", "m");
winSymbolGreek.insert("nu", "n");
winSymbolGreek.insert("xi", "x");
winSymbolGreek.insert("pi", "p");
winSymbolGreek.insert("varpi", "v");
winSymbolGreek.insert("rho", "r");
winSymbolGreek.insert("sigma", "s");
winSymbolGreek.insert("varsigma", "V");
winSymbolGreek.insert("tau", "t");
winSymbolGreek.insert("upsilon", "u");
winSymbolGreek.insert("phi", "f");
winSymbolGreek.insert("varphi", "j");
winSymbolGreek.insert("chi", "c");
winSymbolGreek.insert("psi", "y");
winSymbolGreek.insert("omega", "w");
winSymbolGreek.insert("Gamma", "G");
winSymbolGreek.insert("Delta", "D");
winSymbolGreek.insert("Theta", "Q");
winSymbolGreek.insert("Lambda", "L");
winSymbolGreek.insert("Omega", "W");
winSymbolGreek.insert("Xi", "X");
winSymbolGreek.insert("Pi", "P");
winSymbolGreek.insert("Sigma", "S");
winSymbolGreek.insert("Upsilon", "");
winSymbolGreek.insert("Phi", "F");
winSymbolGreek.insert("Psi", "Y");
}
static QHash<QString, QString> winSymbolSymbol;
if (winSymbolSymbol.isEmpty()) {
winSymbolSymbol.insert("leftrightarrow", QChar(0xAB));
winSymbolSymbol.insert("leftarrow", QChar(0xAC));
winSymbolSymbol.insert("rightarrow", QChar(0xAE));
winSymbolSymbol.insert("to", QChar(0xAE));
winSymbolSymbol.insert("uparrow", QChar(0xAD));
winSymbolSymbol.insert("downarrow", QChar(0xAF));
winSymbolSymbol.insert("Leftrightarrow", QChar(0xDB));
winSymbolSymbol.insert("iff", QChar(0xDB));
winSymbolSymbol.insert("Leftarrow", QChar(0xDC));
winSymbolSymbol.insert("Rightarrow", QChar(0xDE));
winSymbolSymbol.insert("Uparrow", QChar(0xDD));
winSymbolSymbol.insert("Downarrow", QChar(0xFF));
winSymbolSymbol.insert("pm", QChar(0xB1));
winSymbolSymbol.insert("leq", QChar(0xA3));
winSymbolSymbol.insert("geq", QChar(0xB3));
winSymbolSymbol.insert("times", QChar(0xB4));
winSymbolSymbol.insert("propto", QChar(0xB5));
winSymbolSymbol.insert("partial", QChar(0xB6));
winSymbolSymbol.insert("bullet", QChar(0xB7));
winSymbolSymbol.insert("neq", QChar(0xB9));
winSymbolSymbol.insert("ne", QChar(0xB9));
winSymbolSymbol.insert("equiv", QChar(0xBA));
winSymbolSymbol.insert("approx", QChar(0xBB));
winSymbolSymbol.insert("ellipsis", QChar(0xBC));
winSymbolSymbol.insert("Im", QChar(0xC1));
winSymbolSymbol.insert("Re", QChar(0xC2));
winSymbolSymbol.insert("otimes", QChar(0xC4));
winSymbolSymbol.insert("oplus", QChar(0xC5));
winSymbolSymbol.insert("oslash", QChar(0xC6));
winSymbolSymbol.insert("cap", QChar(0xC7));
winSymbolSymbol.insert("land", QChar(0xC7));
winSymbolSymbol.insert("cup", QChar(0xC8));
winSymbolSymbol.insert("lor", QChar(0xC8));
winSymbolSymbol.insert("supset", QChar(0xC9));
winSymbolSymbol.insert("supseteq", QChar(0xCA));
winSymbolSymbol.insert("supsetnot", QChar(0xCB));
winSymbolSymbol.insert("subset", QChar(0xCC));
winSymbolSymbol.insert("subseteq", QChar(0xCD));
winSymbolSymbol.insert("in", QChar(0xCE));
winSymbolSymbol.insert("notin", QChar(0xCF));
winSymbolSymbol.insert("angle", QChar(0xD0));
winSymbolSymbol.insert("nabla", QChar(0xD1));
winSymbolSymbol.insert("copyright", QChar(0xD3));
winSymbolSymbol.insert("registered", QChar(0xD2));
winSymbolSymbol.insert("trademark", QChar(0xD4));
winSymbolSymbol.insert("cdot", QChar(0xD7));
winSymbolSymbol.insert("neg", QChar(0xD8));
winSymbolSymbol.insert("wedge", QChar(0xD9));
winSymbolSymbol.insert("vee", QChar(0xDA));
winSymbolSymbol.insert("diamond", QChar(0xE0));
winSymbolSymbol.insert("langle", QChar(0xE1));
winSymbolSymbol.insert("rangle", QChar(0xF1));
winSymbolSymbol.insert("forall", QChar(0x22));
winSymbolSymbol.insert("exists", QChar(0x24));
winSymbolSymbol.insert("cong", QChar(0x40));
winSymbolSymbol.insert("bot", QChar(0x5E));
winSymbolSymbol.insert("ll", "<<");
winSymbolSymbol.insert("gg", ">>");
winSymbolSymbol.insert("Alef", QChar(0xC0));
winSymbolSymbol.insert("alef", QChar(0xC0));
winSymbolSymbol.insert("tilde", "~");
winSymbolSymbol.insert("emptyset", QChar(0xC6));
winSymbolSymbol.insert("varnothing", QChar(0xC6));
winSymbolSymbol.insert("lceil", QChar(0xE9));
winSymbolSymbol.insert("rceil", QChar(0xF9));
winSymbolSymbol.insert("lfloor", QChar(0xEB));
winSymbolSymbol.insert("rfloor", QChar(0xFB));
winSymbolSymbol.insert("subsetnot", QChar(0xCB));
winSymbolSymbol.insert("DC", "=");
winSymbolSymbol.insert("mid", "|");
winSymbolSymbol.insert("cdots", QString(3, QChar(0xD7)));
winSymbolSymbol.insert("dots", QChar(0xDC));
winSymbolSymbol.insert("ldots", QChar(0xDC));
winSymbolSymbol.insert("cent", "c");
}
static QHash<QString, QString> unicodeGreek;
if (unicodeGreek.isEmpty()) {
unicodeGreek.insert("alpha", QChar(0x3B1));
unicodeGreek.insert("beta", QChar(0x3B2));
unicodeGreek.insert("gamma", QChar(0x3B3));
unicodeGreek.insert("delta", QChar(0x3B4));
unicodeGreek.insert("epsilon", QChar(0x3B5));
unicodeGreek.insert("varepsilon", QChar(0x3B5));
unicodeGreek.insert("zeta", QChar(0x3B6));
unicodeGreek.insert("eta", QChar(0x3B7));
unicodeGreek.insert("theta", QChar(0x3B8));
unicodeGreek.insert("vartheta", QChar(0x3D1));
unicodeGreek.insert("iota", QChar(0x3B9));
unicodeGreek.insert("kappa", QChar(0x3BA));
unicodeGreek.insert("lambda", QChar(0x3BB));
unicodeGreek.insert("mu", QChar(0x3BC));
unicodeGreek.insert("nu", QChar(0x3BD));
unicodeGreek.insert("xi", QChar(0x3BE));
unicodeGreek.insert("pi", QChar(0x3C0));
unicodeGreek.insert("varpi", QChar(0x3D6));
unicodeGreek.insert("rho", QChar(0x3C1));
unicodeGreek.insert("varrho", QChar(0x3F1));
unicodeGreek.insert("sigma", QChar(0x3C3));
unicodeGreek.insert("varsigma", QChar(0x3C2));
unicodeGreek.insert("tau", QChar(0x3C4));
unicodeGreek.insert("upsilon", QChar(0x3C5));
unicodeGreek.insert("phi", QChar(0x3D5));
unicodeGreek.insert("varphi", QChar(0x3C6));
unicodeGreek.insert("chi", QChar(0x3C7));
unicodeGreek.insert("psi", QChar(0x3C8));
unicodeGreek.insert("omega", QChar(0x3C9));
unicodeGreek.insert("Omega", QChar(0x3A9));
unicodeGreek.insert("Gamma", QChar(0x393));
unicodeGreek.insert("Delta", QChar(0x394));
unicodeGreek.insert("Theta", QChar(0x398));
unicodeGreek.insert("Lambda", QChar(0x39B));
unicodeGreek.insert("Xi", QChar(0x39E));
unicodeGreek.insert("Pi", QChar(0x3A0));
unicodeGreek.insert("Sigma", QChar(0x3A3));
unicodeGreek.insert("Upsilon", QChar(0x3A5));
unicodeGreek.insert("Phi", QChar(0x3A6));
unicodeGreek.insert("Psi", QChar(0x3A8));
}
static QHash<QString, QString> unicodeSymbol;
if (unicodeSymbol.isEmpty()) {
unicodeSymbol.insert("leftrightarrow", QChar(0x2194));
unicodeSymbol.insert("leftarrow", QChar(0x2190));
unicodeSymbol.insert("rightarrow", QChar(0x2192));
unicodeSymbol.insert("to", QChar(0x2192));
unicodeSymbol.insert("uparrow", QChar(0x2191));
unicodeSymbol.insert("downarrow", QChar(0x2193));
unicodeSymbol.insert("updownarrow", QChar(0x2195));
unicodeSymbol.insert("Leftrightarrow", QChar(0x21D4));
unicodeSymbol.insert("iff", QChar(0x21D4));
unicodeSymbol.insert("Leftarrow", QChar(0x21D0));
unicodeSymbol.insert("Rightarrow", QChar(0x21D2));
unicodeSymbol.insert("Uparrow", QChar(0x21D1));
unicodeSymbol.insert("Downarrow", QChar(0x21D3));
unicodeSymbol.insert("Updownarrow", QChar(0x21D5));
unicodeSymbol.insert("mp", QChar(0x2213));
unicodeSymbol.insert("ll", QChar(0x226A));
unicodeSymbol.insert("gg", QChar(0x226B));
unicodeSymbol.insert("Alef", QChar(0x2135));
unicodeSymbol.insert("Bet", QChar(0x2136));
unicodeSymbol.insert("Gimel", QChar(0x2137));
unicodeSymbol.insert("Dalet", QChar(0x2138));
unicodeSymbol.insert("alef", QChar(0x2135));
unicodeSymbol.insert("bet", QChar(0x2136));
unicodeSymbol.insert("gimel", QChar(0x2137));
unicodeSymbol.insert("dalet", QChar(0x2138));
unicodeSymbol.insert("nexists", QChar(0x2204));
unicodeSymbol.insert("ni", QChar(0x220B));
unicodeSymbol.insert("notni", QChar(0x220C));
unicodeSymbol.insert("tilde", QChar(0x223C));
unicodeSymbol.insert("emptyset", QChar(0x2300));
unicodeSymbol.insert("varnothing", QChar(0x2300));
unicodeSymbol.insert("odot", QChar(0x2299));
unicodeSymbol.insert("ominus", QChar(0x2296));
unicodeSymbol.insert("lceil", QChar(0x2308));
unicodeSymbol.insert("rceil", QChar(0x2309));
unicodeSymbol.insert("lfloor", QChar(0x230A));
unicodeSymbol.insert("rfloor", QChar(0x230B));
unicodeSymbol.insert("subsetnot", QChar(0x2284));
unicodeSymbol.insert("DC", QChar(0x2393));
unicodeSymbol.insert("bot", QChar(0x22A4));
unicodeSymbol.insert("mid", QChar(0xFF5C));
unicodeSymbol.insert("vdots", QChar(0x22EE));
unicodeSymbol.insert("iddots", QChar(0x22F0));
unicodeSymbol.insert("ddots", QChar(0x22F1));
unicodeSymbol.insert("perthousand", QChar(0x2030));
unicodeSymbol.insert("leftharpoonup", QChar(0x21BC));
unicodeSymbol.insert("rightharpoonup", QChar(0x21C0));
unicodeSymbol.insert("upharpoonleft", QChar(0x21BF));
unicodeSymbol.insert("downharpoonleft", QChar(0x21C3));
unicodeSymbol.insert("leftrightharpoon", QChar(0x21CB));
unicodeSymbol.insert("rightleftharpoon", QChar(0x21CC));
unicodeSymbol.insert("leftharpoondown", QChar(0x21BD));
unicodeSymbol.insert("rightharpoondown", QChar(0x21C1));
unicodeSymbol.insert("upharpoonright", QChar(0x21BE));
unicodeSymbol.insert("downharpoonright", QChar(0x21C2));
unicodeSymbol.insert("nwarrow", QChar(0x2196));
unicodeSymbol.insert("nearrow", QChar(0x2197));
unicodeSymbol.insert("searrow", QChar(0x2198));
unicodeSymbol.insert("swarrow", QChar(0x2199));
unicodeSymbol.insert("mapsto", QChar(0x21A6));
unicodeSymbol.insert("div", QChar(0x00F7));
unicodeSymbol.insert("multimap", QChar(0x22B8));
unicodeSymbol.insert("maporiginal", QChar(0x22B6));
unicodeSymbol.insert("mapimage", QChar(0x22B7));
unicodeSymbol.insert("benzene", QChar(0x232C));
unicodeSymbol.insert("propto", QChar(0x221D));
unicodeSymbol.insert("ne", QChar(0x2260));
unicodeSymbol.insert("equiv", QChar(0x2261));
unicodeSymbol.insert("ellipsis", QChar(0x2026));
unicodeSymbol.insert("Im", QChar(0x2111));
unicodeSymbol.insert("Re", QChar(0x211C));
unicodeSymbol.insert("otimes", QChar(0x2297));
unicodeSymbol.insert("oplus", QChar(0x2295));
unicodeSymbol.insert("oslash", QChar(0x2298));
unicodeSymbol.insert("cap", QChar(0x2229));
unicodeSymbol.insert("land", QChar(0x2229));
unicodeSymbol.insert("cup", QChar(0x222A));
unicodeSymbol.insert("lor", QChar(0x222A));
unicodeSymbol.insert("supset", QChar(0x2283));
unicodeSymbol.insert("supseteq", QChar(0x2286));
unicodeSymbol.insert("supsetnot", QChar(0x2285));
unicodeSymbol.insert("subset", QChar(0x2282));
unicodeSymbol.insert("subseteq", QChar(0x2286));
unicodeSymbol.insert("in", QChar(0x2208));
unicodeSymbol.insert("notin", QChar(0x2209));
unicodeSymbol.insert("angle", QChar(0x2221));
unicodeSymbol.insert("nabla", QChar(0x2207));
unicodeSymbol.insert("neg", QChar(0x00AC));
unicodeSymbol.insert("wedge", QChar(0x2227));
unicodeSymbol.insert("vee", QChar(0x2228));
unicodeSymbol.insert("langle", QChar(0x2329));
unicodeSymbol.insert("rangle", QChar(0x232A));
unicodeSymbol.insert("forall", QChar(0x2200));
unicodeSymbol.insert("exists", QChar(0x2203));
unicodeSymbol.insert("cong", QChar(0x2245));
unicodeSymbol.insert("bot", QChar(0x22A5));
}
static QHash<QString, QString> unicodeBaseSymbol;
if (unicodeBaseSymbol.isEmpty()) {
unicodeBaseSymbol.insert("diamond", QChar(0xE0));
unicodeBaseSymbol.insert("infty", QChar(0x221E));
unicodeBaseSymbol.insert("partial", QChar(0x2202));
unicodeBaseSymbol.insert("times", QChar(0x2A2F));
unicodeBaseSymbol.insert("bullet", QChar(0x2219));
unicodeBaseSymbol.insert("copyright", QChar(0x00A9));
unicodeBaseSymbol.insert("registered", QChar(0x00AE));
unicodeBaseSymbol.insert("trademark", QChar(0x2122));
unicodeBaseSymbol.insert("cdot", QChar(0x00B7));
unicodeBaseSymbol.insert("pm", QChar(0x00B1));
unicodeBaseSymbol.insert("leq", QChar(0x2264));
unicodeBaseSymbol.insert("geq", QChar(0x2265));
unicodeBaseSymbol.insert("hbar", QChar(0x210F));
unicodeBaseSymbol.insert("euro", QChar(0x20AC));
unicodeBaseSymbol.insert("circ", QChar(0x2218));
unicodeBaseSymbol.insert("cent", QChar(0x00A2));
unicodeBaseSymbol.insert("pound", QChar(0x00A3));
unicodeBaseSymbol.insert("yen", QChar(0x00A5));
unicodeBaseSymbol.insert("neq", QChar(0x2260));
unicodeBaseSymbol.insert("Angstrom", QChar(0x212B));
unicodeBaseSymbol.insert("cdots", QString(QChar(0x00B7)) + QString(QChar(0x00B7)) + QString(QChar(0x00B7)));
unicodeBaseSymbol.insert("dots", "...");
unicodeBaseSymbol.insert("ldots", "...");
unicodeBaseSymbol.insert("approx", QChar(0x2248));
}
static QHash<QString, QString> latexSimpleSymbol;
if (latexSimpleSymbol.isEmpty()) {
latexSimpleSymbol.insert("_", "_");
latexSimpleSymbol.insert("}", "}");
latexSimpleSymbol.insert("{", "{");
latexSimpleSymbol.insert("$", "$");
latexSimpleSymbol.insert("%", "%");
latexSimpleSymbol.insert("&", "&");
latexSimpleSymbol.insert("#", "#");
latexSimpleSymbol.insert("ast", "*");
latexSimpleSymbol.insert("glq", QChar(0x27));
latexSimpleSymbol.insert("grq", QChar(0x60));
latexSimpleSymbol.insert("glqq", QChar(0x5C));
latexSimpleSymbol.insert("grqq", "\"");
}
static QHash<QString, QString> latexGreek;
if (latexGreek.isEmpty()) {
latexGreek.insert("alpha", QChar(0xAE));
latexGreek.insert("beta", QChar(0xAF));
latexGreek.insert("gamma", QChar(0xB0));
latexGreek.insert("delta", QChar(0xB1));
latexGreek.insert("epsilon", QChar(0x22));
latexGreek.insert("varepsilon", QChar(0xB2));
latexGreek.insert("zeta", QChar(0xB3));
latexGreek.insert("eta", QChar(0xB4));
latexGreek.insert("theta", QChar(0xB5));
latexGreek.insert("vartheta", QChar(0x23));
latexGreek.insert("iota", QChar(0xB6));
latexGreek.insert("kappa", QChar(0xB7));
latexGreek.insert("lambda", QChar(0xB8));
latexGreek.insert("mu", QChar(0xB9));
latexGreek.insert("nu", QChar(0xBA));
latexGreek.insert("xi", QChar(0xBB));
latexGreek.insert("pi", QChar(0xBC));
latexGreek.insert("varpi", QChar(0x24));
latexGreek.insert("rho", QChar(0xBD));
latexGreek.insert("varrho", QChar(0x25));
latexGreek.insert("sigma", QChar(0xBE));
latexGreek.insert("varsigma", QChar(0x26));
latexGreek.insert("tau", QChar(0xBF));
latexGreek.insert("upsilon", QChar(0xC0));
latexGreek.insert("phi", QChar(0xC1));
latexGreek.insert("varphi", QChar(0x27));
latexGreek.insert("chi", QChar(0xC2));
latexGreek.insert("psi", QChar(0xC3));
latexGreek.insert("omega", QChar(0x21));
latexGreek.insert("Gamma", QChar(0xA1));
latexGreek.insert("Delta", QChar(0xA2));
latexGreek.insert("Theta", QChar(0xA3));
latexGreek.insert("Lambda", QChar(0xA4));
latexGreek.insert("Xi", QChar(0xA5));
latexGreek.insert("Pi", QChar(0xA6));
latexGreek.insert("Sigma", QChar(0xA7));
latexGreek.insert("Upsilon", QChar(0xA8));
latexGreek.insert("Phi", QChar(0xA9));
latexGreek.insert("Psi", QChar(0xAA));
latexGreek.insert("leftharpoonup", QChar(0x28));
latexGreek.insert("rightharpoonup", QChar(0x2A));
latexGreek.insert("leftharpoondown", QChar(0x29));
latexGreek.insert("rightharpoondown", QChar(0x2B));
latexGreek.insert("neg", QChar(0xAC));
latexGreek.insert("star", QChar(0x3F));
}
static QHash<QString, QString> latexSymbol;
if (latexSymbol.isEmpty()) {
latexSymbol.insert("leftrightarrow", QChar(0x24));
latexSymbol.insert("leftarrow", QChar(0xc3));
latexSymbol.insert("rightarrow", QChar(0x21));
latexSymbol.insert("to", QChar(0x21));
latexSymbol.insert("uparrow", QChar(0x22));
latexSymbol.insert("downarrow", QChar(0x23));
latexSymbol.insert("updownarrow", QChar(0x6c));
latexSymbol.insert("Leftrightarrow", QChar(0x2c));
latexSymbol.insert("iff", QChar(0x2c));
latexSymbol.insert("Leftarrow", QChar(0x28));
latexSymbol.insert("Rightarrow", QChar(0x29));
latexSymbol.insert("Uparrow", QChar(0x2a));
latexSymbol.insert("Downarrow", QChar(0x2b));
latexSymbol.insert("Updownarrow", QChar(0x6d));
latexSymbol.insert("pm", QChar(0xa7));
latexSymbol.insert("mp", QChar(0xa8));
latexSymbol.insert("leq", QChar(0xb7));
latexSymbol.insert("geq", QChar(0xb8));
latexSymbol.insert("ll", QChar(0xbf));
latexSymbol.insert("gg", QChar(0xc0));
latexSymbol.insert("Alef", QChar(0x40));
latexSymbol.insert("alef", QChar(0x40));
latexSymbol.insert("ni", QChar(0x33));
latexSymbol.insert("circ", QChar(0xb1));
latexSymbol.insert("tilde", QChar(0xbb));
latexSymbol.insert("emptyset", QChar(0x3b));
latexSymbol.insert("odot", QChar(0xaf));
latexSymbol.insert("ominus", QChar(0xaa));
latexSymbol.insert("odiv", QChar(0xae));
latexSymbol.insert("oplus", QChar(0xa9));
latexSymbol.insert("lceil", QChar(0x64));
latexSymbol.insert("rceil", QChar(0x65));
latexSymbol.insert("lfloor", QChar(0x62));
latexSymbol.insert("rfloor", QChar(0x63));
latexSymbol.insert("bot", QChar(0x3f));
latexSymbol.insert("cdots", QString(3, QChar(0xA2)));
latexSymbol.insert("dots", "...");
latexSymbol.insert("nwarrow", QChar(0x2d));
latexSymbol.insert("nearrow", QChar(0x25));
latexSymbol.insert("searrow", QChar(0x26));
latexSymbol.insert("swarrow", QChar(0x2e));
latexSymbol.insert("div", QChar(0xa5));
latexSymbol.insert("times", QChar(0xa3));
latexSymbol.insert("propto", QChar(0x2f));
latexSymbol.insert("bullet", QChar(0x2b));
latexSymbol.insert("equiv", QChar(0xb4));
latexSymbol.insert("approx", QChar(0xbc));
latexSymbol.insert("ellipsis", "...");
latexSymbol.insert("Im", QChar(0x3D));
latexSymbol.insert("Re", QChar(0x3C));
latexSymbol.insert("oplus", QChar(0xa9));
latexSymbol.insert("oslash", QChar(0xae));
latexSymbol.insert("cap", QChar(0x5c));
latexSymbol.insert("cup", QChar(0x5b));
latexSymbol.insert("land", QChar(0x5c));
latexSymbol.insert("lor", QChar(0x5b));
latexSymbol.insert("supset", QChar(0xbe));
latexSymbol.insert("supseteq", QChar(0xb6));
latexSymbol.insert("subset", QChar(0xbd));
latexSymbol.insert("subseteq", QChar(0xb5));
latexSymbol.insert("in", QChar(0x32));
latexSymbol.insert("nabla", QChar(0x35));
latexSymbol.insert("cdot", QChar(0xa2));
latexSymbol.insert("wedge", QChar(0x5e));
latexSymbol.insert("vee", QChar(0x5f));
latexSymbol.insert("diamond", QChar(0xE0));
latexSymbol.insert("langle", QChar(0x68));
latexSymbol.insert("rangle", QChar(0x69));
latexSymbol.insert("infty", QChar(0x31));
latexSymbol.insert("forall", QChar(0x38));
latexSymbol.insert("exists", QChar(0x39));
latexSymbol.insert("cong", QChar(0xbb));
latexSymbol.insert("mid", "|");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
QHash<QString, QString>::iterator itsimple = simpleTranslations.find(n);
if (itsimple!= simpleTranslations.end()) {
symbol=itsimple.value();
} else {
QHash<QString, QString>::iterator itsimplehia = simpleTranslations_heightIsAscent.find(n);
if (itsimplehia != simpleTranslations_heightIsAscent.end()) {
symbol = itsimplehia.value();
heightIsAscent = true;
} else {
if (parent->getFontEncoding() == MTFEwinSymbol) {
// first we start with greek characters
font = MTSFgreek;
italic = -1;
QHash<QString, QString>::iterator itgreek = winSymbolGreek.find(n);
if (itgreek!=winSymbolGreek.end()) {
symbol = itgreek.value();
} else if (n == "sum") { symbol = "S"; fontFactor = mathFontFactor; heightIsAscent = true; exactAscent = true; }
else if (n == "prod") { symbol = "P"; fontFactor = mathFontFactor; heightIsAscent = true; exactAscent = true; }
else {
// now we set the symbols from the Symbol font
font = MTSFsymbol;
QHash<QString, QString>::iterator itsymbol = winSymbolSymbol.find(n);
if (itsymbol!=winSymbolSymbol.end()) {
symbol = itsymbol.value();
} else if (n == "int") { symbol = QChar(0xF2); fontFactor = mathFontFactor; yfactor = +0.1; }
else if (n == "bbC") { symbol = "C"; bold = +1; italic = -1; }
else if (n == "bbH") { symbol = "H"; bold = +1; italic = -1; }
else if (n == "bbN") { symbol = "N"; bold = +1; italic = -1; }
else if (n == "bbP") { symbol = "P"; bold = +1; italic = -1; }
else if (n == "bbQ") { symbol = "Q"; bold = +1; italic = -1; }
else if (n == "bbR") { symbol = "R"; bold = +1; italic = -1; }
else if (n == "bbZ") { symbol = "Z"; bold = +1; italic = -1; }
else if (n == "iint") { symbol = QString(2, QChar(0xF2)); fontFactor = mathFontFactor; yfactor = +0.1; }
else if (n == "iiint") { symbol = QString(3, QChar(0xF2)); fontFactor = mathFontFactor; yfactor = +0.1; }
else if (n == "bigcap") { symbol = QChar(0xC7); fontFactor = 2; }
else if (n == "bigcup") { symbol = QChar(0xC8); fontFactor = 2; }
else if (n == "bigvee") { symbol = QChar(0xDA); fontFactor = 2; }
else if (n == "bighat") { symbol = QChar(0xD9); fontFactor = 2; }
else { // here are text mode symbols, i.e. bold and italic won't be touched
bold = -1;
italic = -1;
font = MTSFdefault;
if (n == "_") { symbol = "_"; bold = 0; italic = 0; }
else if (n == "}") { symbol = "}"; }
else if (n == "{") { symbol = "{"; }
else if (n == "hbar") { symbol = "h"; bold = 0; italic = 0; drawBar = true; }
else if (n == "euro") { symbol = ""; bold = 0; italic = 0; }
else if (n == "cent") { symbol = QChar(0xA2); bold = 0; italic = 0; }
else if (n == "pound") { symbol = QChar(0xA3); bold = 0; italic = 0; }
else if (n == "yen") { symbol = QChar(0xA5); bold = 0; italic = 0; }
else if (n == "div") { symbol = QChar(0xF7); bold = 0; italic = 0; }
else if (n == "backslash") { symbol = "\\"; bold = 0; italic = 0; }
//else if (n=="|") { symbol="||"; bold=0; italic=0; }
else if (n == "$") { symbol = "$"; bold = 0; italic = 0; }
else if (n == "%") { symbol = "%"; bold = 0; italic = 0; }
else if (n == "&") { symbol = "&"; bold = 0; italic = 0; }
else if (n == "#") { symbol = "#"; bold = 0; italic = 0; }
else if (n == "ast") { symbol = "*"; bold = 0; italic = 0; }
else if (n == "glq") { symbol = "'"; bold = 0; italic = 0; }
else if (n == "grq") { symbol = "'"; bold = 0; italic = 0; }
else if (n == "glqq") { symbol = "\""; bold = 0; italic = 0; }
else if (n == "grqq") { symbol = "\""; bold = 0; italic = 0; }
else if (n == "flq") { symbol = "<"; bold = 0; italic = 0; }
else if (n == "frq") { symbol = ">"; bold = 0; italic = 0; }
else if (n == "flqq") { symbol = ""; bold = 0; italic = 0; }
else if (n == "frqq") { symbol = ""; bold = 0; italic = 0; }
}
//else if (n=="") { symbol=QChar(); font=MTSFdefault; }
//else if (n=="") symbol=QChar(0x);
}
} else if (parent->getFontEncoding() == MTFEunicode) { // use UNICODE encoding for special characters
// first we start with greek characters
font = MTSFdefault; //MTSFgreek;
//std::cout<<"encoding unicode\n";
QHash<QString, QString>::iterator itgreek = unicodeGreek.find(n);
if (itgreek!=unicodeGreek.end()) {
symbol = itgreek.value();
} else {
// now we set the symbols from the Symbol font
font = MTSFsymbol;
QHash<QString, QString>::iterator itsymbol = unicodeSymbol.find(n);
QHash<QString, QString>::iterator itbasesymbol = unicodeBaseSymbol.find(n);
if (itbasesymbol!=unicodeBaseSymbol.end()) {
symbol = itbasesymbol.value();
} else if (itsymbol!=unicodeSymbol.end()) {
symbol = itsymbol.value();
}
else if (n == "sum") { symbol = QChar(0x2211); heightIsAscent = true; exactAscent = true; }
else if (n == "prod") { symbol = QChar(0x220F); heightIsAscent = true; exactAscent = true; }
else if (n == "bbC") { symbol = QChar(0x2102); italic = -1; }
else if (n == "bbH") { symbol = QChar(0x210D); italic = -1; }
else if (n == "bbN") { symbol = QChar(0x2115); italic = -1; }
else if (n == "bbP") { symbol = QChar(0x2119); italic = -1; }
else if (n == "bbQ") { symbol = QChar(0x211A); italic = -1; }
else if (n == "bbR") { symbol = QChar(0x211D); italic = -1; }
else if (n == "bbZ") { symbol = QChar(0x2124); italic = -1; }
else if (n == "iint") { symbol = QChar(0x222C); fontFactor = mathFontFactor; /*yfactor=+0.1;*/ heightIsAscent = true; exactAscent = true; }
else if (n == "iiint") { symbol = QChar(0x222D); fontFactor = mathFontFactor; /*yfactor=+0.1;*/ heightIsAscent = true; exactAscent = true; }
else if (n == "oint") { symbol = QChar(0x222E); fontFactor = mathFontFactor; /*yfactor=+0.1;*/ heightIsAscent = true; exactAscent = true; }
else if (n == "oiint") { symbol = QChar(0x222F); fontFactor = mathFontFactor; /*yfactor=+0.1;*/ heightIsAscent = true; exactAscent = true; }
else if (n == "oiiint") { symbol = QChar(0x2230); fontFactor = mathFontFactor; /*yfactor=+0.1;*/ heightIsAscent = true; exactAscent = true; }
else if (n == "coprod") { symbol = QChar(0x2210); heightIsAscent = true; exactAscent = true; }
else if (n == "bigcap") { symbol = QChar(0x22C2); heightIsAscent = true; exactAscent = true; heightIsAscent = true; exactAscent = true; }
else if (n == "bigcup") { symbol = QChar(0x22C3); heightIsAscent = true; exactAscent = true; heightIsAscent = true; exactAscent = true; }
else if (n == "bigvee") { symbol = QChar(0x22C1); heightIsAscent = true; exactAscent = true; heightIsAscent = true; exactAscent = true; }
else if (n == "bighat") { symbol = QChar(0x22C0); heightIsAscent = true; exactAscent = true; heightIsAscent = true; exactAscent = true; }
else if (n == "int") { symbol = QChar(0x222B); fontFactor = mathFontFactor; /*yfactor=+0.1;*/ heightIsAscent = true; exactAscent = true; }
else { // here are text mode symbols, i.e. bold and italic won't be touched
bold = -1;
italic = -1;
font = MTSFdefault;
if (n == "_") { symbol = "_"; }
else if (n == "}") { symbol = "}"; }
else if (n == "{") { symbol = "{"; }
else if (n == "backslash") { symbol = "\\"; bold = 0; italic = 0; }
//else if (n=="|") { symbol=QChar(0x2016); }
else if (n == "$") { symbol = "$"; }
else if (n == "%") { symbol = "%"; }
else if (n == "&") { symbol = "&"; }
else if (n == "#") { symbol = "#"; }
else if (n == "ast") { symbol = "*"; }
else if (n == "glq") { symbol = QChar(0x2018); bold = 0; italic = 0; }
else if (n == "grq") { symbol = QChar(0x2019); bold = 0; italic = 0; }
else if (n == "glqq") { symbol = QChar(0x201C); bold = 0; italic = 0; }
else if (n == "grqq") { symbol = QChar(0x201D); bold = 0; italic = 0; }
else if (n == "flq") { symbol = QChar(0x2039); bold = 0; italic = 0; }
else if (n == "frq") { symbol = QChar(0x203A); bold = 0; italic = 0; }
else if (n == "flqq") { symbol = ""; bold = 0; italic = 0; }
else if (n == "frqq") { symbol = ""; bold = 0; italic = 0; }
}
//else if (n=="") { symbol=QChar(); font=MTSFdefault; }
//else if (n=="") symbol=QChar(0x);
}
} else if (parent->getFontEncoding() == MTFEunicodeLimited) { // use UNICODE encoding for special characters
// now we set the symbols from the Symbol font
font = MTSFdefault;
QHash<QString, QString>::iterator itsymbol = unicodeBaseSymbol.find(n);
if (itsymbol!=unicodeBaseSymbol.end()) {
symbol = itsymbol.value();
//qDebug()<<"unicodeBaseSymbol: "<<symbol<<font;
} else {
font = MTSFsymbol;
italic = -1;
QHash<QString, QString>::iterator itgreek = winSymbolGreek.find(n);
if (itgreek!=winSymbolGreek.end()) {
symbol = itgreek.value();
//qDebug()<<"winSymbolGreek: "<<symbol<<font;
} else if (n == "sum") { symbol = "S"; fontFactor = mathFontFactor; heightIsAscent = true; exactAscent = true; }
else if (n == "prod") { symbol = "P"; fontFactor = mathFontFactor; heightIsAscent = true; exactAscent = true; }
else {
// now we set the symbols from the Symbol font
font = MTSFsymbol;
QHash<QString, QString>::iterator itsymbol = winSymbolSymbol.find(n);
if (itsymbol!=winSymbolSymbol.end()) {
symbol = itsymbol.value();
//qDebug()<<"winSymbolSymbol: "<<symbol<<font;
} else if (n == "int") { symbol = QChar(0xF2); fontFactor = mathFontFactor; yfactor = +0.1; }
else if (n == "bbC") { symbol = "C"; bold = +1; italic = -1; }
else if (n == "bbH") { symbol = "H"; bold = +1; italic = -1; }
else if (n == "bbN") { symbol = "N"; bold = +1; italic = -1; }
else if (n == "bbP") { symbol = "P"; bold = +1; italic = -1; }
else if (n == "bbQ") { symbol = "Q"; bold = +1; italic = -1; }
else if (n == "bbR") { symbol = "R"; bold = +1; italic = -1; }
else if (n == "bbZ") { symbol = "Z"; bold = +1; italic = -1; }
else if (n == "iint") { symbol = QString(2, QChar(0xF2)); fontFactor = mathFontFactor; yfactor = +0.1; }
else if (n == "iiint") { symbol = QString(3, QChar(0xF2)); fontFactor = mathFontFactor; yfactor = +0.1; }
else if (n == "bigcap") { symbol = QChar(0xC7); fontFactor = 2; }
else if (n == "bigcup") { symbol = QChar(0xC8); fontFactor = 2; }
else if (n == "bigvee") { symbol = QChar(0xDA); fontFactor = 2; }
else if (n == "bighat") { symbol = QChar(0xD9); fontFactor = 2; }
else { // here are text mode symbols, i.e. bold and italic won't be touched
bold = -1;
italic = -1;
font = MTSFdefault;
//qDebug()<<"else: "<<symbol<<font;
if (n == "_") { symbol = "_"; bold = 0; italic = 0; }
else if (n == "}") { symbol = "}"; }
else if (n == "{") { symbol = "{"; }
else if (n == "hbar") { symbol = "h"; bold = 0; italic = 0; drawBar = true; }
else if (n == "euro") { symbol = ""; bold = 0; italic = 0; }
else if (n == "cent") { symbol = QChar(0xA2); bold = 0; italic = 0; }
else if (n == "pound") { symbol = QChar(0xA3); bold = 0; italic = 0; }
else if (n == "yen") { symbol = QChar(0xA5); bold = 0; italic = 0; }
else if (n == "div") { symbol = QChar(0xF7); bold = 0; italic = 0; }
else if (n == "backslash") { symbol = "\\"; bold = 0; italic = 0; }
//else if (n=="|") { symbol="||"; bold=0; italic=0; }
else if (n == "$") { symbol = "$"; bold = 0; italic = 0; }
else if (n == "%") { symbol = "%"; bold = 0; italic = 0; }
else if (n == "&") { symbol = "&"; bold = 0; italic = 0; }
else if (n == "#") { symbol = "#"; bold = 0; italic = 0; }
else if (n == "ast") { symbol = "*"; bold = 0; italic = 0; }
else if (n == "glq") { symbol = "'"; bold = 0; italic = 0; }
else if (n == "grq") { symbol = "'"; bold = 0; italic = 0; }
else if (n == "glqq") { symbol = "\""; bold = 0; italic = 0; }
else if (n == "grqq") { symbol = "\""; bold = 0; italic = 0; }
else if (n == "flq") { symbol = "<"; bold = 0; italic = 0; }
else if (n == "frq") { symbol = ">"; bold = 0; italic = 0; }
else if (n == "flqq") { symbol = ""; bold = 0; italic = 0; }
else if (n == "frqq") { symbol = ""; bold = 0; italic = 0; }
}
}
}
} else if (parent->getFontEncoding() == MTFElatex) { // use UNICODE encoding for special characters
// first we start with greek characters
font = MTSFdefault; //MTSFgreek;
//std::cout<<"encoding unicode\n";
QHash<QString, QString>::iterator itssymbol = latexSimpleSymbol.find(n);
if (itssymbol!=latexSimpleSymbol.end()) {
symbol = itssymbol.value();
} else if (n == "backslash") { symbol = "\\"; bold = 0; italic = 0; }
else {
font = MTSFgreek;
QHash<QString, QString>::iterator itgreek = latexGreek.find(n);
if (itgreek!=latexGreek.end()) {
symbol = itgreek.value();
} else {
// now we set the symbols from the Symbol font
font = MTSFsymbol;
QHash<QString, QString>::iterator itsymbol = latexSymbol.find(n);
if (itsymbol!=latexSymbol.end()) {
symbol = itsymbol.value();
} else if (n == "int") { symbol = QChar(0x73); fontFactor = mathFontFactor; yfactor = +0.1; }
else { // here are text mode symbols, i.e. bold and italic won't be touched
font = MTSFbraces;
if (n == "bigcap") { symbol = QChar(0x5c); heightIsAscent = true; exactAscent = true; }
else if (n == "bigcup") { symbol = QChar(0x5b); heightIsAscent = true; exactAscent = true; }
else if (n == "bigvee") { symbol = QChar(0x5F); heightIsAscent = true; exactAscent = true; }
else if (n == "bighat") { symbol = QChar(0x5E); heightIsAscent = true; exactAscent = true; }
else if (n == "oint") { symbol = QChar(0x49); yfactor = +0.1; }
else if (n == "coprod") { symbol = QChar(0x61); heightIsAscent = true; exactAscent = true; }
else if (n == "iint") { symbol = QString(2, QChar(0x5A)); yfactor = +0.1; }
else if (n == "iiint") { symbol = QString(3, QChar(0x5A)); yfactor = +0.1; }
else if (n == "sum") { symbol = QChar(0x58); heightIsAscent = true; exactAscent = true; }
else if (n == "prod") { symbol = QChar(0x59); heightIsAscent = true; exactAscent = true; }
}
}
}
}
}
}
if (addWhitespace) symbol=symbol+" ";
static QSet<QString> extraSymbolName = {
"infty",
"|", " ", "quad", "qquad", "space", ";", ":", ",", "!",
"longleftarrow", "longrightarrow",
"Longleftarrow", "Longrightarrow",
"longleftrightarrow", "Longleftrightarrow"
};
if (symbol.simplified().isEmpty() && !extraSymbolName.contains(n)) {
parent->error_list.append(tr("unknown symbol '%1' found!").arg(n));
}
//std::cout<<"symbol node '"<<symbolName.toStdString()<<"': symbol='"<<symbol.toStdString()<<"'\n";
}
JKQTMathText::MTsymbolNode::~MTsymbolNode() = default;
QString JKQTMathText::MTsymbolNode::getTypeName() const
{
return QLatin1String("MTsymbolNode(")+symbolName+QLatin1String(")");
}
QFont JKQTMathText::MTsymbolNode::getFontName(symbolFont f, QFont& fi) const {
QFont fr=fi;
switch(f) {
case MTSFgreek: fr.setFamily(parent->getFontGreek()); break;
case MTSFsymbol: fr.setFamily(parent->getFontSymbol()); break;
case MTSFbraces: fr.setFamily(parent->getFontBraces()); break;
case MTSFintegrals: fr.setFamily(parent->getFontIntegrals()); break;
case MTSFcaligraphic: fr.setFamily(parent->getFontCaligraphic()); break;
case MTSFblackboard: fr.setFamily(parent->getFontBlackboard()); break;
default: break;
}
return fr;
}
void JKQTMathText::MTsymbolNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) {
QFont f=currentEv.getFont(parent);
f=getFontName(font, f);
f.setPointSizeF(f.pointSizeF()*fontFactor);
if (italic<0) f.setItalic(false);
if (italic>0) f.setItalic(true);
if (bold<0) f.setBold(false);
if (bold>0) f.setBold(true);
QFontMetricsF fm(f, painter.device());
QString symb=symbol;
width=0;
if (currentEv.insideMath) width=qMax(parent->getTightBoundingRect(f, symb, painter.device()).width(),parent->getTightBoundingRect(f, "i", painter.device()).width());//fm.width(symbol);
else width=fm.boundingRect(symb).width();//fm.width(symbol);
width=qMax(fm.width("j"), width);
if (symb.isEmpty()) {
width=fm.width("a");
if (symbolName=="|") width=fm.width("1")*0.8;
else if (symbolName=="infty") width=fm.width("M");
else if (symbolName=="quad" || symbolName=="qquad") width=parent->getTightBoundingRect(f, "M", painter.device()).width();
else if (symbolName==" " || symbolName=="space") width=parent->getTightBoundingRect(f, "x", painter.device()).width();
else if (symbolName==";") width=parent->getTightBoundingRect(f, "x", painter.device()).width()*0.75;
else if (symbolName==":") width=parent->getTightBoundingRect(f, "x", painter.device()).width()*0.5;
else if (symbolName==",") width=parent->getTightBoundingRect(f, "x", painter.device()).width()*0.25;
else if (symbolName=="!") width=-parent->getTightBoundingRect(f, "x", painter.device()).width()*0.25;
else if (symbolName=="longleftarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; }
else if (symbolName=="longrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; }
else if (symbolName=="Longleftarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; }
else if (symbolName=="Longrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; }
else if (symbolName=="longleftrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; }
else if (symbolName=="Longleftrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; }
}
QRectF tbr=parent->getTightBoundingRect(f, symb, painter.device());
overallHeight=tbr.height();// fm.height();
baselineHeight=tbr.height()-tbr.bottom();
if (exactAscent) {
//baselineHeight=fm.ascent()*0.8;
}
if (heightIsAscent) {
overallHeight=baselineHeight*1.1;
}
if (exactAscent && heightIsAscent) {
//qDebug()<<symbolName<<symbol<<tbr.top()<<tbr.bottom()<<tbr.height();
baselineHeight=tbr.height()-tbr.bottom();//fm.ascent()*0.8;
overallHeight=tbr.height();//baselineHeight*1.1;
}
strikeoutPos=fm.strikeOutPos();
if (extendWidthInMathmode && currentEv.insideMath) width=width*parent->getMathoperatorWidthFactor();
}
double JKQTMathText::MTsymbolNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
double width=0;
double baselineHeight=0;
double overallHeight=0, strikeoutPos=0;
getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
QPen pold=painter.pen();
QFont fold=painter.font();
QFont f=currentEv.getFont(parent);
QFont f1=f;
f=getFontName(font, f);
f.setPointSizeF(f.pointSizeF()*fontFactor);
if (italic<0) f.setItalic(false);
if (italic>0) f.setItalic(true);
if (bold<0) f.setBold(false);
if (bold>0) f.setBold(true);
QFontMetricsF fm(f, painter.device());
QFontMetricsF fm1(f1, painter.device());
painter.setFont(f);
double shift=0;
if (extendWidthInMathmode && currentEv.insideMath) {
double origwidth=width/parent->getMathoperatorWidthFactor();
shift=0.5*(width-origwidth);
//width=width*parent->getMathoperatorWidthFactor();
}
//std::cout<<"symbol '"<<symbolName.toStdString()<<"' = "<<std::hex<<symbol.at(0).digitValue()<<" in font '"<<f.family().toStdString()<<"' ("<<QFontInfo(f).family().toStdString()<<"): "<<fm.inFont(symbol.at(0))<<std::endl;
QPen p=painter.pen();
p.setColor(currentEv.color);
p.setWidthF(qMax(JKQTMathText::ABS_MIN_LINEWIDTH, fm.lineWidth()));
p.setStyle(Qt::SolidLine);
painter.setPen(p);
double xwi=fm.width("x");
if (!symbol.isEmpty()) {
// if the symbol has been recognized in the constructor: draw the symbol
painter.drawText(QPointF(x+shift, y+yfactor*overallHeight), symbol);
double xx=x+shift;
double yy=y-fm.xHeight()-(parent->getTightBoundingRect(f, "M", painter.device()).height()-fm.xHeight())/3.0;
QLineF l(xx, yy, xx+xwi/3.0+((currentEv.italic)?(xwi/3.0):0), yy);
if (drawBar&&l.length()>0) painter.drawLine(l);
// try to draw some often used special symbols, by synthesizing them from
// standard characters in the current drawing font
} else if (symbolName=="infty") {
//std::cout<<"draw infty\n";
f1.setItalic(false);
painter.setFont(f1);
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.translate(x+shift+fm1.width("8")/3.0, y-fm1.xHeight());
painter.rotate(90);
painter.drawText(QPointF(0,0), "8");
} else if (symbolName=="|") {
//std::cout<<"draw infty\n";
f1.setItalic(false);
painter.setFont(f1);
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.translate(x+shift, y);
painter.drawText(QPointF(0,0), "|");
painter.translate(fm1.width("8")/3.0, 0);
painter.drawText(QPointF(0,0), "|");
// here are some spaces
} else if (symbolName==" ") { // full space (width of x)
} else if (symbolName=="space") { // full space (width of x)
} else if (symbolName=="qquad") { // full space(width of M)
} else if (symbolName=="quad") { // full space(width of M)
} else if (symbolName==";") { // 75% space
} else if (symbolName==":") { // 50% space
} else if (symbolName==",") { // 25% space
} else if (symbolName=="!") { // -25% space
} else if (symbolName=="longleftarrow") {
double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0;
double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25;
double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0;
QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, false);
painter.drawPath(path);
} else if (symbolName=="longrightarrow"){
double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0;
double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25;
double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0;
QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, false, true);
painter.drawPath(path);
} else if (symbolName=="Longleftarrow") {
double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0;
double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25;
double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0;
QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, false);
painter.drawPath(path);
} else if (symbolName=="Longrightarrow") {
double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0;
double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25;
double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0;
QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, false, true);
painter.drawPath(path);
} else if (symbolName=="longleftrightarrow") {
double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0;
double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25;
double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0;
QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, true);
painter.drawPath(path);
} else if (symbolName=="Longleftrightarrow") {
double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0;
double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25;
double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0;
QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, true);
painter.drawPath(path);
} else { // draw a box to indicate an unavailable symbol
QRectF tbr=parent->getTightBoundingRect(f, "M", painter.device());
painter.drawRect(QRectF(x+shift,y-tbr.height(), xwi, tbr.height()*0.8));
}
painter.setPen(pold);
painter.setFont(fold);
return x+width;
}
bool JKQTMathText::MTsymbolNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) {
bool ok=true;
QString s;
JKQTMathText::MTenvironment ev=currentEv;
static QMap<QString, QString> entitylut;
if (entitylut.isEmpty()) {
entitylut.insert("sin", "sin");
entitylut.insert("cos", "cos");
entitylut.insert("tan", "tan");
entitylut.insert("sinh", "sinh");
entitylut.insert("cosh", "cosh");
entitylut.insert("tanh", "tanh");
entitylut.insert("atan", "atan");
entitylut.insert("acos", "acos");
entitylut.insert("asin", "asin");
entitylut.insert("arcsin", "arcsin");
entitylut.insert("arccos", "arccos");
entitylut.insert("arctan", "arctan");
entitylut.insert("ii", "i");
entitylut.insert("dd", "d");
entitylut.insert("exp", "exp");
entitylut.insert("log", "log");
entitylut.insert("ln", "ln");
entitylut.insert("ld", "ld");
entitylut.insert("lb", "lb");
entitylut.insert("erf", "erf");
entitylut.insert("mod", "mod");
entitylut.insert("median", "median");
entitylut.insert("min", "min");
entitylut.insert("max", "max");
entitylut.insert("argmin", "argmin");
entitylut.insert("argmax", "argmax");
entitylut.insert("inf", "inf");
entitylut.insert("sup", "sup");
entitylut.insert("liminf", "liminf");
entitylut.insert("limsup", "limsup");
entitylut.insert("lim", "lim");
entitylut.insert("sec", "sec");
entitylut.insert("gcd", "gcd");
entitylut.insert("hom", "hom");
entitylut.insert("ker", "ker");
entitylut.insert("dim", "dim");
entitylut.insert("cot", "cot");
entitylut.insert("arg", "arg");
entitylut.insert("det", "det");
entitylut.insert("deg", "deg");
entitylut.insert("sign", "sign");
entitylut.insert("sgn", "sgn");
entitylut.insert("Pr", "Pr");
entitylut.insert("coth", "coth");
entitylut.insert("alpha", "&alpha;");
entitylut.insert("beta", "&beta;");
entitylut.insert("gamma", "&gamma;");
entitylut.insert("delta", "&delta;");
entitylut.insert("epsilon", "&epsilon;");
entitylut.insert("varepsilon", "&epsilon;");
entitylut.insert("zeta", "&zeta;");
entitylut.insert("eta", "&eta;");
entitylut.insert("theta", "&theta;");
entitylut.insert("vartheta", "&thetasym;");
entitylut.insert("iota", "&iota;");
entitylut.insert("kappa", "&kappa;");
entitylut.insert("lambda", "&lambda;");
entitylut.insert("mu", "&mu;");
entitylut.insert("nu", "&nu;");
entitylut.insert("xi", "&xi;");
entitylut.insert("pi", "&pi;");
entitylut.insert("varpi", "&piv;");
entitylut.insert("rho", "&rho;");
entitylut.insert("sigma", "&sigma;");
entitylut.insert("varsigma", "&sigmaf;");
entitylut.insert("tau", "&tau;");
entitylut.insert("upsilon", "&upsilon;");
entitylut.insert("phi", "&phi;");
entitylut.insert("varphi", "&phi;");
entitylut.insert("chi", "&chi;");
entitylut.insert("psi", "&psi;");
entitylut.insert("omega", "&omega;");
entitylut.insert("Gamma", "&Gamma;");
entitylut.insert("Delta", "&Delta;");
entitylut.insert("Theta", "&Theta;");
entitylut.insert("Lambda", "&Lambda;");
entitylut.insert("Omega", "&Omega;");
entitylut.insert("Xi", "&Xi;");
entitylut.insert("Pi", "&Pi;");
entitylut.insert("Sigma", "&Sigma;");
entitylut.insert("Upsilon", "&Upsilon;");
entitylut.insert("Phi", "&Phi;");
entitylut.insert("Psi", "&Psi;");
entitylut.insert("leftrightarrow", "&harr;");
entitylut.insert("leftarrow", "&larr;");
entitylut.insert("rightarrow", "&rarr;");
entitylut.insert("to", "&rarr;");
entitylut.insert("uparrow", "&uarr;");
entitylut.insert("downarrow", "&darr;");
entitylut.insert("Leftrightarrow", "&hArr;");
entitylut.insert("iff", "&hArr;");
entitylut.insert("Leftarrow", "&lArr;");
entitylut.insert("Rightarrow", "&rArr;");
entitylut.insert("Uparrow", "&uArr;");
entitylut.insert("Downarrow", "&dArr;");
entitylut.insert("pm", "&plusmn;");
entitylut.insert("leq", "&le;");
entitylut.insert("geq", "&ge;");
entitylut.insert("times", "&times;");
entitylut.insert("propto", "&prop;");
entitylut.insert("partial", "&part;");
entitylut.insert("bullet", "&bull;");
entitylut.insert("neq", "&ne;");
entitylut.insert("ne", "&ne;");
entitylut.insert("equiv", "&equiv;");
entitylut.insert("approx", "&asymp;");
entitylut.insert("ellipsis", "...");
entitylut.insert("Im", "&image;");
entitylut.insert("Re", "&real;");
entitylut.insert("otimes", "&otimes;");
entitylut.insert("oplus", "&oplus;");
entitylut.insert("oslash", "/");
entitylut.insert("cap", "&cap;");
entitylut.insert("cup", "&cup;");
entitylut.insert("land", "&cap;");
entitylut.insert("lor", "&cup;");
entitylut.insert("supset", "&sup;");
entitylut.insert("supseteq", "&supe;");
entitylut.insert("supsetnot", "&nsup;");
entitylut.insert("subset", "&sub;");
entitylut.insert("subseteq", "&sube;");
entitylut.insert("in", "&isin;");
entitylut.insert("notin", "&notin;");
entitylut.insert("angle", "&ang;");
entitylut.insert("nabla", "&nabla;");
entitylut.insert("copyright", "&copy;");
entitylut.insert("registered", "&reg;");
entitylut.insert("trademark", "&trade;");
entitylut.insert("cdot", "&sdot;");
entitylut.insert("neg", "&not;");
entitylut.insert("wedge", "&and;");
entitylut.insert("vee", "&vee;");
entitylut.insert("diamond", "&loz;");
entitylut.insert("langle", "&lang;");
entitylut.insert("rangle", "&rang;");
entitylut.insert("int", "&int;");
entitylut.insert("forall", "&forall;");
entitylut.insert("exists", "&exist;");
entitylut.insert("cong", "&sim;");
entitylut.insert("bot", "&perp;");
entitylut.insert("ll", "<<");
entitylut.insert("gg", ">>");
entitylut.insert("bbC", "<b>C</b>");
entitylut.insert("bbH", "<b>H</b>");
entitylut.insert("bbN", "<b>N</b>");
entitylut.insert("bbP", "<b>P</b>");
entitylut.insert("bbQ", "<b>Q</b>");
entitylut.insert("bbR", "<b>R</b>");
entitylut.insert("bbZ", "<b>Z</b>");
entitylut.insert("Alef", "&alefsym;");
entitylut.insert("alef", "&alefsym;");
entitylut.insert("tilde", "~");
entitylut.insert("iint", "&int;&int;");
entitylut.insert("iiint", "&int;&int;&int;");
entitylut.insert("emptyset", "&empty;");
entitylut.insert("varnothing", "&empty;");
entitylut.insert("lceil", "&lceil;");
entitylut.insert("rceil", "&rceil;");
entitylut.insert("lfloor", "&lfloor;");
entitylut.insert("rfloor", "&rfloor;");
entitylut.insert("subsetnot", "&nsub;");
entitylut.insert("DC", "=");
entitylut.insert("cdots", "&sdot;&sdot;&sdot;");
entitylut.insert("dots", "...");
entitylut.insert("cent", "&cent;");
entitylut.insert("_", "_");
entitylut.insert("}", "}");
entitylut.insert("{", "{");
entitylut.insert("hbar", "&#8463;");
entitylut.insert("euro", "&euro;");
entitylut.insert("pound", "&pound;");
entitylut.insert("yen", "&yen;");
entitylut.insert("div", "&divide;");
entitylut.insert("backslash", "\\");
entitylut.insert("$", "$");
entitylut.insert("%", "%");
entitylut.insert("&", "&");
entitylut.insert("#", "#");
entitylut.insert("ast", "*");
entitylut.insert("glq", "'");
entitylut.insert("grq", "'");
entitylut.insert("glqq", "\"");
entitylut.insert("grqq", "\"");
entitylut.insert("flq", "&lt;");
entitylut.insert("frq", "&gt;");
entitylut.insert("flqq", "");
entitylut.insert("frqq", "");
}
QMap<QString, QString>::iterator itS = entitylut.find(symbolName);
if (itS!=entitylut.end()) { s=itS.value(); }
else if (symbolName == "sum") { ev.fontSize*=1.7; s="&sum;"; }
else if (symbolName == "prod") { ev.fontSize*=1.7; s="&prod;"; }
else if (symbolName == "bigcap") { ev.fontSize*=1.7; s="&cap;"; }
else if (symbolName == "bigcup") { ev.fontSize*=1.7; s="&cup;"; }
else if (symbolName == "bigvee") { ev.fontSize*=1.7; s="&or;"; }
else if (symbolName == "bighat") { ev.fontSize*=1.7; s="&and;"; }
else ok=false;
if (ok) html=html+ev.toHtmlStart(defaultEv)+s+ev.toHtmlAfter(defaultEv);
return ok;
}
QString JKQTMathText::MTsymbolNode::getSymbolFontName() const {
QFont f;
switch(font) {
case MTSFsymbol: return "symbol["+getFontName(font, f).family()+"]";
case MTSFgreek: return "greek["+getFontName(font, f).family()+"]";
case MTSFbraces: return "braces["+getFontName(font, f).family()+"]";
case MTSFintegrals: return "integrals["+getFontName(font, f).family()+"]";
case MTSFcaligraphic: return "caligraphic["+getFontName(font, f).family()+"]";
case MTSFblackboard: return "blackboard["+getFontName(font, f).family()+"]";
default:
case MTSFdefault:
return "default["+getFontName(font, f).family()+"]";
}
}
// --------------------------------------------------------------------------------------------------
// -- implementation of the JKQTMathText methods
// --------------------------------------------------------------------------------------------------
JKQTMathText::JKQTMathText(QObject* parent):
QObject(parent)
{
Q_INIT_RESOURCE(xits);
QFontDatabase fontdb;
QString serifFont="Serif";
QString sansFont="Sans";
QString symbolFont="Symbol";
QString scriptFont="Script";
QString typewriterFont="typewriter";
QString decorativeFont="decorative";
QStringList fonts=fontdb.families();
//qDebug()<<"fonts:\n"<<fonts;
if (fonts.contains("Times New Roman")) {
serifFont="Times New Roman";
} else if (fonts.contains("Times")) {
serifFont="Times";
} else if (fonts.contains("FreeSerif")) {
serifFont="FreeSerif";
}
if (fonts.contains("Arial")) {
sansFont="Arial";
} else if (fonts.contains("Helvetica")) {
sansFont="Helvetica";
} else if (fonts.contains("FreeSans")) {
sansFont="FreeSans";
}
if (fonts.contains("Symbol")) {
symbolFont="Symbol";
} else if (fonts.contains("Standard Symbols L")) {
symbolFont="Standard Symbols L";
}
if (fonts.contains("Courier")) {
typewriterFont="Courier";
} else if (fonts.contains("Courier New")) {
typewriterFont="Courier New";
} else if (fonts.contains("Courier Std")) {
typewriterFont="Courier Std";
} else if (fonts.contains("FreeMono")) {
typewriterFont="FreeMono";
}
default_fontSize=fontSize=10;
default_fontRoman=fontRoman=fontReplacements.value(serifFont, serifFont);
default_fontSans=fontSans=fontReplacements.value(sansFont, sansFont);
default_fontTypewriter=fontTypewriter=typewriterFont;
default_fontScript=fontScript=scriptFont;
default_fontGreek=fontGreek=symbolFont;
default_fontSymbol=fontSymbol=symbolFont;
default_fontCaligraphic=fontCaligraphic=decorativeFont;
default_fontBlackboard=fontBlackboard=serifFont;
default_fontBraces=fontBraces=fontRoman;
default_fontIntegrals=fontIntegrals=fontRoman;
default_fontEncoding=fontEncoding=MTFEwinSymbol;
default_fontLatexPostfix=fontLatexPostfix="10";
default_fontLatexPrefix=fontLatexPrefix="jlm_";
default_brace_factor=brace_factor=1.04;
default_subsuper_size_factor=subsuper_size_factor=0.7;
default_italic_correction_factor=italic_correction_factor=0.4;
default_sub_shift_factor=sub_shift_factor=0.4;
default_super_shift_factor=super_shift_factor=0.6;
default_brace_shrink_factor=brace_shrink_factor=0.6;
default_fontColor=fontColor=QColor("black");
default_useSTIXfonts=useSTIXfonts=false;
default_useXITSfonts=useXITSfonts=false;
default_useASANAfonts=useASANAfonts=false;
default_frac_factor=frac_factor=0.9;
default_frac_shift_factor=frac_shift_factor=0.4;
default_underbrace_factor=underbrace_factor=0.75;
default_undersetFactor=undersetFactor=0.7;
default_decoration_height_factor=decoration_height_factor=0.2;
default_brace_y_shift_factor=brace_y_shift_factor=0.7;//-1;
default_operatorsubsuper_size_factor=operatorsubsuper_size_factor=0.65;
default_mathoperator_width_factor=mathoperator_width_factor=1.5;
default_expensiveRendering=expensiveRendering=true;
useUnparsed=false;
parsedNode=nullptr;
unparsedNode=nullptr;
currentToken=MTTnone;
currentTokenName="";
currentTokenID=0;
parseString="";
parsingMathEnvironment=false;
}
JKQTMathText::~JKQTMathText() {
if (parsedNode!=nullptr) delete parsedNode;
parsedNode=nullptr;
if (unparsedNode!=nullptr) delete unparsedNode;
unparsedNode=nullptr;
}
void JKQTMathText::loadSettings(const QSettings& settings, const QString& group){
fontSize=settings.value(group+"font_size", fontSize).toDouble();
fontColor=jkqtp_String2QColor(settings.value(group+"font_color", jkqtp_QColor2String(fontColor)).toString());
setFontRoman(settings.value(group+"font_roman", fontRoman).toString());
setFontSans(settings.value(group+"font_sans", fontSans).toString());
fontTypewriter=settings.value(group+"font_typewriter", fontTypewriter).toString();
fontScript=settings.value(group+"font_script", fontScript).toString();
fontGreek=settings.value(group+"font_greek", fontGreek).toString();
fontSymbol=settings.value(group+"font_symbol", fontSymbol).toString();
fontBraces=settings.value(group+"font_braces", fontBraces).toString();
fontIntegrals=settings.value(group+"font_integrals", fontSans).toString();
fontBlackboard=settings.value(group+"font_blackboard", fontSans).toString();
fontCaligraphic=settings.value(group+"font_caligraphics", fontSans).toString();
brace_factor=settings.value(group+"brace_factor", brace_factor).toDouble();
brace_shrink_factor=settings.value(group+"brace_shrink_factor", brace_shrink_factor).toDouble();
subsuper_size_factor=settings.value(group+"subsuper_size_factor", subsuper_size_factor).toDouble();
italic_correction_factor=settings.value(group+"italic_correction_factor", italic_correction_factor).toDouble();
super_shift_factor=settings.value(group+"super_shift_factor", super_shift_factor).toDouble();
sub_shift_factor=settings.value(group+"sub_shift_factor", sub_shift_factor).toDouble();
frac_factor=settings.value(group+"frac_factor", frac_factor).toDouble();
frac_shift_factor=settings.value(group+"frac_shift_factor", frac_shift_factor).toDouble();
underbrace_factor=settings.value(group+"underbrace_factor", underbrace_factor).toDouble();
undersetFactor=settings.value(group+"undersetFactor", undersetFactor).toDouble();
brace_y_shift_factor=settings.value(group+"brace_y_shift_factor", brace_y_shift_factor).toDouble();
decoration_height_factor=settings.value(group+"decoration_height_factor", decoration_height_factor).toDouble();
operatorsubsuper_size_factor=settings.value(group+"operatorsubsuper_size_factor", operatorsubsuper_size_factor).toDouble();
mathoperator_width_factor=settings.value(group+"mathoperator_width_factor", mathoperator_width_factor).toDouble();
QString v=settings.value(group+"font_encoding", "win_symbol").toString().toLower();
fontEncoding=MTFEwinSymbol;
if (v=="unicode") fontEncoding=MTFEunicode;
useSTIXfonts=settings.value(group+"use_stix_fonts", false).toBool();
useXITSfonts=settings.value(group+"use_xits_fonts", false).toBool();
useASANAfonts=settings.value(group+"use_asana_fonts", false).toBool();
if (useSTIXfonts) useSTIX();
if (useXITSfonts) useXITS();
if (useASANAfonts) useASANA();
}
void JKQTMathText::saveSettings(QSettings& settings, const QString& group) const{
JKQTMTPROPERTYsave(settings, group, fontSize,"font_size");
if (fontColor!=default_fontColor) settings.setValue(group+"font_color", jkqtp_QColor2String(fontColor));
JKQTMTPROPERTYsave(settings, group, fontRoman, "font_roman");
JKQTMTPROPERTYsave(settings, group, fontSans, "font_sans");
JKQTMTPROPERTYsave(settings, group, fontTypewriter, "font_typewriter");
JKQTMTPROPERTYsave(settings, group, fontScript, "font_script");
JKQTMTPROPERTYsave(settings, group, fontGreek, "font_greek");
JKQTMTPROPERTYsave(settings, group, fontSymbol, "font_symbol");
JKQTMTPROPERTYsave(settings, group, fontBraces, "font_braces");
JKQTMTPROPERTYsave(settings, group, fontIntegrals, "font_integrals");
JKQTMTPROPERTYsave(settings, group, fontBlackboard, "font_blackboard");
JKQTMTPROPERTYsave(settings, group, fontCaligraphic, "font_caligraphic");
JKQTMTPROPERTYsave(settings, group, brace_factor, "brace_factor");
JKQTMTPROPERTYsave(settings, group, brace_shrink_factor, "brace_shrink_factor");
JKQTMTPROPERTYsave(settings, group, subsuper_size_factor, "subsuper_size_factor");
JKQTMTPROPERTYsave(settings, group, italic_correction_factor, "italic_correction_factor");
JKQTMTPROPERTYsave(settings, group, sub_shift_factor, "sub_shift_factor");
JKQTMTPROPERTYsave(settings, group, super_shift_factor, "super_shift_factor");
JKQTMTPROPERTYsave(settings, group, useSTIXfonts, "use_stix_fonts");
JKQTMTPROPERTYsave(settings, group, useXITSfonts, "use_xits_fonts");
JKQTMTPROPERTYsave(settings, group, useASANAfonts, "use_asana_fonts");
JKQTMTPROPERTYsave(settings, group, frac_factor, "frac_factor");
JKQTMTPROPERTYsave(settings, group, frac_shift_factor, "frac_shift_factor");
JKQTMTPROPERTYsave(settings, group, underbrace_factor, "underbrace_factor");
JKQTMTPROPERTYsave(settings, group, undersetFactor, "undersetFactor");
JKQTMTPROPERTYsave(settings, group, operatorsubsuper_size_factor, "operatorsubsuper_size_factor");
JKQTMTPROPERTYsave(settings, group, mathoperator_width_factor, "mathoperator_width_factor");
JKQTMTPROPERTYsave(settings, group, brace_y_shift_factor, "brace_y_shift_factor");
JKQTMTPROPERTYsave(settings, group, decoration_height_factor, "decoration_height_factor");
if (fontEncoding!=default_fontEncoding) {
if (fontEncoding==MTFEunicode) settings.setValue(group+"font_encoding", "unicode");
else if (fontEncoding==MTFEwinSymbol) settings.setValue(group+"font_encoding", "win_symbol");
}
}
void JKQTMathText::useSTIX() {
useSTIXfonts=true;
QString fontname="STIX Two Math Standard";
QString fontnametxt="STIX Two Text";
QFontDatabase fdb;
if (!fdb.families().contains(fontname)) {
fontname="STIX Math Standard";
fontnametxt="STIX Math Standard";
if (!fdb.families().contains(fontname)) {
fontname="STIX";
fontnametxt="Times New Roman";
if (!fdb.families().contains(fontname)) {
fontname="STIXGeneral";
fontnametxt="Times New Roman";
}
}
}
fontGreek=fontname;
fontSymbol=fontname;
fontBraces=fontname;
fontIntegrals=fontname;
fontRoman=fontnametxt;
fontEncoding=MTFEunicode;
brace_shrink_factor=0.6;
}
void JKQTMathText::useXITS()
{
//JKQTPAutoOutputTimer jkaaot(QString("JKQTMathText::useXITS():ALL"));
QFontDatabase fdb;
//qDebug()<<"has XITS: "<<fdb.families().contains("XITS");
if (!fdb.families().contains("XITS")) {
//JKQTPAutoOutputTimer jkaaot(QString("JKQTMathText::useXITS():addAutoXITS"));
int i=0;
if (QFile::exists(":/JKQTMathText/fonts/xits-bold.otf")) { i=QFontDatabase::addApplicationFont(":/JKQTMathText/fonts/xits-bold.otf"); }
//qDebug()<<QFontDatabase::applicationFontFamilies(i);
if (QFile::exists(":/JKQTMathText/fonts/xits-bolditalic.otf")) { i=QFontDatabase::addApplicationFont(":/JKQTMathText/fonts/xits-bolditalic.otf"); }
//qDebug()<<QFontDatabase::applicationFontFamilies(i);
if (QFile::exists(":/JKQTMathText/fonts/xits-italic.otf")) { i=QFontDatabase::addApplicationFont(":/JKQTMathText/fonts/xits-italic.otf"); }
//qDebug()<<QFontDatabase::applicationFontFamilies(i);
if (QFile::exists(":/JKQTMathText/fonts/xits-math.otf")) { i=QFontDatabase::addApplicationFont(":/JKQTMathText/fonts/xits-math.otf"); }
//qDebug()<<QFontDatabase::applicationFontFamilies(i);
if (QFile::exists(":/JKQTMathText/fonts/xits-mathbold.otf")) { i=QFontDatabase::addApplicationFont(":/JKQTMathText/fonts/xits-mathbold.otf"); }
//qDebug()<<QFontDatabase::applicationFontFamilies(i);
if (QFile::exists(":/JKQTMathText/fonts/xits-regular.otf")) { i=QFontDatabase::addApplicationFont(":/JKQTMathText/fonts/xits-regular.otf"); }
//qDebug()<<QFontDatabase::applicationFontFamilies(i);
(void)i;
}
//qDebug()<<"has XITS: "<<fdb.families().contains("XITS")<<"\n"<<fdb.families();
bool hasXITS=false;
if (defaultXITSMathFontName.size()==0/* || defaultXITSFontName.size()==0*/) {
{
//JKQTPAutoOutputTimer jkaaot(QString("JKQTMathText::useXITS():scanFamilies"));
for (int i=0; i<fdb.families().size(); i++) {
//::cout<<fdb.families().at(i).simplified().toStdString()<<"\n";
//qDebug()<<fdb.families().at(i).simplified();
if (fdb.families().at(i).contains("XITS Math")) {
//hasXITSMath=true;
defaultXITSMathFontName=fdb.families().at(i);
} else if (fdb.families().at(i).contains("XITS")) {
hasXITS=true;
defaultXITSFontName=fdb.families().at(i);
}
}
}
} else {
hasXITS=true;
}
QString fam="XITS";
if (hasXITS) fam=defaultXITSFontName;
//if (hasXITSMath) fam=defaultXITSMathFontName;
useXITSfonts=true;
fontRoman=fam;
//fontSans=fam;
//fontTypewriter=fam;
fontBlackboard=fam;
//fontCaligraphic=fam;
//fontScript=fam;
fontBraces=fam;
fontSymbol=fam;
fontGreek=fam;
fontEncoding=MTFEunicode;
brace_shrink_factor=0.6;
}
void JKQTMathText::useASANA()
{
QFontDatabase fdb;
#ifdef AUTOLOAD_XITS_FONTS
//qDebug()<<"has XITS: "<<fdb.families().contains("XITS");
if (!fdb.families().contains("Asana")) {
//int i;//=-1;
if (QFile::exists(":/JKQTMathText/fonts/asana-math.otf")) { /*i=*/QFontDatabase::addApplicationFont(":/JKQTMathText/fonts/asana-math.otf"); }
//qDebug()<<QFontDatabase::applicationFontFamilies(i);
}
#endif
//qDebug()<<"has ASANA: "<<fdb.families().contains("Asana Math");
bool hasXITS=false;
QString XITSfam;
//bool hasXITSMath=false;
QString XITSMathfam;
for (int i=0; i<fdb.families().size(); i++) {
if (fdb.families().at(i).contains("Asana Math")) {
//hasXITSMath=true;
XITSMathfam=fdb.families().at(i);
} else if (fdb.families().at(i).contains("Asana")) {
hasXITS=true;
XITSfam=fdb.families().at(i);
}
}
QString fam="Asana Math";
if (hasXITS) fam=XITSfam;
useXITSfonts=true;
fontRoman=fam;
//fontSans=fam;
fontTypewriter=fam;
fontBlackboard=fam;
fontCaligraphic=fam;
fontScript=fam;
fontBraces=fam;
fontSymbol=fam;
fontGreek=fam;
fontEncoding=MTFEunicode;
brace_shrink_factor=0.6;
}
void JKQTMathText::useLatexFonts(QString prefix, const QString& postfix) {
fontLatexPostfix=postfix;
fontLatexPrefix=prefix;
fontRoman=prefix+"cmr"+postfix;
fontSans=prefix+"cmss"+postfix;
fontTypewriter=prefix+"cmtt"+postfix;
fontBlackboard=prefix+"dsrom"+postfix;
fontCaligraphic=prefix+"csmy"+postfix;
fontScript=prefix+"rsfs"+postfix;
fontBraces=prefix+"cmex"+postfix;
fontSymbol=prefix+"cmsy"+postfix;
fontGreek=prefix+"cmmi"+postfix;
fontEncoding=MTFElatex;
brace_shrink_factor=0.6;
}
QString JKQTMathText::toHtml(bool *ok, double fontPointSize) {
QString s;
bool okk=false;
if (getTree()!=nullptr) {
MTenvironment ev;
ev.color=fontColor;
ev.fontSize=fontPointSize;
MTenvironment defaultev;
defaultev.fontSize=fontPointSize;
okk=getTree()->toHtml(s, ev, defaultev);
}
if (ok) *ok=okk;
return s;
}
void JKQTMathText::addReplacementFont(const QString &nonUseFont, const QString &useFont) {
fontReplacements.insert(nonUseFont, useFont);
}
void JKQTMathText::setFontRomanOrSpecial(const QString &__value)
{
if (__value.toUpper()=="XITS") {
useXITS();
} else if (__value.toUpper()=="STIX") {
useSTIX();
} else if (__value.toUpper()=="ASANA") {
useASANA();
} else {
if (__value.toUpper().endsWith("+XITS")) {
useXITS();
setFontRoman(__value.left(__value.size()-5));
} else if (__value.toUpper().endsWith("+STIX")) {
useSTIX();
setFontRoman(__value.left(__value.size()-5));
} else if (__value.toUpper().endsWith("+ASANA")) {
useASANA();
setFontRoman(__value.left(__value.size()-6));
} else {
setFontRoman(__value);
}
}
}
void JKQTMathText::useAnyUnicode(QString timesFont, const QString& sansFont, bool fullMathUnicodeFont) {
if (!timesFont.isEmpty()) { setFontRoman(timesFont); }
if (!sansFont.isEmpty()) { setFontSans(sansFont); }
useSTIXfonts=false;
useXITSfonts=false;
useASANAfonts=false;
if (fullMathUnicodeFont) {
fontGreek=fontRoman;
fontSymbol=fontRoman;
fontIntegrals=fontRoman;
fontEncoding=MTFEunicode;
} else {
fontEncoding=MTFEunicodeLimited;
}
fontBraces=fontRoman;
brace_shrink_factor=0.6;
}
JKQTMathText::tokenType JKQTMathText::getToken() {
currentTokenID++;
if (currentTokenID>parseString.size()-1) return currentToken=MTTnone;
QChar c=parseString[currentTokenID];
currentTokenName="";
if (c=='\\') { // read an instruction name
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==' ') {
currentTokenName=c; // parse one-symbol instructions like \\, \& ...
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTinstruction;
} else { // parse letter instructions
while (c.isLetter()&& (currentTokenID<parseString.size())) {
currentTokenName+=c;
currentTokenID++;
if (currentTokenID<parseString.size()) c=parseString[currentTokenID];
}
if (!c.isLetter()) currentTokenID--;
currentTokenName=currentTokenName.trimmed();
}
//std::cout<<"found instruction node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTinstruction;
} else if (c=='$') {
//std::cout<<"found dollar\n";
return currentToken=MTTdollar;
} else if (c=='&') {
//std::cout<<"found ampersand\n";
return currentToken=MTTampersand;
} else if (c=='{') {
//std::cout<<"found openbrace\n";
return currentToken=MTTopenbrace;
} else if (c=='}') {
//std::cout<<"found closebrace\n";
return currentToken=MTTclosebrace;
} else if (c=='_') {
//std::cout<<"found underscore\n";
return currentToken=MTTunderscore;
} else if (c=='^') {
//std::cout<<"found hat\n";
return currentToken=MTThat;
} else if (c.isSpace()) {
while (c.isSpace() &&(currentTokenID<parseString.size())) { // eat up whitespace
currentTokenID++;
if (currentTokenID<parseString.size())c=parseString[currentTokenID];
}
if (!c.isSpace()) currentTokenID--;
//std::cout<<"found whitespace\n";
return currentToken=MTTwhitespace;
} else {
if (parsingMathEnvironment) {
// inside math environments we split texts at every brace {[(|)]} so that
// braces form their own MTtextNode and may be formated accordingly
if (c=='(' || c=='[' || c=='|' || c==')' || c==']') {
currentTokenName=c;
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTtext;
}
while (c!='(' && c!='&' && c!='[' && c!='|' && c!=')' && c!=']' && c!='\\' && c!='$' && c!='{' && c!='}' && c!='_' && c!='^' && (currentTokenID<parseString.size())) {
// add whitespaces only once
if (c.isSpace()) {
if (!currentTokenName.isEmpty()) {
if (!currentTokenName[currentTokenName.size()-1].isSpace())
currentTokenName+=c;
}
} else currentTokenName+=c;
currentTokenID++;
if (currentTokenID<parseString.size())c=parseString[currentTokenID];
}
if (c=='&' || c=='(' || c=='[' || c=='|' || c==')' || c==']' || c=='\\' || c=='$' || c=='{' || c=='}' || c=='_' || c=='^' || c.isSpace()) currentTokenID--;
//currentTokenName=currentTokenName.trimmed();
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTtext;
} else {
while ((!c.isSpace()) && c!='&' && c!='\\' && c!='$' && c!='{' && c!='}' && c!='_' && c!='^' && (currentTokenID<parseString.size())) {
// add whitespaces only once
if (c.isSpace()) {
if (!currentTokenName.isEmpty()) {
if (!currentTokenName[currentTokenName.size()-1].isSpace())
currentTokenName+=c;
}
} else currentTokenName+=c;
currentTokenID++;
if (currentTokenID<parseString.size())c=parseString[currentTokenID];
}
if (c=='&' || c=='\\' || c=='$' || c=='{' || c=='}' || c=='_' || c=='^' || c.isSpace()) currentTokenID--;
//currentTokenName=currentTokenName.trimmed();
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTtext;
}
}
return currentToken=MTTnone;
}
JKQTMathText::MTnode* JKQTMathText::parseLatexString(bool get, const QString& quitOnClosingBrace, const QString& quitOnEnvironmentEnd) {
//std::cout<<" entering parseLatexString()\n";
MTlistNode* nl=new MTlistNode(this);
if (get) getToken();
bool getNew=true;
while (currentToken!=MTTnone) {
getNew=true;
if (currentToken==MTTtext) {
QString text=currentTokenName;
bool addWhite=(getToken()==MTTwhitespace) && (!parsingMathEnvironment);
getNew=addWhite;
nl->addNode(new MTtextNode(this, text, addWhite, parsingMathEnvironment));
} else if (currentToken==MTTinstruction) {
QString name=currentTokenName;
if (name=="\\") break; // break on linebrak character
getToken(); // look at next token
if (currentToken==MTTopenbrace) {
//std::cout<<"found '{' after '"<<name.toStdString()<<"'\n";
if (name=="sqrt") {
nl->addNode(new MTsqrtNode(this, parseLatexString(true)));
} else if (name=="cbrt") {
nl->addNode(new MTsqrtNode(this, parseLatexString(true), 3));
} else if (name=="verb") {
QString text="";
currentTokenID++;
if (currentTokenID<=parseString.size()-1) {
QChar c=parseString[currentTokenID];
while (c!='}' && (currentTokenID<parseString.size())) {
text=text+c;
currentTokenID++;
if (currentTokenID<parseString.size()) c=parseString[currentTokenID];
}
if (c!='}') error_list.append(tr("error @ ch. %1: \verb{...} not closed by '}'").arg(currentTokenID).arg(name));
nl->addNode(new MTtextNode(this, text, false));
}
} else if (name=="frac") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTbraceNode(this, "(", ")", new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
MTnode* n1=parseLatexString(true);
MTnode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, 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") {
if (getToken()==MTTtext) {
QString envname=currentTokenName;
while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name'
if (envname=="matrix" || envname=="array" || envname=="aligned" || envname=="align" || envname=="cases" || envname=="pmatrix"|| envname=="bmatrix"|| envname=="Bmatrix"|| envname=="vmatrix"|| envname=="Vmatrix") {
QVector< QVector<MTnode*> > items;
//int lines=0;
//int cols=0;
bool first=true;
QVector<MTnode*> line;
//std::cout<<"found \\begin{matrix}\n";
while (first || currentToken==MTTampersand || (currentToken==MTTinstruction && currentTokenName=="\\")) {
MTnode* it=parseLatexString(true, "", envname);
if (currentToken==MTTampersand) {
//std::cout<<" appending item\n";
line.append(it);
} else {
line.append(it);
//std::cout<<" appending item and line with "<<line.size()<<" items.\n";
items.append(line);
line.clear();
}
first=false;
}
//std::cout<<" creating matrix-node with "<<items.size()<<" items.\n";
if (envname=="pmatrix") nl->addNode(new MTbraceNode(this, "(", ")", new MTmatrixNode(this, items)));
else if (envname=="cases") nl->addNode(new MTbraceNode(this, "{", "", new MTmatrixNode(this, items)));
else if (envname=="bmatrix") nl->addNode(new MTbraceNode(this, "[", "]", new MTmatrixNode(this, items)));
else if (envname=="Bmatrix") nl->addNode(new MTbraceNode(this, "{", "}", new MTmatrixNode(this, items)));
else if (envname=="vmatrix") nl->addNode(new MTbraceNode(this, "|", "|", new MTmatrixNode(this, items)));
else if (envname=="Vmatrix") nl->addNode(new MTbraceNode(this, "||", "||", new MTmatrixNode(this, items)));
else nl->addNode(new MTmatrixNode(this, items));
//std::cout<<" creating matrix-node ... done!\n";
} else {
error_list.append(tr("error @ ch. %1: unknown environment '%2'").arg(currentTokenID).arg(envname));
}
} else { // find next '}'
error_list.append(tr("error @ ch. %1: text after '\\begin{' expected!").arg(currentTokenID));
while (currentToken!=MTTclosebrace) getToken();
getNew=true;
}
} else if (name=="end") {
if (getToken()==MTTtext) {
QString envname=currentTokenName;
while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name'
if (envname==quitOnEnvironmentEnd) {
break;
} else {
error_list.append(tr("error @ ch. %1: '\\end{%2}' widthout preceding '\\begin{%3}'").arg(currentTokenID).arg(envname).arg(envname));
}
} else { // find next '}'
error_list.append(tr("error @ ch. %1: text after '\\begin{' expected!").arg(currentTokenID));
while (currentToken!=MTTclosebrace) getToken();
getNew=true;
}
} else if (name=="vec") {
nl->addNode(new MTdecoratedNode(this, MTDvec, parseLatexString(true)));
} else if (name=="overline"||name=="oline"||name=="ol") {
nl->addNode(new MTdecoratedNode(this, MTDoverline, parseLatexString(true)));
} else if (name=="underline"||name=="uline"||name=="ul") {
nl->addNode(new MTdecoratedNode(this, MTDunderline, parseLatexString(true)));
} else if (name=="uuline"||name=="uul") {
nl->addNode(new MTdecoratedNode(this, MTDdoubleunderline, parseLatexString(true)));
} else if (name=="ooline"||name=="ool") {
nl->addNode(new MTdecoratedNode(this, MTDdoubleoverline, parseLatexString(true)));
} else if (name=="arrow") {
nl->addNode(new MTdecoratedNode(this, MTDarrow, parseLatexString(true)));
} else if (name=="hat") {
nl->addNode(new MTdecoratedNode(this, MTDhat, parseLatexString(true)));
} else if (name=="bar") {
nl->addNode(new MTdecoratedNode(this, MTDbar, parseLatexString(true)));
} else if (name=="dot") {
nl->addNode(new MTdecoratedNode(this, MTDdot, parseLatexString(true)));
} else if (name=="tilde") {
nl->addNode(new MTdecoratedNode(this, MTDtilde, parseLatexString(true)));
} else if (name=="ddot") {
nl->addNode(new MTdecoratedNode(this, MTDddot, parseLatexString(true)));
} else {
if (name=="textcolor" || name=="mathcolor" || name=="color" || name=="colorbox") {
bool foundError=true;
QString col="";
if (getToken()==MTTtext) {
col=currentTokenName;
if (getToken()==MTTclosebrace) {
if (getToken()==MTTopenbrace) {
foundError=false;
}
}
}
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 MTinstruction1Node(this, name, parseLatexString(true), QStringList(col)));
} else {
nl->addNode(new MTinstruction1Node(this, name, parseLatexString(true)));
}
}
} else {
//std::cout<<"did not find '{' after '"<<name.toStdString()<<"'\n";
if (name=="right") {
if (currentToken==MTTtext) {
if (currentTokenName.size()>0) {
if (QString(currentTokenName[0])==quitOnClosingBrace || quitOnClosingBrace=="any" || QString(currentTokenName[0])==".") {
//std::cout<<"found \\right '"<<currentTokenName.toStdString()<<"'\n";
showRightBrace=(QString(currentTokenName[0])!=".");
//if (!showRightBrace) std::cout<<"don't show right brace '"<<quitOnClosingBrace.toStdString()<<"' !!!\n";
if (quitOnClosingBrace!="any") currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
} else {
getNew=false;
}
}
} else if (currentToken==MTTinstruction) {
if (quitOnClosingBrace=="~" && (currentTokenName=="rceil" || QString(currentTokenName[0])==".")) {
showRightBrace=(QString(currentTokenName[0])!=".");
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
} else if (quitOnClosingBrace=="}" && (currentTokenName=="}" || QString(currentTokenName[0])==".")) {
showRightBrace=(QString(currentTokenName[0])!=".");
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
} else if (quitOnClosingBrace=="_" && (currentTokenName=="rfloor" || QString(currentTokenName[0])==".")) {
showRightBrace=(QString(currentTokenName[0])!=".");
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
} else if (quitOnClosingBrace=="#" && (currentTokenName=="|" || QString(currentTokenName[0])==".")) {
showRightBrace=(QString(currentTokenName[0])!=".");
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
} else if (quitOnClosingBrace==">" && (currentTokenName=="rangle" || QString(currentTokenName[0])==".")) {
showRightBrace=(QString(currentTokenName[0])!=".");
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
} else if (quitOnClosingBrace=="any") {
showRightBrace=(QString(currentTokenName[0])!=".");
//currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
}
} else {
getNew=false;
}
} else if (name=="left") {
if (currentToken==MTTtext) {
if (currentTokenName.size()>0) {
if (currentTokenName[0]=='(') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1); // we already used the first character from the text token!
nl->addNode(new MTbraceNode(this, "(", ")", parseLatexString(currentTokenName.size()<=0, ")"), showRightBrace));
} else if (currentTokenName[0]=='[') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "[", "]", parseLatexString(currentTokenName.size()<=0, "]"), showRightBrace));
} else if (currentTokenName[0]=='{') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "{", "}", parseLatexString(currentTokenName.size()<=0, "}"), showRightBrace));
} else if (currentTokenName[0]=='<') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "<", ">", parseLatexString(currentTokenName.size()<=0, ">"), showRightBrace));
} else if (currentTokenName[0]=='|') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "|", "|", parseLatexString(currentTokenName.size()<=0, "|"), showRightBrace));
} else if (currentTokenName[0]=='~') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "~", "~", parseLatexString(currentTokenName.size()<=0, "~"), showRightBrace));
} else if (currentTokenName[0]=='_') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "_", "_", parseLatexString(currentTokenName.size()<=0, "_"), showRightBrace));
} else if (currentTokenName[0]=='#') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "#", "#", parseLatexString(currentTokenName.size()<=0, "#"), showRightBrace));
} else if (currentTokenName[0]=='.') {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
JKQTMathText::MTnode* cn=parseLatexString(currentTokenName.size()<=0, "any");
nl->addNode(new MTbraceNode(this, ".", currentTokenName, cn, showRightBrace));
} else {
getNew=false;
}
}
} else if (currentToken==MTTinstruction && currentTokenName=="langle") {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "<", ">", parseLatexString(true, ">"), showRightBrace));
} else if (currentToken==MTTinstruction && currentTokenName=="{") {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "{", "}", parseLatexString(currentTokenName.size()<=0, "}"), showRightBrace));
} else if (currentToken==MTTinstruction && currentTokenName=="lfloor") {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "_", "_", parseLatexString(true, "_"), showRightBrace));
} else if (currentToken==MTTinstruction && currentTokenName=="lceil") {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "~", "~", parseLatexString(true, "~"), showRightBrace));
} else if (currentToken==MTTinstruction && currentTokenName=="|") {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
nl->addNode(new MTbraceNode(this, "#", "#", parseLatexString(currentTokenName.size()<=0, "#"), showRightBrace));
} else if (currentToken==MTTinstruction && currentTokenName==quitOnClosingBrace) {
break;
}
} 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 (n0=='v' && n1.isLetter()) {
done=true;
//std::cout<<"found \\v... command\n";
nl->addNode(new MTdecoratedNode(this, MTDvec, new MTtextNode(this, QString(n1), false, parsingMathEnvironment)));
} else if (n0=='c' && n1.isLetter()) {
done=true;
//std::cout<<"found \\v... command\n";
nl->addNode(new MTinstruction1Node(this, "mathcal", new MTtextNode(this, QString(n1), false, parsingMathEnvironment)));
}
} else if (name.size()==3) {
QString n0=name.left(2);
QChar n1=name[name.size()-1];
if (n0=="bb" && n1.isLetter()) {
done=true;
//std::cout<<"found \\v... command\n";
nl->addNode(new MTinstruction1Node(this, "mathbb", new MTtextNode(this, QString(n1), false, parsingMathEnvironment)));
}
}
if (!done) nl->addNode(new MTsymbolNode(this, name, false));//, addWhite));
}
}
} else if (currentToken==MTTwhitespace) {
if (!parsingMathEnvironment) nl->addNode(new MTwhitespaceNode(this));
} else if (currentToken==MTTunderscore) {
getToken();
MTnode* child=nullptr;
MTnode* child2=nullptr;
if (currentToken==MTTinstruction) {
QString name=currentTokenName;
getToken(); // look at next token
if (currentToken==MTTopenbrace) {
child=new MTinstruction1Node(this, name, parseLatexString(true));
} else {
//bool addWhite=(currentToken==MTTwhitespace);
//getNew=addWhite;
//child=new MTsymbolNode(this, name, addWhite);
getNew=false;
child=new MTsymbolNode(this, name, false);
}
} else if (currentToken==MTTopenbrace) {
child=parseLatexString(true);
} else if (currentToken==MTTtext) {
if (currentTokenName.size()<=1) {
child=new MTtextNode(this, currentTokenName, false, parsingMathEnvironment);
} else {
child=new MTtextNode(this, QString(currentTokenName[0]), false, parsingMathEnvironment);
child2=new MTtextNode(this, currentTokenName.right(currentTokenName.size()-1), false, parsingMathEnvironment);
}
} else {
getNew=false;
}
if (child!=nullptr) nl->addNode(new MTsubscriptNode(this, child));
if (child2!=nullptr) nl->addNode(child2);
} else if (currentToken==MTThat) {
getToken();
MTnode* child=nullptr;
MTnode* child2=nullptr;
if (currentToken==MTTinstruction) {
QString name=currentTokenName;
getToken(); // look at next token
if (currentToken==MTTopenbrace) {
child=new MTinstruction1Node(this, name, parseLatexString(true));
} else {
//bool addWhite=(currentToken==MTTwhitespace);
//getNew=addWhite;
//child=new MTsymbolNode(this, name, addWhite);
getNew=false;
child=new MTsymbolNode(this, name, false);
}
} else if (currentToken==MTTopenbrace) {
child=parseLatexString(true);
} else if (currentToken==MTTtext) {
if (currentTokenName.size()<=1) {
child=new MTtextNode(this, currentTokenName, false, parsingMathEnvironment);
} else {
child=new MTtextNode(this, QString(currentTokenName[0]), false, parsingMathEnvironment);
child2=new MTtextNode(this, currentTokenName.right(currentTokenName.size()-1), false, parsingMathEnvironment);
}
} else {
getNew=false;
}
if (child!=nullptr) nl->addNode(new MTsuperscriptNode(this, child));
if (child2!=nullptr) nl->addNode(child2);
} else if (currentToken==MTTopenbrace) {
nl->addNode(parseLatexString(true));
} else if (currentToken==MTTclosebrace) {
break;
} else if (currentToken==MTTampersand) {
break;
} else if (currentToken==MTTdollar) {
if (parsingMathEnvironment) { // reached end of math environment
parsingMathEnvironment=false;
break;
} else { // starting math environment
parsingMathEnvironment=true;
nl->addNode(new MTinstruction1Node(this, "equation", parseLatexString(true)));
}
}
if (getNew) getToken();
}
//std::cout<<" leaving parseLatexString()\n";
return nl;
}
QList<JKQTMathText::tbrData> JKQTMathText::tbrs=QList<JKQTMathText::tbrData>();
QHash<JKQTMathText::tbrDataH, QRectF> JKQTMathText::tbrh=QHash<JKQTMathText::tbrDataH, QRectF>();
QRectF JKQTMathText::getTightBoundingRect(const QFont &fm, const QString &text, QPaintDevice *pd)
{
JKQTMathText::tbrDataH dh(fm, text, pd);
if (pd) {
if (tbrh.contains(dh)) return tbrh[dh];
/*for (int i=0; i<tbrs.size(); i++) {
if (tbrs[i].f==fm && tbrs[i].text==text && (tbrs[i].ldpiX==pd->logicalDpiX() && tbrs[i].ldpiY==pd->logicalDpiY() && tbrs[i].pdpiX==pd->physicalDpiX() && tbrs[i].pdpiY==pd->physicalDpiY())) {
//qDebug()<<" ### "<<fm<<pd<<tbrs[i].text<<tbrs[i].tbr;
return tbrs[i].tbr;
}
}*/
} else {
//qDebug()<<"warning no pd";
}
tbrData d(fm, text, pd);
tbrs.append(d);
tbrh[dh]=d.tbr;
//qDebug()<<"TBRs lits: "<<tbrs.size();
//qDebug()<<"+++ "<<fm<<pd<<d.text<<d.tbr;
return d.tbr;
}
bool JKQTMathText::parse(QString text){
QString ntext=QString("\\;")+text+QString("\\;");
ntext=ntext.remove("\\limits");
if (parsedNode && parseString==ntext) return true;
if (parsedNode!=nullptr) delete parsedNode;
if (unparsedNode!=nullptr) delete unparsedNode;
parseString=ntext;
currentTokenID=-1;
currentToken=MTTnone;
currentTokenName="";
parsingMathEnvironment=false;
error_list.clear();
parsedNode=parseLatexString(true);
unparsedNode=new MTplainTextNode(this, text, false);
return (parsedNode!=nullptr);
}
QSizeF JKQTMathText::getSize(QPainter& painter){
if (getTree()!=nullptr) {
double w=0, a=0, d=0, s=0;
getSizeDetail(painter, w, a, d, s);
return QSizeF(w, a+d);
}
return QSizeF(0,0);
}
double JKQTMathText::getDescent(QPainter& painter) {
double w=0, a=0, d=0, s=0;
getSizeDetail(painter, w, a, d, s);
return d;
}
double JKQTMathText::getAscent(QPainter& painter) {
double w=0, a=0, d=0, s=0;
getSizeDetail(painter, w, a, d, s);
return a;
}
void JKQTMathText::getSizeDetail(QPainter& painter, double& width, double& ascent, double& descent, double& strikeoutPos) {
width=0;
ascent=0;
descent=0;
strikeoutPos=0;
if (getTree()!=nullptr) {
MTenvironment ev;
ev.color=fontColor;
ev.fontSize=fontSize;
double overallHeight=0;
getTree()->getSize(painter, ev, width, ascent, overallHeight, strikeoutPos);
descent=overallHeight-ascent;
ascent=ascent*1.1;
descent=qMax(ascent*0.1, descent*1.1);
strikeoutPos=strikeoutPos*1.1;
}
}
void JKQTMathText::draw(QPainter& painter, double x, double y, bool drawBoxes){
if (getTree()!=nullptr) {
MTenvironment ev;
ev.color=fontColor;
ev.fontSize=fontSize;
QPen pp=painter.pen();
QPen p=pp;
p.setStyle(Qt::SolidLine);
painter.setPen(p);
getTree()->setDrawBoxes(drawBoxes);
painter.setPen(p);
getTree()->draw(painter, x, y, ev);
painter.setPen(pp);
}
}
void JKQTMathText::draw(QPainter& painter, unsigned int flags, QRectF rect, bool drawBoxes) {
if (getTree()!=nullptr) {
QPen pp=painter.pen();
QPen p=pp;
p.setStyle(Qt::SolidLine);
painter.setPen(p);
MTenvironment ev;
ev.color=fontColor;
ev.fontSize=fontSize;
getTree()->setDrawBoxes(drawBoxes);
painter.setPen(p);
double width=0;
double baselineHeight=0;
double overallHeight=0, strikeoutPos=0;
getTree()->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos);
// align left top
double x=rect.left();
double y=rect.top()+baselineHeight;
// care for horizontal align
if ((flags & Qt::AlignRight) != 0) x=x+rect.width()-width;
else if ((flags & Qt::AlignHCenter) != 0) x=x+(rect.width()-width)/2.0;
// care for vertical align
if ((flags & Qt::AlignBottom) != 0) y=y+rect.height()-overallHeight;
else if ((flags & Qt::AlignVCenter) != 0) y=y+(rect.height()-overallHeight)/2.0;
// finally draw
getTree()->draw(painter, x, y, ev);
painter.setPen(pp);
}
}
JKQTMathText::MTwhitespaceNode::MTwhitespaceNode(JKQTMathText *parent):
MTtextNode(parent, " ", false, false)
{
}
JKQTMathText::MTwhitespaceNode::~MTwhitespaceNode()
= default;
QString JKQTMathText::MTwhitespaceNode::getTypeName() const
{
return QLatin1String("MTwhitespaceNode(")+text+")";
}
bool JKQTMathText::MTwhitespaceNode::toHtml(QString &html, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/) {
html=html+"&nbsp;";
return true;
}
void JKQTMathText::MTnode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;
}
QString JKQTMathText::MTnode::getTypeName() const
{
return "MTnode";
}
QString JKQTMathText::fracModeToString(JKQTMathText::MTfracMode mode)
{
switch(mode) {
case MTFMfrac:
return "frac";
case MTFMdfrac:
return "dfrac";
case MTFMsfrac:
return "sfrac";
case MTFMstfrac:
return "stfrac";
case MTFMtfrac:
return "tfrac";
case MTFMunderbrace:
return "underbrace";
case MTFMoverbrace:
return "overbrace";
case MTFMunderset:
return "underset";
case MTFMoverset:
return "overset";
case MTFMstackrel:
return "stackrel";
}
return "unknown";
}
QString JKQTMathText::decorationToString(JKQTMathText::MTdecoration mode)
{
switch(mode) {
case MTDvec:
return "vec";
case MTDtilde:
return "tilde";
case MTDhat:
return "hat";
case MTDdot:
return "dot";
case MTDddot:
return "ddot";
case MTDbar:
return "bar";
case MTDarrow:
return "arrow";
case MTDoverline:
return "overline";
case MTDdoubleoverline:
return "double overline";
case MTDunderline:
return "underline";
case MTDdoubleunderline:
return "double underline";
}
return "unknown";
}
JKQTMathTextLabel::JKQTMathTextLabel(QWidget *parent):
QLabel(parent)
{
m_mathText=new JKQTMathText(this);
m_mathText->useXITS();
m_mathText->setFontSize(font().pointSizeF()*1.3);
lastText="";
repaintDo=true;
buffer=QPixmap();
}
JKQTMathTextLabel::~JKQTMathTextLabel()
= default;
JKQTMathText *JKQTMathTextLabel::getMathText() const
{
return m_mathText;
}
void JKQTMathTextLabel::setMath(const QString &text, bool doRepaint)
{
if (text!=lastText || doRepaint){
lastText=text;
repaintDo=true;
internalPaint();
update();
}
}
void JKQTMathTextLabel::internalPaint()
{
//return;
//qDebug()<<"internalPaint "<<lastText<<repaintDo;
//if (repaintDo) {
QSizeF size;
{
repaintDo=false;
//qDebug()<<"internalPaint(): parse "<<m_mathText->parse(lastText)<<"\n "<<m_mathText->getErrorList().join("\n")<<"\n\n";
if (!m_mathText->parse(lastText)) {
//qDebug()<<"JKQTMathTextLabel::internalPaint(): parse '"<<lastText<<"': "<<m_mathText->parse(lastText)<<"\n "<<m_mathText->getErrorList().join("\n")<<"\n\n";
}
if (buffer.width()<=0 || buffer.height()<=0) buffer=QPixmap(1000,100);
//qDebug()<<"internalPaint(): buffer "<<buffer.size();
QPainter p;
//qDebug()<<"internalPaint(): "<<p.begin(&buffer);
p.begin(&buffer);
p.setRenderHint(QPainter::Antialiasing);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.setRenderHint(QPainter::TextAntialiasing);
size=m_mathText->getSize(p);
p.end();
}
buffer=QPixmap(static_cast<int>(qMax(32.0,size.width()*1.2)), static_cast<int>(qMax(10.0,size.height()*1.1)));
buffer.fill(Qt::transparent);
{
//qDebug()<<"internalPaint(): "<<buffer.size()<<size;
QPainter p;
//qDebug()<<"internalPaint(): "<<p.begin(&buffer);
p.begin(&buffer);
p.setRenderHint(QPainter::Antialiasing);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.setRenderHint(QPainter::TextAntialiasing);
m_mathText->draw(p,alignment(), QRectF(QPointF(0,0), size));
p.end();
}
setPixmap(buffer);
//}
//qDebug()<<"internalPaint(): setPixmap";
QApplication::processEvents();
//qDebug()<<"internalPaint(): DONE";
}
void JKQTMathTextLabel::paintEvent(QPaintEvent *event)
{
//QLabel::paintEvent(event);
//return;
//qDebug()<<"paintEvent: "<<buffer.size();
//QApplication::processEvents();
QLabel::paintEvent(event);
//qDebug()<<"paintEvent DONE: "<<size();
}
JKQTMathText::tbrData::tbrData(const QFont &f, const QString &text, QPaintDevice *pd):
fm(f, pd)
{
this->text=text;
this->tbr=this->fm.tightBoundingRect(text);
this->f=f;
//this->pd=pd;
if (pd) {
ldpiX=pd->logicalDpiX();
ldpiY=pd->logicalDpiY();
pdpiX=pd->physicalDpiX();
pdpiY=pd->physicalDpiY();
} else {
ldpiX=0;
ldpiY=0;
pdpiX=0;
pdpiY=0;
}
}
bool JKQTMathText::tbrData::operator==(const JKQTMathText::tbrData &other) const
{
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f;
}
JKQTMathText::tbrDataH::tbrDataH(const QFont &f, const QString &text, QPaintDevice *pd)
{
this->text=text;
this->f=f;
if (pd) {
ldpiX=pd->logicalDpiX();
ldpiY=pd->logicalDpiY();
pdpiX=pd->physicalDpiX();
pdpiY=pd->physicalDpiY();
} else {
ldpiX=0;
ldpiY=0;
pdpiX=0;
pdpiY=0;
}
}
bool JKQTMathText::tbrDataH::operator==(const JKQTMathText::tbrDataH &other) const
{
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f;
}
JKQTMathText::MTplainTextNode::MTplainTextNode(JKQTMathText *parent, const QString& text, bool addWhitespace, bool stripInnerWhitepace):
JKQTMathText::MTtextNode(parent, text, addWhitespace, stripInnerWhitepace)
{
}
QString JKQTMathText::MTplainTextNode::getTypeName() const
{return QLatin1String("MTplainTextNode(")+text+")";
}
QString JKQTMathText::MTplainTextNode::textTransform(const QString &text, JKQTMathText::MTenvironment /*currentEv*/, bool /*forSize*/)
{
return text;
}
void initJKQTMathTextResources()
{
Q_INIT_RESOURCE(xits);
}
JKQTMathText::MTnodeSize::MTnodeSize(): width(0), baselineHeight(0),overallHeight(0),strikeoutPos() {}