/* Copyright (c) 2008-2019 Jan W. Krieger () 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 . */ #include "jkqtmathtext/jkqtmathtext.h" #include "jkqtplottertools/jkqtptools.h" #include #include #include #include #include /** * \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: if (insideMath) f.setFamily(parent->getFontMathSans()); else f.setFamily(parent->getFontSans()); break; case MTEtypewriter: f.setFamily(parent->getFontTypewriter()); break; case MTEscript: f.setFamily(parent->getFontScript()); break; case MTEroman: if (insideMath) f.setFamily(parent->getFontMathRoman()); else 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 ""; } QString JKQTMathText::MTenvironment::toHtmlAfter(JKQTMathText::MTenvironment /*defaultEv*/) const { return ""; } 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) { double w=width, b=baselineHeight, o=overallHeight, s=strikeoutPos; getSizeInternal(painter, currentEv, w, b, o, s); 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; } 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(x-3.0,y-3.0,6.0,6.0); p.setColor("lightgreen"); painter.setPen(p); painter.drawLine(x-2.0, y, x+2.0, y); painter.drawLine(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; itext=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="< this->text="<text<<"]"; } JKQTMathText::MTtextNode::~MTtextNode() = default; void JKQTMathText::MTtextNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { 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->getTBR(f, txt, painter.device()); //fm.tightBoundingRect(txt); if (txt=="|") { br=fm.boundingRect("X"); tbr=QRect(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==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 (igetFontEncoding()==MTFEunicode) { if (currentEv.insideMath) { txt=""; for (int i=0; i': 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; igetFontEncoding()==MTFEunicode) { txt=""; for (int i=0; iname=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) { 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) { 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="<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(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=="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=="text" || name=="mbox" || name=="operatorname") { 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) { JKQTMathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor(); QFontMetricsF fm(ev.getFont(parent), painter.device()); double shift=parent->getSubShiftFactor()*parent->getTBR(ev.getFont(parent), "M", painter.device()).height(); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); QFontMetricsF fmouter(currentEv.getFont(parent), painter.device()); QRectF tbr=parent->getTBR(currentEv.getFont(parent), "M", painter.device()); overallHeight=tbr.height()+shift+(overallHeight-baselineHeight); baselineHeight=tbr.height(); strikeoutPos=fmouter.strikeOutPos(); if (currentEv.italic) width=width-double(fm.width(' '))*parent->getItalicCorrectionFactor(); } double JKQTMathText::MTsubscriptNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv) { doDrawBoxes(painter, x, y, currentEv); JKQTMathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor(); QFontMetricsF fm(ev.getFont(parent), painter.device()); double shift=parent->getSubShiftFactor()*parent->getTBR(ev.getFont(parent), "M", painter.device()).height(); double xx=x; if (currentEv.italic) xx=xx-double(fm.width(' '))*parent->getItalicCorrectionFactor(); return child->draw(painter, xx, y+shift, ev);//+0.5*fm.boundingRect("A").width(); } bool JKQTMathText::MTsubscriptNode::isSubOrSuper() { return true; } QString JKQTMathText::MTsubscriptNode::getTypeName() const { return "MTsubscriptNode"; } bool JKQTMathText::MTsubscriptNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { html=html+""; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+""; 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) { 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) { 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+"√"; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+" "; 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) { 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->getTBR(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) { ev1.fontSize=ev1.fontSize*parent->getFracFactor(); ev2.fontSize=ev2.fontSize*parent->getFracFactor(); } else if (mode==MTFMtfrac) { 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="< baselineHeight="<getTBR(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) { ev1.fontSize=ev1.fontSize*parent->getFracFactor(); ev2.fontSize=ev2.fontSize*parent->getFracFactor(); } else if (mode==MTFMtfrac) { 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==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; 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 > children): JKQTMathText::MTnode(parent) { this->lines=children.size(); this->columns=0; for (int i=0; ithis->columns) this->columns=children[i].size(); } this->children=children; } JKQTMathText::MTmatrixNode::~MTmatrixNode() { for (int i=0; igetFracFactor(); QVector colwidth, rowheight; //QVector > widths, heights, baselines; double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos1=0; //widths.resize(lines); colwidth.resize(columns); for (int i=0; igetSize(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; igetFracFactor(); QVector colwidth, rowheight, rowascent; //QVector > widths, heights, baselines; double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos=0; //widths.resize(lines); colwidth.resize(columns); for (int i=0; igetSize(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; i0) yy=yy+rowascent[0]; for (int i=0; idraw(painter, xx, yy, ev1); xx=xx+colwidth[j]+xw; } if (idrawBoxes=draw; for (int i=0; isetDrawBoxes(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) { 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) { 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<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<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) { JKQTMathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor(); QFontMetricsF fm(currentEv.getFont(parent), painter.device()); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); double shift=0;//parent->getSuperShiftFactor()*fm.ascent(); overallHeight=overallHeight+shift; strikeoutPos=fm.strikeOutPos(); if (currentEv.italic) width=width+double(fm.width(' '))*parent->getItalicCorrectionFactor(); } double JKQTMathText::MTsuperscriptNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv) { 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()); double shift=0;//parent->getSuperShiftFactor()*fm.ascent(); //double shift=ev.; double xx=x; if (currentEv.italic) xx=xx+double(fm.width(' '))*parent->getItalicCorrectionFactor(); return child->draw(painter, xx, y-shift, ev);//+0.5*fm.boundingRect("A").width(); } bool JKQTMathText::MTsuperscriptNode::isSubOrSuper() { return true; } QString JKQTMathText::MTsuperscriptNode::getTypeName() const { return "MTsuperscriptNode"; } bool JKQTMathText::MTsuperscriptNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { html=html+""; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+""; 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) { 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) { //std::cout<<"drawing brace-node: '"<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()<<" ==> "<getBraceShrinkFactor()-lw; } bool JKQTMathText::MTbraceNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { QString ob=openbrace; QString cb=closebrace; if (ob=="<") ob="⟨"; else if (ob=="_") ob="⌊"; else if (ob=="~") ob="⌈"; else if (ob=="||" || ob=="#") ob="||"; if (cb=="<") cb="⟩"; else if (cb=="_") cb="⌋"; else if (cb=="~") cb="⌉"; 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" <<"max"<<"min"<<"argmax"<<"argmin"<<"sup"<<"inf" <<"liminf"<<"limsup"<<"lim"<<"max"<<"min"; } JKQTMathText::MTlistNode::~MTlistNode() { for (int i=0; igetTBR(currentEv.getFont(parent), "M", painter.device()); double xnew=0; bool wasBrace=false; for (int i=0; igetSize(painter, currentEv, w1, bh, oh, sp); //qDebug()<<"i="<getTypeName()<<" w1="<getTypeName()<<" w2="<getTypeName()<<" w1="<getTypeName()<<" w2="<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: "<getTypeName()<<" w1="<getTypeName()<<" w2="<getTypeName()<<" w3="<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) 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="<getSuperShiftFactor()*tbr.height()+(oh-bh);//((overallHeight-baselineHeight)+(oh-bh)); if (wasBrace) { shift=baselineHeight-parent->getSuperShiftFactor()*tbr.height()+(oh-bh); } //qDebug()<<"+++ super: bh="<baselineHeight) { double lheight=overallHeight-baselineHeight; baselineHeight=shift+bh; overallHeight=baselineHeight+lheight; } //qDebug()<<"### super"; //qDebug()<<"### subsupop: super overallHeight="<overallHeight-baselineHeight) { overallHeight=baselineHeight+shift+(oh-bh); } //qDebug()<<"### sub"; //qDebug()<<"### subsupop: sub overallHeight="<getTBR(currentEv.getFont(parent), "M", painter.device()); bool wasBrace=false; for (int i=0; i(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(nodes[i])) { double ccwidth=0, ccbaselineHeight=0, ccoverallHeight=0, ccstrieoutPos=0; nodes[i]->getSize(painter, currentEv, ccwidth, ccbaselineHeight, ccoverallHeight, ccstrieoutPos); if (i+1(nodes[i+1])) { // is this subscript? double shift=-parent->getSuperShiftFactor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->getSuperShiftFactor()*tbr.height(); } //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccoverallHeight-ccbaselineHeight)-4,8,8); double xnew1=nodes[i]->draw(painter, xnew, ynew+shift-(ccoverallHeight-ccbaselineHeight), currentEv); i++; //painter.setPen(QPen("magenta")); //painter.drawEllipse(xnew-4,ynew-4,8,8); double xnew2=nodes[i]->draw(painter, xnew, ynew, currentEv); //i++; xnew=qMax(xnew1, xnew2); doDraw=false; } } } else if (dynamic_cast(nodes[i])) { if (i+1(nodes[i+1])) { // is this subscript? //painter.setPen(QPen("magenta")); //painter.drawEllipse(xnew-4,ynew-4,8,8); double xnew1=nodes[i]->draw(painter, xnew, ynew, currentEv); i++; double ccwidth=0, ccbaselineHeight=0, ccoverallHeight=0, ccstrieoutPos=0; nodes[i]->getSize(painter, currentEv, ccwidth, ccbaselineHeight, ccoverallHeight, ccstrieoutPos); //QRectF tbr=fm.tightBoundingRect("M"); double shift=-parent->getSuperShiftFactor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->getSuperShiftFactor()*tbr.height(); } //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccoverallHeight-ccbaselineHeight)-4,8,8); double xnew2=nodes[i]->draw(painter, xnew, ynew+shift-(ccoverallHeight-ccbaselineHeight), currentEv); //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[i+1]); MTsuperscriptNode* supn=nullptr; if (i+2(nodes[i+2]); //std::cout<<"symbol ='"<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(" "); } } } nodes[i]->getSize(painter, currentEv, cwidth, cbaselineHeight, coverallHeight, cstrieoutPos); } if (i(nodes[i])) { // is this superscript? double ccwidth=0, ccbaselineHeight=0, ccoverallHeight=0, ccstrieoutPos=0; nodes[i]->getSize(painter, currentEv, ccwidth, ccbaselineHeight, ccoverallHeight, ccstrieoutPos); //QRectF tbr=fm.tightBoundingRect("M"); double shift=-parent->getSuperShiftFactor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->getSuperShiftFactor()*tbr.height(); } //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccoverallHeight-ccbaselineHeight)-4,8,8); xnew=nodes[i]->draw(painter, xnew, ynew+shift-(ccoverallHeight-ccbaselineHeight), currentEv); } else { xnew=nodes[i]->draw(painter, xnew, ynew, currentEv); } } wasBrace=dynamic_cast(nodes[i]); } return xnew; } bool JKQTMathText::MTlistNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { bool ok=true; for (int i=0; itoHtml(h, currentEv, defaultEv); html=html+h; } return ok; } void JKQTMathText::MTlistNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; for (int i=0; isetDrawBoxes(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 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("min", "min"); 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 simpleTranslations_heightIsAscent; if (simpleTranslations_heightIsAscent.isEmpty()) { simpleTranslations_heightIsAscent.insert("erf", "erf"); 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 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 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 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 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("pm", QChar(0x00B1)); unicodeSymbol.insert("mp", QChar(0x2213)); unicodeSymbol.insert("leq", QChar(0x2264)); unicodeSymbol.insert("geq", QChar(0x2265)); unicodeSymbol.insert("ll", QChar(0x226A)); unicodeSymbol.insert("gg", QChar(0x226B)); unicodeSymbol.insert("hbar", QChar(0x210F)); unicodeSymbol.insert("euro", QChar(0x20AC)); unicodeSymbol.insert("Angstrom", QChar(0x212B)); 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("circ", QChar(0x2218)); 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("cdots", QString(QChar(0x00B7)) + QString(QChar(0x00B7)) + QString(QChar(0x00B7))); unicodeSymbol.insert("vdots", QChar(0x22EE)); unicodeSymbol.insert("iddots", QChar(0x22F0)); unicodeSymbol.insert("ddots", QChar(0x22F1)); unicodeSymbol.insert("dots", "..."); unicodeSymbol.insert("ldots", "..."); 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("cent", QChar(0x00A2)); unicodeSymbol.insert("pound", QChar(0x00A3)); unicodeSymbol.insert("yen", QChar(0x00A5)); 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("times", QChar(0x2A2F)); unicodeSymbol.insert("propto", QChar(0x221D)); unicodeSymbol.insert("partial", QChar(0x2202)); unicodeSymbol.insert("bullet", QChar(0x2219)); unicodeSymbol.insert("neq", QChar(0x2260)); unicodeSymbol.insert("ne", QChar(0x2260)); unicodeSymbol.insert("equiv", QChar(0x2261)); unicodeSymbol.insert("approx", QChar(0x2245)); 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("copyright", QChar(0x00A9)); unicodeSymbol.insert("registered", QChar(0x00AE)); unicodeSymbol.insert("trademark", QChar(0x2122)); unicodeSymbol.insert("cdot", QChar(0x00B7)); unicodeSymbol.insert("neg", QChar(0x00AC)); unicodeSymbol.insert("wedge", QChar(0x2227)); unicodeSymbol.insert("vee", QChar(0x2228)); unicodeSymbol.insert("diamond", QChar(0xE0)); unicodeSymbol.insert("langle", QChar(0x2329)); unicodeSymbol.insert("rangle", QChar(0x232A)); unicodeSymbol.insert("infty", QChar(0x221E)); unicodeSymbol.insert("forall", QChar(0x2200)); unicodeSymbol.insert("exists", QChar(0x2203)); unicodeSymbol.insert("cong", QChar(0x2245)); unicodeSymbol.insert("bot", QChar(0x22A5)); } static QHash 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 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 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::iterator itsimple = simpleTranslations.find(n); if (itsimple!= simpleTranslations.end()) { symbol=itsimple.value(); } else { QHash::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::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::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::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::iterator itsymbol = unicodeSymbol.find(n); if (itsymbol!=unicodeSymbol.end()) { symbol = itsymbol.value(); } 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() == MTFElatex) { // use UNICODE encoding for special characters // first we start with greek characters font = MTSFdefault; //MTSFgreek; //std::cout<<"encoding unicode\n"; QHash::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::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::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 extraSymbolName = { "infty", "|", " ", "quad", ";", ":", ",", "!", "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 '"<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) { 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->getTBR(f, symb, painter.device()).width(),parent->getTBR(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") width=parent->getTBR(f, "M", painter.device()).width(); else if (symbolName==" ") width=parent->getTBR(f, "x", painter.device()).width(); else if (symbolName==";") width=parent->getTBR(f, "x", painter.device()).width()*0.75; else if (symbolName==":") width=parent->getTBR(f, "x", painter.device()).width()*0.5; else if (symbolName==",") width=parent->getTBR(f, "x", painter.device()).width()*0.25; else if (symbolName=="!") width=-parent->getTBR(f, "x", painter.device()).width()*0.25; else if (symbolName=="longleftarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="longrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longleftarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="longleftrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longleftrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } } QRectF tbr=parent->getTBR(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()<getMathoperatorWidthFactor(); } double JKQTMathText::MTsymbolNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv) { 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 '"<getTBR(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 } else if (symbolName=="quad") { // 75% space } 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->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, false); painter.drawPath(path); } else if (symbolName=="longrightarrow"){ double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, false, true); painter.drawPath(path); } else if (symbolName=="Longleftarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, false); painter.drawPath(path); } else if (symbolName=="Longrightarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, false, true); painter.drawPath(path); } else if (symbolName=="longleftrightarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, true); painter.drawPath(path); } else if (symbolName=="Longleftrightarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, true); painter.drawPath(path); } else { // draw a box to indicate an unavailable symbol QRectF tbr=parent->getTBR(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 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("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("max", "max"); entitylut.insert("min", "min"); 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("Pr", "Pr"); entitylut.insert("coth", "coth"); entitylut.insert("alpha", "α"); entitylut.insert("beta", "β"); entitylut.insert("gamma", "γ"); entitylut.insert("delta", "δ"); entitylut.insert("epsilon", "ε"); entitylut.insert("varepsilon", "ε"); entitylut.insert("zeta", "ζ"); entitylut.insert("eta", "η"); entitylut.insert("theta", "θ"); entitylut.insert("vartheta", "ϑ"); entitylut.insert("iota", "ι"); entitylut.insert("kappa", "κ"); entitylut.insert("lambda", "λ"); entitylut.insert("mu", "μ"); entitylut.insert("nu", "ν"); entitylut.insert("xi", "ξ"); entitylut.insert("pi", "π"); entitylut.insert("varpi", "ϖ"); entitylut.insert("rho", "ρ"); entitylut.insert("sigma", "σ"); entitylut.insert("varsigma", "ς"); entitylut.insert("tau", "τ"); entitylut.insert("upsilon", "υ"); entitylut.insert("phi", "φ"); entitylut.insert("varphi", "φ"); entitylut.insert("chi", "χ"); entitylut.insert("psi", "ψ"); entitylut.insert("omega", "ω"); entitylut.insert("Gamma", "Γ"); entitylut.insert("Delta", "Δ"); entitylut.insert("Theta", "Θ"); entitylut.insert("Lambda", "Λ"); entitylut.insert("Omega", "Ω"); entitylut.insert("Xi", "Ξ"); entitylut.insert("Pi", "Π"); entitylut.insert("Sigma", "Σ"); entitylut.insert("Upsilon", "Υ"); entitylut.insert("Phi", "Φ"); entitylut.insert("Psi", "Ψ"); entitylut.insert("leftrightarrow", "↔"); entitylut.insert("leftarrow", "←"); entitylut.insert("rightarrow", "→"); entitylut.insert("to", "→"); entitylut.insert("uparrow", "↑"); entitylut.insert("downarrow", "↓"); entitylut.insert("Leftrightarrow", "⇔"); entitylut.insert("iff", "⇔"); entitylut.insert("Leftarrow", "⇐"); entitylut.insert("Rightarrow", "⇒"); entitylut.insert("Uparrow", "⇑"); entitylut.insert("Downarrow", "⇓"); entitylut.insert("pm", "±"); entitylut.insert("leq", "≤"); entitylut.insert("geq", "≥"); entitylut.insert("times", "×"); entitylut.insert("propto", "∝"); entitylut.insert("partial", "∂"); entitylut.insert("bullet", "•"); entitylut.insert("neq", "≠"); entitylut.insert("ne", "≠"); entitylut.insert("equiv", "≡"); entitylut.insert("approx", "≈"); entitylut.insert("ellipsis", "..."); entitylut.insert("Im", "ℑ"); entitylut.insert("Re", "ℜ"); entitylut.insert("otimes", "⊗"); entitylut.insert("oplus", "⊕"); entitylut.insert("oslash", "/"); entitylut.insert("cap", "∩"); entitylut.insert("cup", "∪"); entitylut.insert("land", "∩"); entitylut.insert("lor", "∪"); entitylut.insert("supset", "⊃"); entitylut.insert("supseteq", "⊇"); entitylut.insert("supsetnot", "⊅"); entitylut.insert("subset", "⊂"); entitylut.insert("subseteq", "⊆"); entitylut.insert("in", "∈"); entitylut.insert("notin", "∉"); entitylut.insert("angle", "∠"); entitylut.insert("nabla", "∇"); entitylut.insert("copyright", "©"); entitylut.insert("registered", "®"); entitylut.insert("trademark", "™"); entitylut.insert("cdot", "⋅"); entitylut.insert("neg", "¬"); entitylut.insert("wedge", "∧"); entitylut.insert("vee", "∨"); entitylut.insert("diamond", "◊"); entitylut.insert("langle", "⟨"); entitylut.insert("rangle", "⟩"); entitylut.insert("int", "∫"); entitylut.insert("forall", "∀"); entitylut.insert("exists", "∃"); entitylut.insert("cong", "∼"); entitylut.insert("bot", "⊥"); entitylut.insert("ll", "<<"); entitylut.insert("gg", ">>"); entitylut.insert("bbC", "C"); entitylut.insert("bbH", "H"); entitylut.insert("bbN", "N"); entitylut.insert("bbP", "P"); entitylut.insert("bbQ", "Q"); entitylut.insert("bbR", "R"); entitylut.insert("bbZ", "Z"); entitylut.insert("Alef", "ℵ"); entitylut.insert("alef", "ℵ"); entitylut.insert("tilde", "~"); entitylut.insert("iint", "∫∫"); entitylut.insert("iiint", "∫∫∫"); entitylut.insert("emptyset", "∅"); entitylut.insert("varnothing", "∅"); entitylut.insert("lceil", "⌈"); entitylut.insert("rceil", "⌉"); entitylut.insert("lfloor", "⌊"); entitylut.insert("rfloor", "⌋"); entitylut.insert("subsetnot", "⊄"); entitylut.insert("DC", "="); entitylut.insert("cdots", "⋅⋅⋅"); entitylut.insert("dots", "..."); entitylut.insert("cent", "¢"); entitylut.insert("_", "_"); entitylut.insert("}", "}"); entitylut.insert("{", "{"); entitylut.insert("hbar", "ℏ"); entitylut.insert("euro", "€"); entitylut.insert("pound", "£"); entitylut.insert("yen", "¥"); entitylut.insert("div", "÷"); 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", "<"); entitylut.insert("frq", ">"); entitylut.insert("flqq", ""); entitylut.insert("frqq", ""); } QMap::iterator itS = entitylut.find(symbolName); if (itS!=entitylut.end()) { s=itS.value(); } else if (symbolName == "sum") { ev.fontSize*=1.7; s="∑"; } else if (symbolName == "prod") { ev.fontSize*=1.7; s="∏"; } else if (symbolName == "bigcap") { ev.fontSize*=1.7; s="∩"; } else if (symbolName == "bigcup") { ev.fontSize*=1.7; s="∪"; } else if (symbolName == "bigvee") { ev.fontSize*=1.7; s="∨"; } else if (symbolName == "bighat") { ev.fontSize*=1.7; s="∧"; } else ok=false; if (ok) html=html+ev.toHtmlStart(defaultEv)+s+ev.toHtmlAfter(defaultEv); return ok; } // -------------------------------------------------------------------------------------------------- // -- 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"<toHtml(s, ev, defaultev); } if (ok) *ok=okk; return s; } 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::setFontRomanOrSpecial(const QString &roman, const QString &math) { if (math.toUpper()=="XITS") { useXITS(); } else if (math.toUpper()=="STIX") { useSTIX(); } else if (math.toUpper()=="ASANA") { useASANA(); } else { setFontMathRoman(math); } setFontRoman(roman); } void JKQTMathText::useAnyUnicode(QString timesFont, const QString& sansFont) { if (!timesFont.isEmpty()) { fontMathRoman=timesFont; fontRoman=timesFont; } if (!sansFont.isEmpty()) { fontMathSans=sansFont; fontSans=sansFont; } useSTIXfonts=false; useXITSfonts=false; useASANAfonts=false; fontGreek=fontMathRoman; fontSymbol=fontMathRoman; fontBraces=fontMathRoman; fontIntegrals=fontMathRoman; fontEncoding=MTFEunicode; 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 '"<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 '"<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!='}' && (currentTokenIDaddNode(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=="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 > items; //int lines=0; //int cols=0; bool first=true; QVector 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 "<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 '"<0) { if (QString(currentTokenName[0])==quitOnClosingBrace || quitOnClosingBrace=="any" || QString(currentTokenName[0])==".") { //std::cout<<"found \\right '"<" && (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::tbrs=QList(); QHash JKQTMathText::tbrh=QHash(); QRectF JKQTMathText::getTBR(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; ilogicalDpiX() && tbrs[i].ldpiY==pd->logicalDpiY() && tbrs[i].pdpiX==pd->physicalDpiX() && tbrs[i].pdpiY==pd->physicalDpiY())) { //qDebug()<<" ### "<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; getTree()->setDrawBoxes(drawBoxes); getTree()->draw(painter, x, y, ev); } } void JKQTMathText::draw(QPainter& painter, int flags, QRectF rect, bool drawBoxes) { if (getTree()!=nullptr) { MTenvironment ev; ev.color=fontColor; ev.fontSize=fontSize; getTree()->setDrawBoxes(drawBoxes); 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); } } 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+" "; 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 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 "<parse(lastText)<<"\n "<getErrorList().join("\n")<<"\n\n"; if (!m_mathText->parse(lastText)) { qDebug()<<"JKQTMathTextLabel::internalPaint(): parse '"<parse(lastText)<<"\n "<getErrorList().join("\n")<<"\n\n"; } if (buffer.width()<=0 || buffer.height()<=0) buffer=QPixmap(1000,100); //qDebug()<<"internalPaint(): buffer "<getSize(p); p.end(); } buffer=QPixmap(qMax(32.0,size.width()*1.2), qMax(10.0,size.height()*1.1)); buffer.fill(Qt::transparent); { //qDebug()<<"internalPaint(): "<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: "<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); }