/* Copyright (c) 2008-2018 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 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 #include #include #include #include //#define QColor2String(color) QString(jkqtp_rgbtostring((color).red(), (color).green(), (color).blue(), (color).alpha()).c_str()) 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->get_fontMathSans()); else f.setFamily(parent->get_fontSans()); break; case MTEtypewriter: f.setFamily(parent->get_fontTypewriter()); break; case MTEscript: f.setFamily(parent->get_fontScript()); break; case MTEroman: if (insideMath) f.setFamily(parent->get_fontMathRoman()); else f.setFamily(parent->get_fontRoman()); break; case MTEcaligraphic: f.setFamily(parent->get_fontCaligraphic()); break; case MTEblackboard: f.setFamily(parent->get_fontBlackboard()); 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; } 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(); 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); painter.restore(); } } JKQTmathText::MTtextNode::MTtextNode(JKQTmathText* parent, 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() { } 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->get_fontBraces()); } 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->get_fontBraces()); } 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 (iget_fontEncoding()==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->get_fontEncoding()==MTFEunicode) { txt=""; for (int i=0; iget_fontEncoding()==MTFEunicode) { txt=""; for (int i=0; iname=name; this->child=child; this->parameters=parameters; } 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; 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; } 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; 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; } 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; 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; } return child->toHtml(html, ev, defaultEv); } void JKQTmathText::MTinstruction1Node::set_drawBoxes(bool draw) { drawBoxes=draw; child->set_drawBoxes(draw); } 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->get_subsuper_size_factor(); QFontMetricsF fm(ev.getFont(parent), painter.device()); double shift=parent->get_sub_shift_factor()*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->get_italic_correction_factor(); } 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->get_subsuper_size_factor(); QFontMetricsF fm(ev.getFont(parent), painter.device()); double shift=parent->get_sub_shift_factor()*parent->getTBR(ev.getFont(parent), "M", painter.device()).height(); double xx=x; if (currentEv.italic) xx=xx-double(fm.width(' '))*parent->get_italic_correction_factor(); 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::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(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(); 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(); 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); } painter.restore(); 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::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(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->get_underbrace_factor(); } else if (mode==MTFMunderset || mode==MTFMoverset) { ev2.fontSize=ev2.fontSize*parent->get_underset_factor(); } else if (mode==MTFMfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor(); ev2.fontSize=ev2.fontSize*parent->get_frac_factor(); } else if (mode==MTFMtfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor()*0.7; ev2.fontSize=ev2.fontSize*parent->get_frac_factor()*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->get_underbrace_factor(); } else if (mode==MTFMunderset || mode==MTFMoverset) { ev2.fontSize=ev2.fontSize*parent->get_underset_factor(); } else if (mode==MTFMfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor(); ev2.fontSize=ev2.fontSize*parent->get_frac_factor(); } else if (mode==MTFMtfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor()*0.7; ev2.fontSize=ev2.fontSize*parent->get_frac_factor()*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(); 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->get_frac_shift_factor())-descent1, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->get_frac_shift_factor())+ascent2, ev2); } else if (mode==MTFMstackrel) { child1->draw(painter, x+xw/2.0+(width-width1)/2.0, yline-xh*(parent->get_frac_shift_factor())-descent1, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->get_frac_shift_factor())+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(); painter.translate(x+xw/2.0+(width1)/2.0, ybrace); painter.rotate(180); QPainterPath path=makeHBracePath(0,0, width, bw); painter.drawPath(path); painter.restore(); 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); } painter.restore(); 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::set_drawBoxes(bool draw) { this->drawBoxes=draw; child1->set_drawBoxes(draw); child2->set_drawBoxes(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; iget_frac_factor(); 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; iget_frac_factor(); 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; iset_drawBoxes(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->get_decoration_height_factor()*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->get_decoration_height_factor(); 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::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(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->get_subsuper_size_factor(); QFontMetricsF fm(currentEv.getFont(parent), painter.device()); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); double shift=0;//parent->get_super_shift_factor()*fm.ascent(); overallHeight=overallHeight+shift; strikeoutPos=fm.strikeOutPos(); if (currentEv.italic) width=width+double(fm.width(' '))*parent->get_italic_correction_factor(); } 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->get_subsuper_size_factor(); double cwidth, cbaselineHeight, coverallheight, cStrikeoutPos; child->getSize(painter, ev, cwidth, cbaselineHeight, coverallheight, cStrikeoutPos); QFontMetricsF fm(currentEv.getFont(parent), painter.device()); double shift=0;//parent->get_super_shift_factor()*fm.ascent(); //double shift=ev.; double xx=x; if (currentEv.italic) xx=xx+double(fm.width(' '))*parent->get_italic_correction_factor(); 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::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(draw); } JKQTmathText::MTbraceNode::MTbraceNode(JKQTmathText* parent, QString openbrace, 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->get_brace_shrink_factor(); baselineHeight=/*qMin(baselineHeight, braceheight)*/ baselineHeight*parent->get_brace_factor(); overallHeight=qMax(overallHeight, braceheight)*parent->get_brace_factor(); //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(); painter.translate(xnew+bracewidth*(1.0-brace_fraction), y-cbaselineHeight+coverallHeight/2.0); painter.rotate(90); painter.drawPath(path); painter.restore(); } 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->get_brace_shrink_factor()-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(); painter.translate(xnew+bracewidth*brace_fraction, y-cbaselineHeight+coverallHeight/2.0); painter.rotate(270); painter.drawPath(path); painter.restore(); } 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()<<" ==> "<get_brace_shrink_factor()-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::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(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->get_fontSize()) { const QFontMetricsF fme(evf, painter.device()); if (fme.ascent()>overallHeight) break; ev.fontSize+=0.5; evf.setPointSizeF(ev.fontSize); } ev.fontSize=ev.fontSize*parent->get_brace_factor(); evf.setPointSizeF(ev.fontSize); QFontMetricsF fm(evf, painter.device()); QString bc="_X"; bracewidth=fm.width("I")*parent->get_brace_shrink_factor(); braceheight=parent->getTBR(evf, bc, painter.device()).height();*/ double lw=qMax(0.25,ceil(ev.fontSize/12.0)); braceheight=overallHeight*parent->get_brace_factor(); 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="<getSize(painter, currentEv, w1, bh, oh, sp); //qDebug()<<"sub_super: sub: "<getTypeName()<<" w1="<getTypeName()<<" w2="<get_operatorsubsuper_size_factor(); 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->get_operatorsubsuper_size_factor(); 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->get_child()->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="<get_super_shift_factor()*tbr.height()+(oh-bh);//((overallHeight-baselineHeight)+(oh-bh)); if (wasBrace) { shift=baselineHeight-parent->get_super_shift_factor()*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->get_super_shift_factor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->get_super_shift_factor()*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->get_super_shift_factor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->get_super_shift_factor()*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->get_symbolName(); 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 ='"<get_operatorsubsuper_size_factor(); 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->get_child()->getSize(painter, ev, w2, bh2, oh2, sp); supn->get_child()->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->get_child()->draw(painter, xnew+(w-w2)/2.0, ynew+bh2+d1, ev); i++; //double xnew3= double xn3=supn->get_child()->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->get_operatorsubsuper_size_factor(); 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->get_child()->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->get_child()->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->get_operatorsubsuper_size_factor(); 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->get_child()->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->get_child()->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->get_super_shift_factor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->get_super_shift_factor()*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::set_drawBoxes(bool draw) { this->drawBoxes=draw; for (int i=0; iset_drawBoxes(draw); } } JKQTmathText::MTsymbolNode::MTsymbolNode(JKQTmathText* parent, 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; //qDebug()<<"MTsymbolNode("<get_fontEncoding()==MTFEwinSymbol) { // first we start with greek characters font=MTSFgreek; italic=-1; if (n=="alpha") symbol="a"; else if (n=="beta") symbol="b"; else if (n=="gamma") symbol="g"; else if (n=="delta") symbol="d"; else if (n=="epsilon") symbol="e"; else if (n=="varepsilon") symbol="e"; else if (n=="zeta") symbol="z"; else if (n=="eta") symbol="h"; else if (n=="theta") symbol="q"; else if (n=="vartheta") symbol="J"; else if (n=="iota") symbol="i"; else if (n=="kappa") symbol="k"; else if (n=="lambda") symbol="l"; else if (n=="mu") symbol="m"; else if (n=="nu") symbol="n"; else if (n=="xi") symbol="x"; else if (n=="pi") symbol="p"; else if (n=="varpi") symbol="v"; else if (n=="rho") symbol="r"; else if (n=="sigma") symbol="s"; else if (n=="varsigma") symbol="V"; else if (n=="tau") symbol="t"; else if (n=="upsilon") symbol="u"; else if (n=="phi") symbol="f"; else if (n=="varphi") symbol="j"; else if (n=="chi") symbol="c"; else if (n=="psi") symbol="y"; else if (n=="omega") symbol="w"; else if (n=="Gamma") symbol="G"; else if (n=="Delta") symbol="D"; else if (n=="Theta") symbol="Q"; else if (n=="Lambda") symbol="L"; else if (n=="Omega") symbol="W"; else if (n=="Xi") symbol="X"; else if (n=="Pi") symbol="P"; else if (n=="Sigma") symbol="S"; 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 if (n=="Upsilon") symbol=""; else if (n=="Phi") symbol="F"; else if (n=="Psi") symbol="Y"; else { // now we set the symbols from the Symbol font font=MTSFsymbol; if (n=="leftrightarrow") symbol=QChar(0xAB); else if (n=="leftarrow") symbol=QChar(0xAC); else if (n=="rightarrow"||n=="to") symbol=QChar(0xAE); else if (n=="uparrow") symbol=QChar(0xAD); else if (n=="downarrow") symbol=QChar(0xAF); else if (n=="Leftrightarrow" || n=="iff") symbol=QChar(0xDB); else if (n=="Leftarrow") symbol=QChar(0xDC); else if (n=="Rightarrow") symbol=QChar(0xDE); else if (n=="Uparrow") symbol=QChar(0xDD); else if (n=="Downarrow") symbol=QChar(0xFF); else if (n=="pm") symbol=QChar(0xB1); else if (n=="leq") symbol=QChar(0xA3); else if (n=="geq") symbol=QChar(0xB3); else if (n=="times") symbol=QChar(0xB4); else if (n=="propto") symbol=QChar(0xB5); else if (n=="partial") symbol=QChar(0xB6); else if (n=="bullet") symbol=QChar(0xB7); else if (n=="neq"||n=="ne") symbol=QChar(0xB9); else if (n=="equiv") symbol=QChar(0xBA); else if (n=="approx") symbol=QChar(0xBB); else if (n=="ellipsis") symbol=QChar(0xBC); else if (n=="Im") symbol=QChar(0xC1); else if (n=="Re") symbol=QChar(0xC2); else if (n=="otimes") symbol=QChar(0xC4); else if (n=="oplus") symbol=QChar(0xC5); else if (n=="oslash") symbol=QChar(0xC6); else if (n=="cap"||n=="land") symbol=QChar(0xC7); else if (n=="cup"||n=="lor") symbol=QChar(0xC8); else if (n=="supset") symbol=QChar(0xC9); else if (n=="supseteq") symbol=QChar(0xCA); else if (n=="supsetnot") symbol=QChar(0xCB); else if (n=="subset") symbol=QChar(0xCC); else if (n=="subseteq") symbol=QChar(0xCD); else if (n=="in") symbol=QChar(0xCE); else if (n=="notin") symbol=QChar(0xCF); else if (n=="angle") symbol=QChar(0xD0); else if (n=="nabla") symbol=QChar(0xD1); else if (n=="copyright") symbol=QChar(0xD3); else if (n=="registered") symbol=QChar(0xD2); else if (n=="trademark") symbol=QChar(0xD4); else if (n=="cdot") symbol=QChar(0xD7); else if (n=="neg") symbol=QChar(0xD8); else if (n=="wedge") symbol=QChar(0xD9); else if (n=="vee") symbol=QChar(0xDA); else if (n=="diamond") symbol=QChar(0xE0); else if (n=="langle") symbol=QChar(0xE1); else if (n=="rangle") symbol=QChar(0xF1); else if (n=="int") { symbol=QChar(0xF2); fontFactor=mathFontFactor; yfactor=+0.1; } else if (n=="forall") { symbol=QChar(0x22); } else if (n=="exists") { symbol=QChar(0x24); } else if (n=="cong") { symbol=QChar(0x40); } else if (n=="bot") { symbol=QChar(0x5E); } else if (n=="ll") { symbol="<<"; } else if (n=="gg") { symbol=">>"; } 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=="Alef" || n=="alef") symbol=QChar(0xC0); else if (n=="tilde") symbol="~"; 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=="emptyset") symbol=QChar(0xC6); else if (n=="varnothing") symbol=QChar(0xC6); else if (n=="lceil") symbol=QChar(0xE9); else if (n=="rceil") symbol=QChar(0xF9); else if (n=="lfloor") symbol=QChar(0xEB); else if (n=="rfloor") symbol=QChar(0xFB); else if (n=="subsetnot") symbol=QChar(0xCB); else if (n=="DC") symbol="="; else if (n=="bot") { symbol=QChar(0x5E); } else if (n=="cdots") { symbol=QString(3,QChar(0xD7)); } else if (n=="dots" || n=="ldots") { symbol=QChar(0xDC); } else if (n=="cent") { symbol="c"; } 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->get_fontEncoding()==MTFEunicode) { // use UNICODE encoding for special characters // first we start with greek characters font=MTSFdefault; //MTSFgreek; //std::cout<<"encoding unicode\n"; if (n=="alpha") symbol=QChar(0x3B1); else if (n=="beta") symbol=QChar(0x3B2); else if (n=="gamma") symbol=QChar(0x3B3); else if (n=="delta") symbol=QChar(0x3B4); else if (n=="epsilon") symbol=QChar(0x3B5); else if (n=="varepsilon") symbol=QChar(0x3B5); else if (n=="zeta") symbol=QChar(0x3B6); else if (n=="eta") symbol=QChar(0x3B7); else if (n=="theta") symbol=QChar(0x3B8); else if (n=="vartheta") symbol=QChar(0x3D1); else if (n=="iota") symbol=QChar(0x3B9); else if (n=="kappa") symbol=QChar(0x3BA); else if (n=="lambda") symbol=QChar(0x3BB); else if (n=="mu") symbol=QChar(0x3BC); else if (n=="nu") symbol=QChar(0x3BD); else if (n=="xi") symbol=QChar(0x3BE); else if (n=="pi") symbol=QChar(0x3C0); else if (n=="varpi") symbol=QChar(0x3D6); else if (n=="rho") symbol=QChar(0x3C1); else if (n=="varrho") symbol=QChar(0x3F1); else if (n=="sigma") symbol=QChar(0x3C3); else if (n=="varsigma") symbol=QChar(0x3C2); else if (n=="tau") symbol=QChar(0x3C4); else if (n=="upsilon") symbol=QChar(0x3C5); else if (n=="phi") symbol=QChar(0x3D5); else if (n=="varphi") symbol=QChar(0x3C6); else if (n=="chi") symbol=QChar(0x3C7); else if (n=="psi") symbol=QChar(0x3C8); else if (n=="omega") symbol=QChar(0x3C9); else if (n=="Omega") symbol=QChar(0x3A9); else if (n=="Gamma") symbol=QChar(0x393); else if (n=="Delta") symbol=QChar(0x394); else if (n=="Theta") symbol=QChar(0x398); else if (n=="Lambda") symbol=QChar(0x39B); else if (n=="Xi") symbol=QChar(0x39E); else if (n=="Pi") symbol=QChar(0x3A0); else if (n=="Sigma") symbol=QChar(0x3A3); else if (n=="Upsilon") symbol=QChar(0x3A5); else if (n=="Phi") symbol=QChar(0x3A6); else if (n=="Psi") symbol=QChar(0x3A8); else { // now we set the symbols from the Symbol font font=MTSFsymbol; if (n=="leftrightarrow") symbol=QChar(0x2194); else if (n=="leftarrow") symbol=QChar(0x2190); else if (n=="rightarrow"||n=="to") symbol=QChar(0x2192); else if (n=="uparrow") symbol=QChar(0x2191); else if (n=="downarrow") symbol=QChar(0x2193); else if (n=="updownarrow") symbol=QChar(0x2195); else if (n=="Leftrightarrow" || n=="iff") symbol=QChar(0x21D4); else if (n=="Leftarrow") symbol=QChar(0x21D0); else if (n=="Rightarrow") symbol=QChar(0x21D2); else if (n=="Uparrow") symbol=QChar(0x21D1); else if (n=="Downarrow") symbol=QChar(0x21D3); else if (n=="Updownarrow") symbol=QChar(0x21D5); else if (n=="sum") { symbol=QChar(0x2211); heightIsAscent=true; exactAscent=true; } else if (n=="prod") { symbol=QChar(0x220F); heightIsAscent=true; exactAscent=true; } else if (n=="pm") symbol=QChar(0x00B1); else if (n=="mp") symbol=QChar(0x2213); else if (n=="leq") symbol=QChar(0x2264); else if (n=="geq") symbol=QChar(0x2265); else if (n=="ll") symbol=QChar(0x226A); else if (n=="gg") symbol=QChar(0x226B); else if (n=="hbar") symbol=QChar(0x210F); else if (n=="euro") symbol=QChar(0x20AC); 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=="Angstrom") symbol=QChar(0x212B); else if (n=="Alef" || n=="alef") symbol=QChar(0x2135); else if (n=="Bet" || n=="bet") symbol=QChar(0x2136); else if (n=="Gimel" || n=="gimel") symbol=QChar(0x2137); else if (n=="Dalet" || n=="dalet") symbol=QChar(0x2138); else if (n=="nexists") { symbol=QChar(0x2204); } else if (n=="ni") symbol=QChar(0x220B); else if (n=="notni") symbol=QChar(0x220C); else if (n=="circ") symbol=QChar(0x2218); else if (n=="tilde") symbol=QChar(0x223C); 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=="emptyset") symbol=QChar(0x2300); else if (n=="varnothing") symbol=QChar(0x2300); else if (n=="odot") symbol=QChar(0x2299); else if (n=="ominus") symbol=QChar(0x2296); else if (n=="lceil") symbol=QChar(0x2308); else if (n=="rceil") symbol=QChar(0x2309); else if (n=="lfloor") symbol=QChar(0x230A); else if (n=="rfloor") symbol=QChar(0x230B); else if (n=="subsetnot") symbol=QChar(0x2284); else if (n=="DC") symbol=QChar(0x2393); else if (n=="bot") { symbol=QChar(0x22A4); } else if (n=="cdots") { symbol=QString(QChar(0x00B7))+QString(QChar(0x00B7))+QString(QChar(0x00B7)); }//QChar(0x22EF); } else if (n=="vdots") { symbol=QChar(0x22EE); } else if (n=="iddots") { symbol=QChar(0x22F0); } else if (n=="ddots") { symbol=QChar(0x22F1); } else if (n=="dots" || n=="ldots") { symbol="..."; }//QChar(0x2026); } else if (n=="perthousand") { symbol=QChar(0x2030); } else if (n=="leftharpoonup") { symbol=QChar(0x21BC); } else if (n=="rightharpoonup") { symbol=QChar(0x21C0); } else if (n=="upharpoonleft") { symbol=QChar(0x21BF); } else if (n=="downharpoonleft") { symbol=QChar(0x21C3); } else if (n=="leftrightharpoon") { symbol=QChar(0x21CB); } else if (n=="rightleftharpoon") { symbol=QChar(0x21CC); } else if (n=="coprod") { symbol=QChar(0x2210); heightIsAscent=true; exactAscent=true; } else if (n=="leftharpoondown") { symbol=QChar(0x21BD); } else if (n=="rightharpoondown") { symbol=QChar(0x21C1); } else if (n=="upharpoonright") { symbol=QChar(0x21BE); } else if (n=="downharpoonright") { symbol=QChar(0x21C2); } else if (n=="nwarrow") { symbol=QChar(0x2196); } else if (n=="nearrow") { symbol=QChar(0x2197); } else if (n=="searrow") { symbol=QChar(0x2198); } else if (n=="swarrow") { symbol=QChar(0x2199); } else if (n=="mapsto") { symbol=QChar(0x21A6); } else if (n=="cent") { symbol=QChar(0x00A2); } else if (n=="pound") { symbol=QChar(0x00A3); } else if (n=="yen") { symbol=QChar(0x00A5); } else if (n=="div") { symbol=QChar(0x00F7); } else if (n=="multimap") { symbol=QChar(0x22B8); } else if (n=="maporiginal") { symbol=QChar(0x22B6); } else if (n=="mapimage") { symbol=QChar(0x22B7); } 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=="benzene") symbol=QChar(0x232C); else if (n=="times") symbol=QChar(0x2A2F); else if (n=="propto") symbol=QChar(0x221D); else if (n=="partial") symbol=QChar(0x2202); else if (n=="bullet") symbol=QChar(0x2219); else if (n=="neq"||n=="ne") symbol=QChar(0x2260); else if (n=="equiv") symbol=QChar(0x2261); else if (n=="approx") symbol=QChar(0x2245); else if (n=="ellipsis") symbol=QChar(0x2026); else if (n=="Im") symbol=QChar(0x2111); else if (n=="Re") symbol=QChar(0x211C); else if (n=="otimes") symbol=QChar(0x2297); else if (n=="oplus") symbol=QChar(0x2295); else if (n=="oslash") symbol=QChar(0x2298); else if (n=="cap"||n=="land") symbol=QChar(0x2229); else if (n=="cup"||n=="lor") symbol=QChar(0x222A); else if (n=="supset") symbol=QChar(0x2283); else if (n=="supseteq") symbol=QChar(0x2286); else if (n=="supsetnot") symbol=QChar(0x2285); else if (n=="subset") symbol=QChar(0x2282); else if (n=="subseteq") symbol=QChar(0x2286); else if (n=="in") symbol=QChar(0x2208); else if (n=="notin") symbol=QChar(0x2209); else if (n=="angle") symbol=QChar(0x2221); else if (n=="nabla") symbol=QChar(0x2207); else if (n=="copyright") symbol=QChar(0x00A9); else if (n=="registered") symbol=QChar(0x00AE); else if (n=="trademark") symbol=QChar(0x2122); else if (n=="cdot") symbol=QChar(0x00B7); else if (n=="neg") symbol=QChar(0x00AC); else if (n=="wedge") symbol=QChar(0x2227); else if (n=="vee") symbol=QChar(0x2228); else if (n=="diamond") symbol=QChar(0xE0); else if (n=="langle") symbol=QChar(0x2329); else if (n=="rangle") symbol=QChar(0x232A); else if (n=="int") { symbol=QChar(0x222B); fontFactor=mathFontFactor; /*yfactor=+0.1;*/ heightIsAscent=true; exactAscent=true; } else if (n=="infty") { symbol=QChar(0x221E); } else if (n=="forall") { symbol=QChar(0x2200); } else if (n=="exists") { symbol=QChar(0x2203); } else if (n=="cong") { symbol=QChar(0x2245); } else if (n=="bot") { symbol=QChar(0x22A5); } 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->get_fontEncoding()==MTFElatex) { // use UNICODE encoding for special characters // first we start with greek characters font=MTSFdefault; //MTSFgreek; //std::cout<<"encoding unicode\n"; 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(0x27); } else if (n=="grq") { symbol=QChar(0x60); } else if (n=="glqq") { symbol=QChar(0x5C); } else if (n=="grqq") { symbol="\""; } //else if (n=="flq") { symbol=QChar(0x2039); } //else if (n=="frq") { symbol=QChar(0x203A); } //else if (n=="flqq") { symbol=""; } //else if (n=="frqq") { symbol=""; } else { font=MTSFgreek; if (n=="alpha") symbol=QChar(0xAE); else if (n=="beta") symbol=QChar(0xAF); else if (n=="gamma") symbol=QChar(0xB0); else if (n=="delta") symbol=QChar(0xB1); else if (n=="epsilon") symbol=QChar(0x22); else if (n=="varepsilon") symbol=QChar(0xB2); else if (n=="zeta") symbol=QChar(0xB3); else if (n=="eta") symbol=QChar(0xB4); else if (n=="theta") symbol=QChar(0xB5); else if (n=="vartheta") symbol=QChar(0x23); else if (n=="iota") symbol=QChar(0xB6); else if (n=="kappa") symbol=QChar(0xB7); else if (n=="lambda") symbol=QChar(0xB8); else if (n=="mu") symbol=QChar(0xB9); else if (n=="nu") symbol=QChar(0xBA); else if (n=="xi") symbol=QChar(0xBB); else if (n=="pi") symbol=QChar(0xBC); else if (n=="varpi") symbol=QChar(0x24); else if (n=="rho") symbol=QChar(0xBD); else if (n=="varrho") symbol=QChar(0x25); else if (n=="sigma") symbol=QChar(0xBE); else if (n=="varsigma") symbol=QChar(0x26); else if (n=="tau") symbol=QChar(0xBF); else if (n=="upsilon") symbol=QChar(0xC0); else if (n=="phi") symbol=QChar(0xC1); else if (n=="varphi") symbol=QChar(0x27); else if (n=="chi") symbol=QChar(0xC2); else if (n=="psi") symbol=QChar(0xC3); else if (n=="omega") symbol=QChar(0x21); //else if (n=="Omega") symbol=QChar(0x3A9); else if (n=="Gamma") symbol=QChar(0xA1); else if (n=="Delta") symbol=QChar(0xA2); else if (n=="Theta") symbol=QChar(0xA3); else if (n=="Lambda") symbol=QChar(0xA4); else if (n=="Xi") symbol=QChar(0xA5); else if (n=="Pi") symbol=QChar(0xA6); else if (n=="Sigma") symbol=QChar(0xA7); else if (n=="Upsilon") symbol=QChar(0xA8); else if (n=="Phi") symbol=QChar(0xA9); else if (n=="Psi") symbol=QChar(0xAA); else if (n=="leftharpoonup") { symbol=QChar(0x28); } else if (n=="rightharpoonup") { symbol=QChar(0x2A); } else if (n=="leftharpoondown") { symbol=QChar(0x29); } else if (n=="rightharpoondown") { symbol=QChar(0x2B); } else if (n=="neg") symbol=QChar(0xAC); else if (n=="star") symbol=QChar(0x3F); else { // now we set the symbols from the Symbol font font=MTSFsymbol; if (n=="leftrightarrow") symbol=QChar(0x24); else if (n=="leftarrow") symbol=QChar(0xc3); else if (n=="rightarrow"||n=="to") symbol=QChar(0x21); else if (n=="uparrow") symbol=QChar(0x22); else if (n=="downarrow") symbol=QChar(0x23); else if (n=="updownarrow") symbol=QChar(0x6c); else if (n=="Leftrightarrow" || n=="iff") symbol=QChar(0x2c); else if (n=="Leftarrow") symbol=QChar(0x28); else if (n=="Rightarrow") symbol=QChar(0x29); else if (n=="Uparrow") symbol=QChar(0x2a); else if (n=="Downarrow") symbol=QChar(0x2b); else if (n=="Updownarrow") symbol=QChar(0x6d); else if (n=="pm") symbol=QChar(0xa7); else if (n=="mp") symbol=QChar(0xa8); else if (n=="leq") symbol=QChar(0xb7); else if (n=="geq") symbol=QChar(0xb8); else if (n=="ll") symbol=QChar(0xbf); else if (n=="gg") symbol=QChar(0xc0); //else if (n=="euro") symbol=QChar(0x20AC); else if (n=="Alef" || n=="alef") symbol=QChar(0x40); //else if (n=="Bet") symbol=QChar(0x2136); //else if (n=="Gimel") symbol=QChar(0x2137); //else if (n=="Dalet") symbol=QChar(0x2138); else if (n=="ni") symbol=QChar(0x33); else if (n=="circ") symbol=QChar(0xb1); else if (n=="tilde") symbol=QChar(0xbb); else if (n=="emptyset") symbol=QChar(0x3b); else if (n=="odot") symbol=QChar(0xaf); else if (n=="ominus") symbol=QChar(0xaa); else if (n=="odiv") symbol=QChar(0xae); else if (n=="oplus") symbol=QChar(0xa9); else if (n=="lceil") symbol=QChar(0x64); else if (n=="rceil") symbol=QChar(0x65); else if (n=="lfloor") symbol=QChar(0x62); else if (n=="rfloor") symbol=QChar(0x63); else if (n=="bot") { symbol=QChar(0x3f); } else if (n=="cdots") { symbol=QString(3,QChar(0xA2)); } else if (n=="dots") { symbol="..."; } else if (n=="nwarrow") { symbol=QChar(0x2d); } else if (n=="nearrow") { symbol=QChar(0x25); } else if (n=="searrow") { symbol=QChar(0x26); } else if (n=="swarrow") { symbol=QChar(0x2e); } else if (n=="div") { symbol=QChar(0xa5); } else if (n=="times") symbol=QChar(0xa3); else if (n=="propto") symbol=QChar(0x2f); else if (n=="bullet") symbol=QChar(0x2b); else if (n=="equiv") symbol=QChar(0xb4); else if (n=="approx") symbol=QChar(0xbc); else if (n=="ellipsis") symbol="..."; else if (n=="Im") symbol=QChar(0x3D); else if (n=="Re") symbol=QChar(0x3C); //else if (n=="otimes") symbol=QChar(0x2297); else if (n=="oplus") symbol=QChar(0xa9); else if (n=="oslash") symbol=QChar(0xae); else if (n=="cap"||n=="land") symbol=QChar(0x5c); else if (n=="cup"||n=="lor") symbol=QChar(0x5b); else if (n=="supset") symbol=QChar(0xbe); else if (n=="supseteq") symbol=QChar(0xb6); else if (n=="subset") symbol=QChar(0xbd); else if (n=="subseteq") symbol=QChar(0xb5); else if (n=="in") symbol=QChar(0x32); else if (n=="nabla") symbol=QChar(0x35); else if (n=="cdot") symbol=QChar(0xa2); else if (n=="wedge") symbol=QChar(0x5e); else if (n=="vee") symbol=QChar(0x5f); else if (n=="diamond") symbol=QChar(0xE0); else if (n=="langle") symbol=QChar(0x68); else if (n=="rangle") symbol=QChar(0x69); else if (n=="int") { symbol=QChar(0x73); fontFactor=mathFontFactor; yfactor=+0.1; } else if (n=="infty") { symbol=QChar(0x31); } else if (n=="forall") { symbol=QChar(0x38); } else if (n=="exists") { symbol=QChar(0x39); } else if (n=="cong") { symbol=QChar(0xbb); } else if (n=="bot") { symbol=QChar(0x3f); } 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=="oiint") { symbol=QChar(0x222F); fontFactor=mathFontFactor; yfactor=+0.1; } //else if (n=="oiiint") { symbol=QChar(0x2230); fontFactor=mathFontFactor; 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; } /*else if (n=="angle") symbol=QChar(0x2221); else if (n=="supsetnot") symbol=QChar(0x2285); else if (n=="notin") symbol=QChar(0x2209); else if (n=="multimap") { symbol=QChar(0x22B8); } else if (n=="neq") symbol=QChar(0x2260); else if (n=="maporiginal") { symbol=QChar(0x22B6); } else if (n=="mapimage") { symbol=QChar(0x22B7); } else if (n=="partial") symbol=QChar(0x2202); else if (n=="benzene") symbol=QChar(0x232C); else if (n=="perthousand") { symbol=QChar(0x2030); } else if (n=="upharpoonleft") { symbol=QChar(0x21BF); } else if (n=="downharpoonleft") { symbol=QChar(0x21C3); } else if (n=="leftrightharpoon") { symbol=QChar(0x21CB); } else if (n=="rightleftharpoon") { symbol=QChar(0x21CC); } else if (n=="upharpoonright") { symbol=QChar(0x21BE); } else if (n=="downharpoonright") { symbol=QChar(0x21C2); } else if (n=="varnothing") symbol=QChar(0x2300); else if (n=="mapsto") { symbol=QChar(0x21A6); } else if (n=="cent") { symbol=QChar(0x00A2); } else if (n=="pound") { symbol=QChar(0x00A3); } else if (n=="yen") { symbol=QChar(0x00A5); } else if (n=="hbar") symbol=QChar(0x210F); else if (n=="nexists") { symbol=QChar(0x2204); } else if (n=="notni") symbol=QChar(0x220C); else if (n=="subsetnot") symbol=QChar(0x2284);*/ //else if (n=="DC") symbol=QChar(0x2393); //else if (n=="copyright") symbol=QChar(0x00A9); //else if (n=="registered") symbol=QChar(0x00AE); //else if (n=="trademark") symbol=QChar(0x2122); } //else if (n=="") { symbol=QChar(); font=MTSFdefault; } //else if (n=="") symbol=QChar(0x); } } } } if (addWhitespace) symbol=symbol+" "; //std::cout<<"symbol node '"<get_fontGreek()); break; case MTSFsymbol: fr.setFamily(parent->get_fontSymbol()); break; case MTSFbraces: fr.setFamily(parent->get_fontBraces()); break; case MTSFintegrals: fr.setFamily(parent->get_fontIntegrals()); break; case MTSFcaligraphic: fr.setFamily(parent->get_fontCaligraphic()); break; case MTSFblackboard: fr.setFamily(parent->get_fontBlackboard()); 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==" ") 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()<get_mathoperator_width_factor(); } 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); if (extendWidthInMathmode && currentEv.insideMath) { x=x+0.5*width*parent->get_mathoperator_width_factor(); } //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(); painter.translate(x+fm1.width("8")/3.0, y-fm1.xHeight()); painter.rotate(90); painter.drawText(QPointF(0,0), "8"); painter.restore(); } else if (symbolName=="|") { //std::cout<<"draw infty\n"; f1.setItalic(false); painter.setFont(f1); painter.save(); painter.translate(x, y); painter.drawText(QPointF(0,0), "|"); painter.translate(fm1.width("8")/3.0, 0); painter.drawText(QPointF(0,0), "|"); painter.restore(); // here are some spaces } else if (symbolName==" ") { // full 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+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+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+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+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+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+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,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; if (symbolName == "sin") { s="sin"; } else if (symbolName == "cos") { s="cos"; } else if (symbolName == "tan") { s="tan"; } else if (symbolName == "sinh") { s="sinh"; } else if (symbolName == "cosh") { s="cosh"; } else if (symbolName == "tanh") { s="tanh"; } else if (symbolName == "atan") { s="atan"; } else if (symbolName == "acos") { s="acos"; } else if (symbolName == "asin") { s="asin"; } else if (symbolName == "arcsin") { s="arcsin"; } else if (symbolName == "arccos") { s="arccos"; } else if (symbolName == "arctan") { s="arctan"; } else if (symbolName == "ii") { s="i"; } else if (symbolName == "dd") { s="d"; } else if (symbolName == "exp") { s="exp"; } else if (symbolName == "log") { s="log"; } else if (symbolName == "ln") { s="ln"; } else if (symbolName == "ld") { s="ld"; } else if (symbolName == "lb") { s="lb"; } else if (symbolName == "erf") { s="erf"; } else if (symbolName == "min") { s="min"; } else if (symbolName == "max") { s="max"; } else if (symbolName == "argmin") { s="argmin"; } else if (symbolName == "argmax") { s="argmax"; } else if (symbolName == "inf") { s="inf"; } else if (symbolName == "sup") { s="sup"; } else if (symbolName == "liminf") { s="liminf"; } else if (symbolName == "limsup") { s="limsup"; } else if (symbolName == "lim") { s="lim"; } else if (symbolName == "max") { s="max"; } else if (symbolName == "min") { s="min"; } else if (symbolName == "sec") { s="sec"; } else if (symbolName == "gcd") { s="gcd"; } else if (symbolName == "hom") { s="hom"; } else if (symbolName == "ker") { s="ker"; } else if (symbolName == "dim") { s="dim"; } else if (symbolName == "cot") { s="cot"; } else if (symbolName == "arg") { s="arg"; } else if (symbolName == "det") { s="det"; } else if (symbolName == "deg") { s="deg"; } else if (symbolName == "Pr") { s="Pr"; } else if (symbolName == "coth") { s="coth"; } else if (symbolName == "alpha") s="α"; else if (symbolName == "beta") s="β"; else if (symbolName == "gamma") s="γ"; else if (symbolName == "delta") s="δ"; else if (symbolName == "epsilon") s="ε"; else if (symbolName == "varepsilon") s="ε"; else if (symbolName == "zeta") s="ζ"; else if (symbolName == "eta") s="η"; else if (symbolName == "theta") s="θ"; else if (symbolName == "vartheta") s="ϑ"; else if (symbolName == "iota") s="ι"; else if (symbolName == "kappa") s="κ"; else if (symbolName == "lambda") s="λ"; else if (symbolName == "mu") s="μ"; else if (symbolName == "nu") s="ν"; else if (symbolName == "xi") s="ξ"; else if (symbolName == "pi") s="π"; else if (symbolName == "varpi") s="ϖ"; else if (symbolName == "rho") s="ρ"; else if (symbolName == "sigma") s="σ"; else if (symbolName == "varsigma") s="ς"; else if (symbolName == "tau") s="τ"; else if (symbolName == "upsilon") s="υ"; else if (symbolName == "phi") s="φ"; else if (symbolName == "varphi") s="φ"; else if (symbolName == "chi") s="χ"; else if (symbolName == "psi") s="ψ"; else if (symbolName == "omega") s="ω"; else if (symbolName == "Gamma") s="Γ"; else if (symbolName == "Delta") s="Δ"; else if (symbolName == "Theta") s="Θ"; else if (symbolName == "Lambda") s="Λ"; else if (symbolName == "Omega") s="Ω"; else if (symbolName == "Xi") s="Ξ"; else if (symbolName == "Pi") s="Π"; else if (symbolName == "Sigma") s="Σ"; else if (symbolName == "sum") { ev.fontSize*=1.7; s="∑"; } else if (symbolName == "prod") { ev.fontSize*=1.7; s="∏"; } else if (symbolName == "Upsilon") s="Υ"; else if (symbolName == "Phi") s="Φ"; else if (symbolName == "Psi") s="Ψ"; else if (symbolName == "leftrightarrow") s="↔"; else if (symbolName == "leftarrow") s="←"; else if (symbolName == "rightarrow"||symbolName=="to") s="→"; else if (symbolName == "uparrow") s="↑"; else if (symbolName == "downarrow") s="↓"; else if (symbolName == "Leftrightarrow" || symbolName=="iff") s="⇔"; else if (symbolName == "Leftarrow") s="⇐"; else if (symbolName == "Rightarrow") s="⇒"; else if (symbolName == "Uparrow") s="⇑"; else if (symbolName == "Downarrow") s="⇓"; else if (symbolName == "pm") s="±"; else if (symbolName == "leq") s="≤"; else if (symbolName == "geq") s="≥"; else if (symbolName == "times") s="×"; else if (symbolName == "propto") s="∝"; else if (symbolName == "partial") s="∂"; else if (symbolName == "bullet") s="•"; else if (symbolName == "neq"||symbolName=="ne") s="≠"; else if (symbolName == "equiv") s="≡"; else if (symbolName == "approx") s="≈"; else if (symbolName == "ellipsis") s="..."; else if (symbolName == "Im") s="ℑ"; else if (symbolName == "Re") s="ℜ"; else if (symbolName == "otimes") s="⊗"; else if (symbolName == "oplus") s="⊕"; else if (symbolName == "oslash") s="/"; else if (symbolName == "cap"||symbolName=="land") s="∩"; else if (symbolName == "cup"||symbolName=="lor") s="∪"; else if (symbolName == "supset") s="⊃"; else if (symbolName == "supseteq") s="⊇"; else if (symbolName == "supsetnot") s="⊅"; else if (symbolName == "subset") s="⊂"; else if (symbolName == "subseteq") s="⊆"; else if (symbolName == "in") s="∈"; else if (symbolName == "notin") s="∉"; else if (symbolName == "angle") s="∠"; else if (symbolName == "nabla") s="∇"; else if (symbolName == "copyright") s="©"; else if (symbolName == "registered") s="®"; else if (symbolName == "trademark") s="™"; else if (symbolName == "cdot") s="⋅"; else if (symbolName == "neg") s="¬"; else if (symbolName == "wedge") s="∧"; else if (symbolName == "vee") s="∨"; else if (symbolName == "diamond") s="◊"; else if (symbolName == "langle") s="⟨"; else if (symbolName == "rangle") s="⟩"; else if (symbolName == "int") { s="∫"; } else if (symbolName == "forall") { s="∀"; } else if (symbolName == "exists") { s="∃"; } else if (symbolName == "cong") { s="∼"; } else if (symbolName == "bot") { s="⊥"; } else if (symbolName == "ll") { s="<<"; } else if (symbolName == "gg") { s=">>"; } else if (symbolName == "bbC") { s="C"; } else if (symbolName == "bbH") { s="H"; } else if (symbolName == "bbN") { s="N"; } else if (symbolName == "bbP") { s="P"; } else if (symbolName == "bbQ") { s="Q"; } else if (symbolName == "bbR") { s="R"; } else if (symbolName == "bbZ") { s="Z"; } else if (symbolName == "Alef" || symbolName=="alef") s="ℵ"; else if (symbolName == "tilde") s="~"; else if (symbolName == "iint") { s="∫∫"; } else if (symbolName == "iiint") { s="∫∫∫"; } else if (symbolName == "emptyset") s="∅"; else if (symbolName == "varnothing") s="∅"; else if (symbolName == "lceil") s="⌈"; else if (symbolName == "rceil") s="⌉"; else if (symbolName == "lfloor") s="⌊"; else if (symbolName == "rfloor") s="⌋"; else if (symbolName == "subsetnot") s="⊄"; else if (symbolName == "DC") s="="; else if (symbolName == "cdots") { s="⋅⋅⋅"; } else if (symbolName == "dots") { s="..."; } else if (symbolName == "cent") { 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 if (symbolName == "_") { s="_"; } else if (symbolName == "}") { s="}"; } else if (symbolName == "{") { s="{"; } else if (symbolName == "hbar") { s="ℏ"; } else if (symbolName == "euro") { s="€"; } else if (symbolName == "pound") { s="£"; } else if (symbolName == "yen") { s="¥"; } else if (symbolName == "div") { s="÷"; } else if (symbolName == "backslash") { s="\\"; } else if (symbolName == "$") { s="$"; } else if (symbolName == "%") { s="%"; } else if (symbolName == "&") { s="&"; } else if (symbolName == "#") { s="#"; } else if (symbolName == "ast") { s="*"; } else if (symbolName == "glq") { s="'"; } else if (symbolName == "grq") { s="'"; } else if (symbolName == "glqq") { s="\""; } else if (symbolName == "grqq") { s="\""; } else if (symbolName == "flq") { s="<"; } else if (symbolName == "frq") { s=">"; } else if (symbolName == "flqq") { s=""; } else if (symbolName == "frqq") { 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) { 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::useAnyUnicode(QString timesFont, 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()->set_drawBoxes(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()->set_drawBoxes(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() { } 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::set_drawBoxes(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->set_fontSize(font().pointSizeF()*1.3); lastText=""; repaintDo=true; buffer=QPixmap(); } JKQTMathTextLabel::~JKQTMathTextLabel() { } 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 "<get_error_list().join("\n")<<"\n\n"; if (!m_mathText->parse(lastText)) { qDebug()<<"JKQTMathTextLabel::internalPaint(): parse '"<parse(lastText)<<"\n "<get_error_list().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, 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; }