/* Copyright (c) 2008-2020 Jan W. Krieger () This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License (LGPL) for more details. You should have received a copy of the GNU Lesser General Public License (LGPL) along with this program. If not, see . */ #include "jkqtmathtext/jkqtmathtext.h" #include "jkqtcommon/jkqtpcodestructuring.h" #include "jkqtcommon/jkqtpstringtools.h" #include #include #include #include #include #include #include const double JKQTMathText::ABS_MIN_LINEWIDTH=0.02; QPainterPath makeHBracePath(double x, double ybrace, double width, double bw, double cubicshrink=0.5, double cubiccontrolfac=0.3) { double xl1=x-(width)*cubicshrink+bw*cubicshrink; double xr2=x+(width)*cubicshrink-bw*cubicshrink; double xl2=x-bw*cubicshrink; double xr1=x+bw*cubicshrink; QPainterPath path; path.moveTo(xl1-bw*cubicshrink, ybrace-bw*cubicshrink); path.cubicTo(xl1-bw*cubicshrink, ybrace-bw*cubicshrink+bw*cubiccontrolfac, xl1-bw*cubiccontrolfac, ybrace, xl1, ybrace); path.lineTo(xl2, ybrace); path.cubicTo(xl2+bw*cubiccontrolfac, ybrace, (xl2+xr1)/2.0, ybrace+bw*cubicshrink-bw*cubiccontrolfac, (xl2+xr1)/2.0, ybrace+bw*cubicshrink); path.cubicTo((xl2+xr1)/2.0, ybrace+bw*cubicshrink-bw*cubiccontrolfac, xr1-bw*cubiccontrolfac, ybrace, xr1, ybrace); path.lineTo(xr2, ybrace); path.cubicTo(xr2+bw*cubiccontrolfac, ybrace, xr2+bw*cubicshrink, ybrace-bw*cubicshrink+bw*cubiccontrolfac, xr2+bw*cubicshrink, ybrace-bw*cubicshrink); return path; } QPainterPath makeArrow(double x, double y, double width, double arrowW, bool left=false, bool right=true) { double x1=x; double x2=x+width; double x3=x2-arrowW/2.0; double y3u=y-arrowW/2.0; double y3d=y+arrowW/2.0; double x3l=x+arrowW/2.0; QPainterPath path; path.moveTo(x1, y); path.lineTo(x2, y); if (right) { path.moveTo(x3, y3u); path.lineTo(x2, y); path.lineTo(x3, y3d); } if (left) { path.moveTo(x3l, y3u); path.lineTo(x1, y); path.lineTo(x3l, y3d); } return path; } QPainterPath makeDArrow(double x, double y, double width, double arrowW, bool left=false, bool right=true) { double x1=x; double x2=x+width; double dx=arrowW/4.0; double y1=y-dx; double y2=y+dx; double x3=x2-arrowW/2.0; double y3u=y-arrowW/2.0; double y3d=y+arrowW/2.0; double x3l=x+arrowW/2.0; QPainterPath path; path.moveTo(x1+dx, y1); path.lineTo(x2-dx, y1); path.moveTo(x1+dx, y2); path.lineTo(x2-dx, y2); if (right) { path.moveTo(x3, y3u); path.lineTo(x2, y); path.lineTo(x3, y3d); } if (left) { path.moveTo(x3l, y3u); path.lineTo(x1, y); path.lineTo(x3l, y3d); } return path; } // -------------------------------------------------------------------------------------------------- // -- implementation of the MTnode's methods // -------------------------------------------------------------------------------------------------- JKQTMathText::MTenvironment::MTenvironment() { color=QColor("black"); font=MTEroman; fontSize=10; bold=false; italic=false; smallCaps=false; underlined=false; overline=false; strike=false; insideMath=false; } QFont JKQTMathText::MTenvironment::getFont(JKQTMathText* parent) const { QFont f; switch (font) { case MTEsans: if (insideMath) { f.setFamily(parent->getFontMathSans()); } else { f.setFamily(parent->getFontSans()); } break; case MTEmathSans: f.setFamily(parent->getFontMathSans()); break; case MTEtypewriter: f.setFamily(parent->getFontTypewriter()); break; case MTEscript: f.setFamily(parent->getFontScript()); break; case MTEcaligraphic: f.setFamily(parent->getFontCaligraphic()); break; case MTEblackboard: f.setFamily(parent->getFontBlackboard()); break; case MTEfraktur: f.setFamily(parent->getFontFraktur()); break; case MTEmathRoman: f.setFamily(parent->getFontMathRoman()); break; default: case MTEroman: if (insideMath) { f.setFamily(parent->getFontMathRoman()); } else { f.setFamily(parent->getFontRoman()); } break; } f.setBold(bold); f.setItalic(italic); f.setUnderline(underlined); f.setOverline(overline); f.setStrikeOut(strike); f.setCapitalization(QFont::MixedCase); if (smallCaps) f.setCapitalization(QFont::SmallCaps); f.setPointSizeF(fontSize); f.setStyleStrategy(QFont::NoFontMerging); return f; } QString JKQTMathText::MTenvironment::toHtmlStart(MTenvironment defaultEv) const { QString s; s=s+"font-size: "+QLocale::c().toString(fontSize)+"pt; "; if (insideMath) { if (defaultEv.italic) { if (!italic) s=s+"font-style: italic; "; if (italic) s=s+"font-style: normal; "; } else { if (!italic) s=s+"font-style: italic; "; } } else { if (!defaultEv.italic && italic) s=s+"font-style: italic; "; } if (bold && !defaultEv.bold) s=s+"font-weight: bold"; QStringList td; if (underlined && !defaultEv.underlined) td<<"underline"; if (overline && !defaultEv.overline) td<<"overline"; if (strike && !defaultEv.strike) td<<"line-through"; if (td.size()>0) s=s+"text-decoration: "+td.join(", "); return ""; } QString JKQTMathText::MTenvironment::toHtmlAfter(JKQTMathText::MTenvironment /*defaultEv*/) const { return ""; } JKQTMathText::MTnode::MTnode(JKQTMathText* parent) { this->parent=parent; drawBoxes=false; } JKQTMathText::MTnode::~MTnode() = default; void JKQTMathText::MTnode::getSize(QPainter &painter, JKQTMathText::MTenvironment currentEv, double &width, double &baselineHeight, double &overallHeight, double &strikeoutPos, const MTnodeSize* prevNodeSize) { double w=width, b=baselineHeight, o=overallHeight, s=strikeoutPos; getSizeInternal(painter, currentEv, w, b, o, s, prevNodeSize); if (w<1e5) width=w; if (b<1e5) baselineHeight=b; if (o<1e5) overallHeight=o; if (s<1e5) strikeoutPos=s; } bool JKQTMathText::MTnode::toHtml(QString &/*html*/, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/) { return false; } bool JKQTMathText::MTnode::getDrawBoxes() const { return this->drawBoxes; } void JKQTMathText::MTnode::doDrawBoxes(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv) { if (drawBoxes) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); double w, oh, bh, sp; getSize(painter, currentEv, w, bh, oh, sp); QPen p=painter.pen(); p.setColor("lightcoral"); p.setWidthF(0.5); painter.setPen(p); QRectF r(x, y-bh, w, oh); painter.drawRect(r); p.setColor("lightblue"); painter.setPen(p); if (w>0) painter.drawLine(QLineF(x, y, x+w, y)); p.setColor("green"); painter.setPen(p); painter.drawEllipse(QRectF(x-3.0,y-3.0,6.0,6.0)); p.setColor("lightgreen"); painter.setPen(p); painter.drawLine(QLineF(x-2.0, y, x+2.0, y)); painter.drawLine(QLineF(x, y-2, x, y+2.0)); } } JKQTMathText::MTtextNode::MTtextNode(JKQTMathText* _parent, const QString& textIn, bool addWhitespace, bool stripInnerWhitepace): JKQTMathText::MTnode(_parent) { QString text=textIn; if (stripInnerWhitepace) { text=""; for (int i=0; itext=text; // strip all whitespace from left while (this->text.size()>1 && this->text[0].isSpace()) { this->text=this->text.right(this->text.size()-1); } if (addWhitespace /*&& (this->text.size()>0)*/ && (!this->text[this->text.size()-1].isSpace())) this->text=this->text+" "; //qDebug()<<"MTtextNode( text="< this->text="<text<<"]"; } JKQTMathText::MTtextNode::~MTtextNode() = default; void JKQTMathText::MTtextNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) { QFont f=currentEv.getFont(parent); if (currentEv.insideMath && (text=="(" || text=="[" || text=="|" || text=="]" || text==")" || text=="<" || text==">" || text==QString(QChar(0x2329)) || text==QString(QChar(0x232A)) || text==QString(QChar(0x2308)) || text==QString(QChar(0x2309)) || text==QString(QChar(0x230A)) || text==QString(QChar(0x230B)))) { f.setItalic(false); //f.setFamily(parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Text).first); } QString txt=textTransform(text, currentEv, true); QFontMetricsF fm(f, painter.device()); QRectF br=fm.boundingRect(txt); QRectF tbr=parent->getTightBoundingRect(f, txt, painter.device()); //fm.tightBoundingRect(txt); if (txt=="|") { br=fm.boundingRect("X"); tbr=QRectF(0,0,fm.boundingRect("X").width(), 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.boundingRect("I").width(); } //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); } if (onlyDigits && currentEv.insideMath) { f.setItalic(false); } painter.setFont(f); //qDebug()<<"MTtextNode: text="<blackboardSimulated) { QPainterPath path; path.addText(QPointF(x+dx, y), f, txt); painter.drawPath(path); } else { 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 (iblackboardSimulated) { QPainterPath path; path.addText(QPointF(xx, y), ff, QString(txt[i])); painter.drawPath(path); } else { painter.setFont(ff); painter.drawText(QPointF(xx, y), QString(txt[i])); } xx=xx+fmff.boundingRect(txt[i]).width(); } else { if (currentEv.font==MTEblackboard && parent->blackboardSimulated) { QPainterPath path; path.addText(QPointF(xx, y), f, QString(txt[i])); painter.drawPath(path); } else { painter.setFont(f); painter.drawText(QPointF(xx, y), QString(txt[i])); } xx=xx+fm.boundingRect(txt[i]).width(); } i++; } } painter.setPen(pold); painter.setFont(fold); return x+width; } bool JKQTMathText::MTtextNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { html=html+currentEv.toHtmlStart(defaultEv)+text+currentEv.toHtmlAfter(defaultEv); return true; } QString JKQTMathText::MTtextNode::getText() const { return this->text; } QString JKQTMathText::MTtextNode::getTypeName() const { return QLatin1String("MTtextNode(")+text+")"; } QString JKQTMathText::MTtextNode::textTransform(const QString &text, JKQTMathText::MTenvironment currentEv, bool /*forSize*/) { QString txt=text; auto fnt=parent->getFontData(currentEv.font, currentEv.insideMath); if (fnt.second==MTFEunicode || fnt.second==MTFEunicodeLimited) { 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(" ", " "); } } return txt; } JKQTMathText::MTinstruction1Node::MTinstruction1Node(JKQTMathText* _parent, const QString& name, MTnode* child, const QStringList& parameters): JKQTMathText::MTnode(_parent) { this->name=name; this->child=child; this->parameters=parameters; JKQTMathText::MTenvironment ev; if (!setupMTenvironment(ev)) { parent->error_list.append(tr("unknown instruction '%1' found!").arg(name)); } } JKQTMathText::MTinstruction1Node::~MTinstruction1Node() { if (child!=nullptr) delete child; } QString JKQTMathText::MTinstruction1Node::getTypeName() const { return QLatin1String("MTinstruction1Node(")+name+")"; } void JKQTMathText::MTinstruction1Node::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) { JKQTMathText::MTenvironment ev=currentEv; setupMTenvironment(ev); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); if (name=="colorbox" || name=="fbox" || name=="boxed") { QFontMetricsF fm(ev.getFont(parent)); double xw=fm.boundingRect("x").width(); width+=xw; overallHeight+=xw; baselineHeight+=xw/2.0; } } double JKQTMathText::MTinstruction1Node::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) { doDrawBoxes(painter, x, y, currentEv); JKQTMathText::MTenvironment ev=currentEv; setupMTenvironment(ev); QPen oldPen=painter.pen(); double shiftX=0; if (name=="colorbox" || name=="fbox" || name=="boxed") { QColor fcol=currentEv.color; if (name=="colorbox") fcol=QColor(parameters.value(0, ev.color.name())); //qDebug()<<"COLOR="<getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); QPen p=painter.pen(); QFontMetricsF fm(currentEv.getFont(parent)); double xw=fm.boundingRect("x").width(); p.setColor(fcol); painter.setPen(p); painter.drawRect(QRectF(x,y-baselineHeight-xw/2,width+xw,overallHeight+xw)); shiftX=xw/2.0; } double xnew= child->draw(painter, x+shiftX, y, ev); painter.setPen(oldPen); return xnew; } bool JKQTMathText::MTinstruction1Node::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { JKQTMathText::MTenvironment ev=currentEv; setupMTenvironment(ev); return child->toHtml(html, ev, defaultEv); } void JKQTMathText::MTinstruction1Node::setDrawBoxes(bool draw) { drawBoxes=draw; child->setDrawBoxes(draw); } JKQTMathText::MTnode *JKQTMathText::MTinstruction1Node::getChild() const { return this->child; } QString JKQTMathText::MTinstruction1Node::getName() const { return this->name; } QStringList JKQTMathText::MTinstruction1Node::getParameters() const { return this->parameters; } bool JKQTMathText::MTinstruction1Node::setupMTenvironment(JKQTMathText::MTenvironment &ev) { if (name=="bf" || name=="textbf" || name=="mathbf") ev.bold=true; else if (name=="em") ev.italic=!ev.italic; else if (name=="it" || name=="textit" || name=="mathit") ev.italic=true; else if (name=="textcolor" || name=="mathcolor" || name=="color") ev.color=QColor(parameters.value(0, ev.color.name())); else if (name=="ensuremath" || name=="equation") { ev.italic=true; ev.insideMath=true; } else if (name=="sc" || name=="textsc" || name=="mathsc") ev.smallCaps=true; else if (name=="ul" || name=="underline" || name=="underlined") ev.underlined=true; else if (name=="ol" || name=="overline" || name=="overlined") ev.overline=true; else if (name=="strike") ev.strike=true; else if (name=="rm" || name=="textrm") { ev.font=JKQTMathText::MTEroman; ev.italic=false; } else if (name=="mathrm" || name=="operatorname") { ev.font=JKQTMathText::MTEroman; ev.italic=false; } else if (name=="mathbfit" || name=="bfit" || name=="textbfit") { ev.bold=true; ev.italic=true; } else if (name=="text" || name=="mbox" || name=="ensuretext") { ev.insideMath=false; ev.font=JKQTMathText::MTEroman; ev.italic=false; } else if (name=="mat") { ev.font=JKQTMathText::MTEroman; ev.italic=false; ev.bold=true; } else if (name=="cal" || name=="textcal" || name=="mathcal") { ev.font=JKQTMathText::MTEcaligraphic; ev.italic=false; } else if (name=="fcal" || name=="textfcal" || name=="mathfcal") { ev.font=JKQTMathText::MTEcaligraphic; ev.bold=true; } else if (name=="frak" || name=="textfrak" || name=="mathfrak") { ev.font=JKQTMathText::MTEfraktur; ev.italic=false; } else if (name=="ffrak" || name=="textffrak" || name=="mathffrak") { ev.font=JKQTMathText::MTEfraktur; ev.bold=true; } else if (name=="bb" || name=="textbb" || name=="mathbb") { ev.font=JKQTMathText::MTEblackboard; ev.italic=false; } else if (name=="tt" || name=="texttt" || name=="mathtt") { ev.font=JKQTMathText::MTEtypewriter; ev.italic=false; } else if (name=="sf" || name=="textsf" || name=="mathsf") { ev.font=JKQTMathText::MTEsans; ev.italic=false; } else if (name=="sfit" || name=="textsfit" || name=="mathsfit") { ev.font=JKQTMathText::MTEsans; ev.italic=true; } else if (name=="script" || name=="scr" || name=="textscript" || name=="textscr" || name=="mathscript" || name=="mathscr") { ev.font=JKQTMathText::MTEscript; ev.italic=false; } else if (name=="fscript" || name=="fscr" || name=="textfscript" || name=="textfscr" || name=="mathfscript" || name=="mathfscr") { ev.font=JKQTMathText::MTEscript; ev.bold=true; ev.italic=false; } else if (name=="displaystyle") { ev.fontSize=ev.fontSize/0.8; } else if (name=="scriptstyle") { ev.fontSize=ev.fontSize*0.8; } else if (name=="scriptscriptstyle") { ev.fontSize=ev.fontSize*0.8*0.8; } else { return false; } return true; } JKQTMathText::MTsubscriptNode::MTsubscriptNode(JKQTMathText* _parent, MTnode* child): JKQTMathText::MTnode(_parent) { this->child=child; } JKQTMathText::MTsubscriptNode::~MTsubscriptNode() { if (child!=nullptr) delete child; } void JKQTMathText::MTsubscriptNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* prevNodeSize) { JKQTMathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor(); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); QFontMetricsF fm(ev.getFont(parent), painter.device()); QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device()); double shift=parent->getSubShiftFactor()*tbr.height(); if (prevNodeSize!=nullptr && prevNodeSize->overallHeight-prevNodeSize->baselineHeight>shift) { shift=-1.0*(prevNodeSize->overallHeight-prevNodeSize->baselineHeight-shift); } double yshift=baselineHeight-shift; baselineHeight=shift; strikeoutPos=fm.strikeOutPos()+yshift; if (currentEv.italic && prevNodeSize==nullptr) width=width-double(fm.boundingRect(' ').width())*parent->getItalicCorrectionFactor(); } double JKQTMathText::MTsubscriptNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* prevNodeSize) { doDrawBoxes(painter, x, y, currentEv); JKQTMathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor(); QFontMetricsF fm(ev.getFont(parent), painter.device()); QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device()); double width=0, baselineHeight=0, overallHeight=0, strikeoutPos=0; child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); double shift=parent->getSubShiftFactor()*tbr.height(); if (prevNodeSize!=nullptr && prevNodeSize->overallHeight-prevNodeSize->baselineHeight>shift) { //qDebug()<<"oldshift="<overallHeight="<overallHeight<<", prevNodeSize->baselineHeight="<baselineHeight; shift=-1.0*(prevNodeSize->overallHeight-prevNodeSize->baselineHeight-shift); //qDebug()<<"newshift="<child; } bool JKQTMathText::MTsubscriptNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { html=html+""; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+""; return ok; } void JKQTMathText::MTsubscriptNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; child->setDrawBoxes(draw); } JKQTMathText::MTsqrtNode::MTsqrtNode(JKQTMathText* _parent, MTnode* child, int degree): JKQTMathText::MTnode(_parent) { this->child=child; this->degree=degree; } JKQTMathText::MTsqrtNode::~MTsqrtNode() { if (child!=nullptr) delete child; } void JKQTMathText::MTsqrtNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) { QFontMetricsF fm(currentEv.getFont(parent), painter.device()); child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); overallHeight=overallHeight*1.2;//+fm.ascent()*0.1; baselineHeight=baselineHeight*1.2;//+fm.ascent()*0.1; width=width+fm.boundingRect("A").width()*2; // 1.53 } double JKQTMathText::MTsqrtNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) { doDrawBoxes(painter, x, y, currentEv); double width=0, baselineHeight=0, overallHeight=0, sp=0; child->getSize(painter, currentEv, width, baselineHeight, overallHeight, sp); QFont f=currentEv.getFont(parent); QFont fsmall=f; QFontMetricsF fm(f, painter.device()); double w=fm.boundingRect("A").width(); double a=baselineHeight*1.15; double d=overallHeight-baselineHeight; //painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); QPen p=painter.pen(); p.setColor(currentEv.color); p.setWidthF(fm.lineWidth()); //painter.setPen(p); QPainterPath path; if (w>0) { path.moveTo(x+0.1*w, y-0.4*a); path.lineTo(x+0.33*w, y-0.4*a); path.lineTo( x+0.66*w, y+0.5*d); path.lineTo(x+w, y-a); } if (degree!=2) { fsmall.setPointSizeF(fsmall.pointSizeF()/2.0); fsmall.setItalic(false); painter.setFont(fsmall); painter.drawText(QPointF(x+0.33*w, y-0.55*a), QLocale::c().toString(degree)); } //painter.restore(); double xnew=child->draw(painter, x+1.2*w, y, currentEv); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(p); if (w>0) { path.lineTo( xnew+0.2*w, y-a); path.lineTo(xnew+0.2*w, y-0.8*a); painter.drawPath(path); } return xnew+0.33*w; } bool JKQTMathText::MTsqrtNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { html=html+"√"; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+" "; return ok; } void JKQTMathText::MTsqrtNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; child->setDrawBoxes(draw); } QString JKQTMathText::MTsqrtNode::getTypeName() const { return "MTsqrtNode"; } JKQTMathText::MTnode *JKQTMathText::MTsqrtNode::getChild() const { return this->child; } int JKQTMathText::MTsqrtNode::getDegree() const { return this->degree; } JKQTMathText::MTfracNode::MTfracNode(JKQTMathText* _parent, MTnode* child_top, MTnode* child_bottom, MTfracMode mode): JKQTMathText::MTnode(_parent) { this->child1=child_top; this->child2=child_bottom; this->mode=mode; } JKQTMathText::MTfracNode::~MTfracNode() { if (child1!=nullptr) delete child1; if (child2!=nullptr) delete child2; } QString JKQTMathText::MTfracNode::getTypeName() const { return "MTfracNode"; } void JKQTMathText::MTfracNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) { QFontMetricsF fm(currentEv.getFont(parent), painter.device()); JKQTMathText::MTenvironment ev1=currentEv; JKQTMathText::MTenvironment ev2=currentEv; double xh=fm.xHeight(); //tightBoundingRect("x").height(); double sp=xh; double Ah=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device()).height();//fm.ascent(); double xw=fm.boundingRect("x").width(); if (mode==MTFMunderbrace || mode==MTFMoverbrace) { ev2.fontSize=ev2.fontSize*parent->getUnderbraceFactor(); } else if (mode==MTFMunderset || mode==MTFMoverset) { ev2.fontSize=ev2.fontSize*parent->getUndersetFactor(); } else if (mode==MTFMfrac || mode==MTFMsfrac) { ev1.fontSize=ev1.fontSize*parent->getFracFactor(); ev2.fontSize=ev2.fontSize*parent->getFracFactor(); } else if (mode==MTFMtfrac || mode==MTFMstfrac) { ev1.fontSize=ev1.fontSize*parent->getFracFactor()*0.7; ev2.fontSize=ev2.fontSize*parent->getFracFactor()*0.7; } double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos1=0; double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos2=0; child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos1); child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos2); overallHeight=0; baselineHeight=0; width=0; if (mode==MTFMfrac || mode==MTFMdfrac || mode==MTFMtfrac) { //std::cout<<"\nxh="< baselineHeight="<getTightBoundingRect(f, "M", painter.device()).height();//fm.ascent(); double bw=Ah/2.0; if (mode==MTFMunderbrace || mode==MTFMoverbrace) { ev2.fontSize=ev2.fontSize*parent->getUnderbraceFactor(); } else if (mode==MTFMunderset || mode==MTFMoverset) { ev2.fontSize=ev2.fontSize*parent->getUndersetFactor(); } else if (mode==MTFMfrac || mode==MTFMsfrac) { ev1.fontSize=ev1.fontSize*parent->getFracFactor(); ev2.fontSize=ev2.fontSize*parent->getFracFactor(); } else if (mode==MTFMtfrac || mode==MTFMstfrac) { ev1.fontSize=ev1.fontSize*parent->getFracFactor()*0.7; ev2.fontSize=ev2.fontSize*parent->getFracFactor()*0.7; } double width1=0, baselineHeight1=0, overallHeight1=0;//, strikeoutPos1=0; double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos=0; child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos); child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos); double ascent1=baselineHeight1; double descent1=overallHeight1-baselineHeight1; double ascent2=baselineHeight2; double descent2=overallHeight2-baselineHeight2; double yline=y-xh*0.5; //double overallHeight=overallHeight1+overallHeight2+xh; //double baselineHeight=3.0*xh/2.0+overallHeight1; double width=qMax(width1, width2); QPen p=painter.pen(); p.setColor(ev1.color); p.setStyle(Qt::SolidLine); p.setWidthF(qMax(JKQTMathText::ABS_MIN_LINEWIDTH, lw)); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.setPen(p); if (mode==MTFMfrac || mode==MTFMdfrac || mode==MTFMtfrac) { QLineF l(x+xw/4.0, yline, x+width+xw/2.0, yline); if (l.length()>0) painter.drawLine(l); child1->draw(painter, x+xw/2.0+(width-width1)/2.0, yline-xh*(parent->getFracShiftFactor())-descent1, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->getFracShiftFactor())+ascent2, ev2); } else if (mode==MTFMstfrac || mode==MTFMsfrac) { child1->draw(painter, x, yline-descent1, ev1); child2->draw(painter, x+width+xw, yline+ascent2, ev2); QLineF l(x+width+1.2*xw, yline-descent1-ascent1, x+width-0.2*xw, yline+ascent1+descent1); if (l.length()>0) painter.drawLine(l); } else if (mode==MTFMstackrel) { child1->draw(painter, x+xw/2.0+(width-width1)/2.0, yline-xh*(parent->getFracShiftFactor())-descent1, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->getFracShiftFactor())+ascent2, ev2); } else if (mode==MTFMunderset) { child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y+descent1+xh/6.0+ascent2, ev2); } else if (mode==MTFMunderbrace) { double ybrace=y+descent1+bw/2.0; QPainterPath path=makeHBracePath(x+xw/2.0+(width1)/2.0, ybrace, width, bw); painter.drawPath(path); child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y+descent1+bw+ascent2, ev2); } else if (mode==MTFMoverset) { child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y-ascent1-xh/6.0-descent2, ev2); } else if (mode==MTFMoverbrace) { double ybrace=y-ascent1-bw/2.0; { painter.save(); auto __finalpaintinner=JKQTPFinally([&painter]() {painter.restore();}); painter.translate(x+xw/2.0+(width1)/2.0, ybrace); painter.rotate(180); QPainterPath path=makeHBracePath(0,0, width, bw); painter.drawPath(path); } child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y-ascent1-bw-descent2, ev2); } if (mode==MTFMstackrel) return x+width+ xw; else if (mode==MTFMstfrac || mode==MTFMsfrac) return x+width+width2+xw; else return x+width+xw; } bool JKQTMathText::MTfracNode::toHtml(QString &/*html*/, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/) { bool ok=false; return ok; } void JKQTMathText::MTfracNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; child1->setDrawBoxes(draw); child2->setDrawBoxes(draw); } JKQTMathText::MTnode *JKQTMathText::MTfracNode::getChild1() const { return this->child1; } JKQTMathText::MTnode *JKQTMathText::MTfracNode::getChild2() const { return this->child2; } JKQTMathText::MTfracMode JKQTMathText::MTfracNode::getMode() const { return this->mode; } JKQTMathText::MTmatrixNode::MTmatrixNode(JKQTMathText* _parent, QVector > children): JKQTMathText::MTnode(_parent) { this->lines=children.size(); this->columns=0; for (int i=0; ithis->columns) this->columns=children[i].size(); } this->children=children; } JKQTMathText::MTmatrixNode::~MTmatrixNode() { for (int i=0; igetFracFactor(); QVector colwidth, rowheight; //QVector > widths, heights, baselines; double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos1=0; //widths.resize(lines); colwidth.resize(columns); for (int i=0; igetSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos1); /*widths[i].operator[](j)=width1; baselines[i].operator[](j)=baselineHeight; heights[i].operator[](j)=overallHeight1;*/ if (overallHeight1>rowheight[i]) rowheight[i]=overallHeight1; if (width1>colwidth[j]) colwidth[j]=width1; } } overallHeight=(lines-1)*xw/2.0; width=columns*xw; for (int i=0; igetFracFactor(); QVector colwidth, rowheight, rowascent; //QVector > widths, heights, baselines; double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos=0; //widths.resize(lines); colwidth.resize(columns); for (int i=0; igetSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos); /*widths[i].operator[](j)=width1; baselines[i].operator[](j)=baselineHeight; heights[i].operator[](j)=overallHeight1;*/ if (overallHeight1>rowheight[i]) rowheight[i]=overallHeight1; if (baselineHeight1>rowascent[i]) rowascent[i]=baselineHeight1; if (width1>colwidth[j]) colwidth[j]=width1; } } double overallHeight=(lines-1)*xw/2.0; double width=(columns)*xw; for (int i=0; i0) yy=yy+rowascent[0]; for (int i=0; idraw(painter, xx, yy, ev1); xx=xx+colwidth[j]+xw; } if (i > JKQTMathText::MTmatrixNode::getChildren() const { return this->children; } int JKQTMathText::MTmatrixNode::getColumns() const { return this->columns; } int JKQTMathText::MTmatrixNode::getLines() const { return this->lines; } void JKQTMathText::MTmatrixNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; for (int i=0; isetDrawBoxes(draw); } } } JKQTMathText::MTdecoratedNode::MTdecoratedNode(JKQTMathText* _parent, MTdecoration decoration, MTnode* child): JKQTMathText::MTnode(_parent) { this->child=child; this->decoration=decoration; } JKQTMathText::MTdecoratedNode::~MTdecoratedNode() { if (child!=nullptr) delete child; } void JKQTMathText::MTdecoratedNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) { QFontMetricsF fm(currentEv.getFont(parent), painter.device()); double wc=fm.boundingRect("A").width(); double dheightfactor=1.0+parent->getDecorationHeightFactor()*2.0; child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); overallHeight=overallHeight*dheightfactor; baselineHeight=baselineHeight*dheightfactor; width=width+0.3*wc; } double JKQTMathText::MTdecoratedNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) { doDrawBoxes(painter, x, y, currentEv); MTenvironment ev=currentEv; double width=0, baselineHeight=0, overallHeight=0, strikeoutPos=0; child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); QFontMetricsF fm(ev.getFont(parent), painter.device()); double w=width; double wc=fm.boundingRect("A").width(); //double ll=wc*0.8; double a=baselineHeight; //double d=overallHeight-baselineHeight; double dheightfactor=parent->getDecorationHeightFactor(); double dpos=y-a*(1.0+dheightfactor); double dposb=y+qMax((overallHeight-baselineHeight)*(1.0+dheightfactor), fm.xHeight()*dheightfactor); double deltax=0;//(wc-ll)/2.0; double dheight=dheightfactor*a; if (ev.italic) deltax+=0.1*fm.boundingRect("A").width(); QPen pold=painter.pen(); QPen p=pold; p.setColor(ev.color); p.setWidthF(qMax(JKQTMathText::ABS_MIN_LINEWIDTH, fm.lineWidth()));//ceil(currentEv.fontSize/16.0)); if (decoration==MTDbar) ev.overline=true; double xnew=child->draw(painter, x, y, ev); if (decoration==MTDvec) { painter.setPen(p); QPolygonF poly; poly<0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDdoubleoverline) { painter.setPen(p); QLineF l(x+deltax, dpos, xnew+deltax-0.2*wc, dpos); if (l.length()>0) painter.drawLine(l); l=QLineF(x+deltax, dpos-2.0*p.widthF(), xnew+deltax-0.2*wc, dpos-2.0*p.widthF()); if (l.length()>0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDunderline) { painter.setPen(p); QLineF l(x+deltax, dposb, xnew+deltax-0.2*wc, dposb); if (l.length()>0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDdoubleunderline) { painter.setPen(p); QLineF l(x+deltax, dposb, xnew+deltax-0.2*wc, dposb); if (l.length()>0) painter.drawLine(l); l=QLineF(x+deltax, dposb+2.0*p.widthF(), xnew+deltax-0.2*wc, dposb+2.0*p.widthF()); if (l.length()>0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDarrow) { painter.setPen(p); QLineF l(x+deltax, dpos+dheight/2.0, xnew+deltax-0.2*wc, dpos+dheight/2.0); if (l.length()>0) painter.drawLine(l); QPolygonF poly; poly<toHtml(html, ev, defaultEv); return false; } void JKQTMathText::MTdecoratedNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; child->setDrawBoxes(draw); } QString JKQTMathText::MTdecoratedNode::getTypeName() const { return "MTdecoratedNode"; } JKQTMathText::MTnode *JKQTMathText::MTdecoratedNode::getChild() const { return this->child; } JKQTMathText::MTdecoration JKQTMathText::MTdecoratedNode::getDecoration() const { return this->decoration; } JKQTMathText::MTsuperscriptNode::MTsuperscriptNode(JKQTMathText* _parent, MTnode* child): JKQTMathText::MTnode(_parent) { this->child=child; } JKQTMathText::MTsuperscriptNode::~MTsuperscriptNode() { if (child!=nullptr) delete child; } void JKQTMathText::MTsuperscriptNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* prevNodeSize) { JKQTMathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor(); QFontMetricsF fm(currentEv.getFont(parent), painter.device()); QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device()); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); double shift=parent->getSuperShiftFactor()*tbr.height(); if (prevNodeSize!=nullptr && prevNodeSize->baselineHeight>tbr.height()) { shift=prevNodeSize->baselineHeight-(overallHeight-baselineHeight)-shift; } double yshift=shift+overallHeight-baselineHeight; baselineHeight=overallHeight=overallHeight+shift; strikeoutPos=strikeoutPos-yshift; if (currentEv.italic && prevNodeSize==nullptr) width=width+double(fm.boundingRect(' ').width())*parent->getItalicCorrectionFactor(); } double JKQTMathText::MTsuperscriptNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* prevNodeSize) { doDrawBoxes(painter, x, y, currentEv); JKQTMathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getSubsuperSizeFactor(); double cWidth, cBaselineHeight, cOverallHeight, cStrikeoutPos; child->getSize(painter, ev, cWidth, cBaselineHeight, cOverallHeight, cStrikeoutPos); QFontMetricsF fm(currentEv.getFont(parent), painter.device()); QRectF tbr=parent->getTightBoundingRect(currentEv.getFont(parent), "M", painter.device()); double shift=parent->getSuperShiftFactor()*tbr.height(); if (prevNodeSize!=nullptr && prevNodeSize->baselineHeight>tbr.height()) { shift=prevNodeSize->baselineHeight-(cOverallHeight-cBaselineHeight)-shift; } double yshift=shift+cOverallHeight-cBaselineHeight; double xx=x; if (currentEv.italic && prevNodeSize==nullptr) xx=xx+double(fm.boundingRect(' ').width())*parent->getItalicCorrectionFactor(); return child->draw(painter, xx, y-yshift, ev);//+0.5*fm.boundingRect("A").width(); } JKQTMathText::MTnode *JKQTMathText::MTsuperscriptNode::getChild() const { return this->child; } QString JKQTMathText::MTsuperscriptNode::getTypeName() const { return "MTsuperscriptNode"; } bool JKQTMathText::MTsuperscriptNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { html=html+""; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+""; return ok; } void JKQTMathText::MTsuperscriptNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; child->setDrawBoxes(draw); } JKQTMathText::MTbraceNode::MTbraceNode(JKQTMathText* _parent, const QString& openbrace, const QString& closebrace, MTnode* child, bool showRightBrace): JKQTMathText::MTnode(_parent) { this->child=child; this->openbrace=openbrace; this->closebrace=closebrace; this->showRightBrace=showRightBrace; } JKQTMathText::MTbraceNode::~MTbraceNode() { if (child!=nullptr) delete child; } void JKQTMathText::MTbraceNode::getSizeInternal(QPainter& painter, JKQTMathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const MTnodeSize* /*prevNodeSize*/) { JKQTMathText::MTenvironment ev=currentEv; child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); double bracewidth=0, braceheight=0; getBraceWidth(painter, ev, baselineHeight, overallHeight, bracewidth, braceheight); bracewidth=bracewidth/parent->getBraceShrinkFactor(); baselineHeight=/*qMin(baselineHeight, braceheight)*/ baselineHeight*parent->getBraceFactor(); overallHeight=qMax(overallHeight, braceheight)*parent->getBraceFactor(); //fm.height(); width=width+bracewidth*2.0; } double JKQTMathText::MTbraceNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) { //std::cout<<"drawing brace-node: '"<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/16.0));//fm.lineWidth(); double xnew=x+lw; QPen pold=painter.pen(); QPen p=pold; p.setWidthF(lw); p.setColor(currentEv.color); painter.setPen(p); double brace_fraction=0.85; if (openbrace=="(") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.cubicTo(xnew, (y1+y2)/2.0+fabs(y1-y2)/6.0, xnew, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } else if (openbrace=="[") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.lineTo(xnew+lw/2.0, y1); path.lineTo(xnew+lw/2.0, y2); path.lineTo(xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } else if (openbrace=="{") { QPainterPath path=makeHBracePath(0,0,cOverallHeight, bracewidth*brace_fraction); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.translate(xnew+bracewidth*(1.0-brace_fraction), y-cBaselineHeight+cOverallHeight/2.0); painter.rotate(90); painter.drawPath(path); } else if (openbrace=="_") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.lineTo(xnew, y1); path.lineTo(xnew, y2); painter.drawPath(path); } else if (openbrace=="~") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew, y1); path.lineTo(xnew, y2); path.lineTo(xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } else if (openbrace=="|") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; QLineF l(xnew+brace_fraction*bracewidth, y1, xnew+brace_fraction*bracewidth, y2); if (l.length()>0) painter.drawLine(l); painter.drawPath(path); } else if (openbrace=="#" || openbrace=="||") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; QLineF l(xnew+brace_fraction*bracewidth, y1, xnew+brace_fraction*bracewidth, y2); if (l.length()>0) painter.drawLine(l); l=QLineF(xnew+brace_fraction*bracewidth-1.5*lw, y1, xnew+brace_fraction*bracewidth-1.5*lw, y2); if (l.length()>0) painter.drawLine(l); } else if (openbrace=="<") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.lineTo(xnew, (y2+y1)/2.0); path.lineTo(xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } painter.setPen(pold); xnew= child->draw(painter, xnew+bracewidth/parent->getBraceShrinkFactor()-lw, y, currentEv)+lw; if (showRightBrace) { painter.setPen(p); if (closebrace==")") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.cubicTo(xnew+bracewidth, (y1+y2)/2.0+fabs(y1-y2)/6.0, xnew+bracewidth, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } else if (closebrace=="]") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.lineTo(xnew+bracewidth-lw/2.0, y1); path.lineTo(xnew+bracewidth-lw/2.0, y2); path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } else if (closebrace=="}") { QPainterPath path=makeHBracePath(0,0,cOverallHeight, bracewidth*brace_fraction); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.translate(xnew+bracewidth*brace_fraction, y-cBaselineHeight+cOverallHeight/2.0); painter.rotate(270); painter.drawPath(path); } else if (closebrace=="_") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.lineTo(xnew+bracewidth, y1); path.lineTo(xnew+bracewidth, y2); painter.drawPath(path); } else if (closebrace=="~") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+bracewidth, y1); path.lineTo(xnew+bracewidth, y2); path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } else if (closebrace=="|") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; QLineF l(xnew+(1.0-brace_fraction)*bracewidth, y1, xnew+(1.0-brace_fraction)*bracewidth, y2); if (l.length()>0) painter.drawLine(l); painter.drawPath(path); } else if (closebrace=="#" || closebrace=="||") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; QLineF l(xnew+(1.0-brace_fraction)*bracewidth, y1, xnew+(1.0-brace_fraction)*bracewidth, y2); if (l.length()>0) painter.drawLine(l); l=QLineF(xnew+(1.0-brace_fraction)*bracewidth+1.5*lw, y1, xnew+(1.0-brace_fraction)*bracewidth+1.5*lw, y2); if (l.length()>0) painter.drawLine(l); } else if (closebrace==">") { QPainterPath path; double y1=y+(cOverallHeight-cBaselineHeight); double y2=y-cBaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.lineTo(xnew+bracewidth, (y2+y1)/2.0); path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } painter.setPen(pold); } //qDebug()<<" ==> "<getBraceShrinkFactor()-lw; } bool JKQTMathText::MTbraceNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { QString ob=openbrace; QString cb=closebrace; if (ob=="<") ob="⟨"; else if (ob=="_") ob="⌊"; else if (ob=="~") ob="⌈"; else if (ob=="||" || ob=="#") ob="||"; if (cb=="<") cb="⟩"; else if (cb=="_") cb="⌋"; else if (cb=="~") cb="⌉"; else if (cb=="||" || cb=="#") cb="||"; html=html+ob; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+cb; return ok; } void JKQTMathText::MTbraceNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; child->setDrawBoxes(draw); } QString JKQTMathText::MTbraceNode::getTypeName() const { return QLatin1String("MTbraceNode(")+openbrace+" "+closebrace+")"; } void JKQTMathText::MTbraceNode::getBraceWidth(QPainter &/*painter*/, JKQTMathText::MTenvironment ev, double /*baselineHeight*/, double overallHeight, double &bracewidth, double &braceheight) { /*QFont evf=ev.getFont(parent); if (ev.insideMath) evf.setItalic(false); ev.italic=false; while (ev.fontSize<10*parent->getFontSize()) { const QFontMetricsF fme(evf, painter.device()); if (fme.ascent()>overallHeight) break; ev.fontSize+=0.5; evf.setPointSizeF(ev.fontSize); } ev.fontSize=ev.fontSize*parent->getBraceFactor(); evf.setPointSizeF(ev.fontSize); QFontMetricsF fm(evf, painter.device()); QString bc="_X"; bracewidth=fm.width("I")*parent->getBraceShrinkFactor(); braceheight=parent->getTBR(evf, bc, painter.device()).height();*/ double lw=qMax(0.25,ceil(ev.fontSize/12.0)); braceheight=overallHeight*parent->getBraceFactor(); bracewidth=0.6*pow(braceheight, 0.6); if (openbrace=="{" || closebrace=="}") bracewidth=qMax(bracewidth, lw*3.5); } JKQTMathText::MTlistNode::MTlistNode(JKQTMathText* _parent): JKQTMathText::MTnode(_parent) { nodes.clear(); // these operations cause sub/sup script to be typeset over/under the operator, not right besides! subsupOperations<<"sum"<<"prod"<<"coprod" <<"bigcap"<<"bigcup"<<"bigvee"<<"bighat" <<"int"<<"iint"<<"iiint"<<"oint"<<"oiint"<<"oiiint" <<"mod"<<"median"<<"max"<<"min"<<"argmax"<<"argmin"<<"sup"<<"inf" <<"liminf"<<"limsup"<<"lim"<<"max"<<"min"; } JKQTMathText::MTlistNode::~MTlistNode() { for (int i=0; igetTightBoundingRect(currentEv.getFont(parent), "M", painter.device()); double xnew=0; bool wasBrace=false; for (int i=0; i0 && wasBrace) { nodes[i-1]->getSize(painter, currentEv, prevNodeSize.width, prevNodeSize.baselineHeight, prevNodeSize.overallHeight, prevNodeSize.strikeoutPos); prevNodeSizePtr=&prevNodeSize; } bool doDraw=true; MTsymbolNode* smb=dynamic_cast(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])) { if (i+1(nodes[i+1])) { // is this subscript? double w1, w2, oh, bh, sp; nodes[i]->getSize(painter, currentEv, w1, bh, oh, sp, prevNodeSizePtr); if (bh>baselineHeight) { overallHeight=overallHeight+bh-baselineHeight; baselineHeight=bh; strikeoutPos=sp; } if (baselineHeight+oh-bh>overallHeight) { overallHeight=baselineHeight+oh-bh; strikeoutPos=sp; } i++; nodes[i]->getSize(painter, currentEv, w2, bh, oh, sp, prevNodeSizePtr); //qDebug()<<"super_sub: sub: "<getTypeName()<<" w2="<getOperatorsubsuperSizeFactor(); double w1=0, w2=0, w3=0; double oh1=0, oh2=0, oh3=0; double bh1=0, bh2=0, bh3=0; double sp1=0, sp2=0, sp3=0; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp1); //qDebug()<<"sub_super: node: "<getTypeName()<<" w1="<getTypeName()<<" w2="<getTypeName()<<" w3="<getOperatorsubsuperSizeFactor(); double w1=0, w2=0; double oh1=0, oh2=0; double bh1=0, bh2=0; double sp1=0, sp2=0;//, sp3=0; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp1); subn->getChild()->getSize(painter, ev, w2, bh2, oh2, sp2); //double d1=oh1-bh1; //double d2=oh2-bh2; double oh=oh1+oh2; double sh=oh1-bh1+oh2*1.1; if (oh>overallHeight) overallHeight=oh; if (bh1>baselineHeight) baselineHeight=bh1; if (sh>overallHeight-baselineHeight) { overallHeight=baselineHeight+sh; } double w=qMax(w1, w2)+fm.boundingRect(' ').width(); i++; doDraw=false; xnew+=w; //qDebug()<<"### subsupop: sub overallHeight="<0 && wasBrace) { nodes[i-1]->getSize(painter, currentEv, prevNodeSize.width, prevNodeSize.baselineHeight, prevNodeSize.overallHeight, prevNodeSize.strikeoutPos); prevNodeSizePtr=&prevNodeSize; } MTsymbolNode* smb=dynamic_cast(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])) { if (i+1(nodes[i+1])) { // is this subscript? //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccOverallHeight-ccBaselineHeight)-4,8,8); double xnew1=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr); i++; //painter.setPen(QPen("magenta")); //painter.drawEllipse(xnew-4,ynew-4,8,8); double xnew2=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr); //i++; xnew=qMax(xnew1, xnew2); doDraw=false; } } } else if (dynamic_cast(nodes[i])) { if (i+1(nodes[i+1])) { // is this subscript? //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccOverallHeight-ccBaselineHeight)-4,8,8); double xnew1=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr); i++; //painter.setPen(QPen("magenta")); //painter.drawEllipse(xnew-4,ynew-4,8,8); double xnew2=nodes[i]->draw(painter, xnew, ynew, currentEv, prevNodeSizePtr); //i++; xnew=qMax(xnew1, xnew2); doDraw=false; } } } else { if (smb) { QString s=smb->getSymbolName(); if (subsupOperations.contains(s)) { MTsubscriptNode* subn=nullptr; if (i+1(nodes[i+1]); MTsuperscriptNode* supn=nullptr; if (i+2(nodes[i+2]); //std::cout<<"symbol ='"<getOperatorsubsuperSizeFactor(); double w1=0, w2=0, w3=0; double oh1=0, oh2=0, oh3=0; double bh1=0, bh2=0, bh3=0, sp; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp); subn->getChild()->getSize(painter, ev, w2, bh2, oh2, sp); supn->getChild()->getSize(painter, ev, w3, bh3, oh3, sp); double d1=oh1-bh1; //double d2=oh2-bh2; double d3=oh3-bh3; double w=qMax(qMax(w1, w2), w3); //double xnew1= double xn1=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv); i++; //double xnew2= double xn2=subn->getChild()->draw(painter, xnew+(w-w2)/2.0, ynew+bh2+d1, ev); i++; //double xnew3= double xn3=supn->getChild()->draw(painter, xnew+(w-w3)/2.0, ynew-bh1-d3-fm.xHeight()/4.0, ev); doDraw=false; xnew=qMax(qMax(xn1, xn2), xn3)+fm.boundingRect(' ').width(); } else if (subn) { // is this subscript and not superscript? MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor(); double w1=0, w2=0; double oh1=0, oh2=0; double bh1=0, bh2=0, sp=0; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp); subn->getChild()->getSize(painter, ev, w2, bh2, oh2, sp); double d1=oh1-bh1; //double d2=oh2-bh2; double w=qMax(w1, w2); //double xnew1= double xn2=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv); i++; //double xnew2= double xn1=subn->getChild()->draw(painter, xnew+(w-w2)/2.0, ynew+bh2+d1, ev)+fm.boundingRect(' ').width(); doDraw=false; //xnew+=w; xnew=qMax(xn1, xn2); } else if (supn) { // is this subscript and superscript? MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->getOperatorsubsuperSizeFactor(); double w1=0, w3=0; double oh1=0, oh3=0; double bh1=0, bh3=0, sp; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp); supn->getChild()->getSize(painter, ev, w3, bh3, oh3, sp); //double d1=oh1-bh1; //double d2=oh2-bh2; double d3=oh3-bh3; double w=qMax(w1, w3); //double xnew1= double xn1=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv); i++; //double xnew3= double xn3=supn->getChild()->draw(painter, xnew+(w-w3)/2.0, ynew-bh1-d3-fm.xHeight()/4.0, ev); doDraw=false; xnew=qMax(xn1, xn3)+fm.boundingRect(' ').width(); } } } } if (idraw(painter, xnew, ynew, currentEv, prevNodeSizePtr); } wasBrace=dynamic_cast(nodes[i]); } return xnew; } bool JKQTMathText::MTlistNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { bool ok=true; for (int i=0; itoHtml(h, currentEv, defaultEv); html=html+h; } return ok; } void JKQTMathText::MTlistNode::setDrawBoxes(bool draw) { this->drawBoxes=draw; for (int i=0; isetDrawBoxes(draw); } } QList JKQTMathText::MTlistNode::getNodes() const { return this->nodes; } JKQTMathText::MTsymbolNode::MTsymbolNode(JKQTMathText* _parent, const QString& name, bool _addWhitespace): JKQTMathText::MTnode(_parent), symbolName(name), addWhitespace(_addWhitespace) { } JKQTMathText::MTsymbolNode::~MTsymbolNode() = default; QString JKQTMathText::MTsymbolNode::getTypeName() const { return QLatin1String("MTsymbolNode(")+symbolName+QLatin1String(")"); } bool JKQTMathText::MTsymbolNode::getWinSymbolProp(JKQTMathText::MTsymbolNode::SymbolProps& props, const QString &n, const MTenvironment& currentEv, double mathFontFactor) const { auto fnt=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Text); auto fntSym=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Symbols); //qDebug()<<" +--- getWinSymbolProp("< winSymbolSymbol; if (winSymbolSymbol.isEmpty()) { winSymbolSymbol.insert("leftrightarrow", QChar(0xAB)); winSymbolSymbol.insert("leftarrow", QChar(0xAC)); winSymbolSymbol.insert("rightarrow", QChar(0xAE)); winSymbolSymbol.insert("to", QChar(0xAE)); winSymbolSymbol.insert("uparrow", QChar(0xAD)); winSymbolSymbol.insert("downarrow", QChar(0xAF)); winSymbolSymbol.insert("Leftrightarrow", QChar(0xDB)); winSymbolSymbol.insert("iff", QChar(0xDB)); winSymbolSymbol.insert("Leftarrow", QChar(0xDC)); winSymbolSymbol.insert("Rightarrow", QChar(0xDE)); winSymbolSymbol.insert("Uparrow", QChar(0xDD)); winSymbolSymbol.insert("Downarrow", QChar(0xFF)); winSymbolSymbol.insert("pm", QChar(0xB1)); winSymbolSymbol.insert("leq", QChar(0xA3)); winSymbolSymbol.insert("geq", QChar(0xB3)); winSymbolSymbol.insert("le", QChar(0xA3)); winSymbolSymbol.insert("ge", QChar(0xB3)); winSymbolSymbol.insert("times", QChar(0xB4)); winSymbolSymbol.insert("propto", QChar(0xB5)); winSymbolSymbol.insert("partial", QChar(0xB6)); winSymbolSymbol.insert("bullet", QChar(0xB7)); winSymbolSymbol.insert("neq", QChar(0xB9)); winSymbolSymbol.insert("ne", QChar(0xB9)); winSymbolSymbol.insert("equiv", QChar(0xBA)); winSymbolSymbol.insert("approx", QChar(0xBB)); winSymbolSymbol.insert("ellipsis", QChar(0xBC)); winSymbolSymbol.insert("Im", QChar(0xC1)); winSymbolSymbol.insert("Re", QChar(0xC2)); winSymbolSymbol.insert("otimes", QChar(0xC4)); winSymbolSymbol.insert("oplus", QChar(0xC5)); winSymbolSymbol.insert("oslash", QChar(0xC6)); winSymbolSymbol.insert("cap", QChar(0xC7)); winSymbolSymbol.insert("land", QChar(0xC7)); winSymbolSymbol.insert("cup", QChar(0xC8)); winSymbolSymbol.insert("lor", QChar(0xC8)); winSymbolSymbol.insert("supset", QChar(0xC9)); winSymbolSymbol.insert("supseteq", QChar(0xCA)); winSymbolSymbol.insert("supsetnot", QChar(0xCB)); winSymbolSymbol.insert("subset", QChar(0xCC)); winSymbolSymbol.insert("subseteq", QChar(0xCD)); winSymbolSymbol.insert("in", QChar(0xCE)); winSymbolSymbol.insert("notin", QChar(0xCF)); winSymbolSymbol.insert("angle", QChar(0xD0)); winSymbolSymbol.insert("nabla", QChar(0xD1)); winSymbolSymbol.insert("copyright", QChar(0xD3)); winSymbolSymbol.insert("registered", QChar(0xD2)); winSymbolSymbol.insert("circledR", QChar(0xD2)); winSymbolSymbol.insert("trademark", QChar(0xD4)); winSymbolSymbol.insert("textregistered", QChar(0xD4)); winSymbolSymbol.insert("cdot", QChar(0xD7)); winSymbolSymbol.insert("neg", QChar(0xD8)); winSymbolSymbol.insert("wedge", QChar(0xD9)); winSymbolSymbol.insert("vee", QChar(0xDA)); winSymbolSymbol.insert("diamond", QChar(0xE0)); winSymbolSymbol.insert("langle", QChar(0xE1)); winSymbolSymbol.insert("rangle", QChar(0xF1)); winSymbolSymbol.insert("forall", QChar(0x22)); winSymbolSymbol.insert("exists", QChar(0x24)); winSymbolSymbol.insert("cong", QChar(0x40)); winSymbolSymbol.insert("bot", QChar(0x5E)); winSymbolSymbol.insert("ll", "<<"); winSymbolSymbol.insert("gg", ">>"); winSymbolSymbol.insert("Alef", QChar(0xC0)); winSymbolSymbol.insert("alef", QChar(0xC0)); winSymbolSymbol.insert("tilde", "~"); winSymbolSymbol.insert("emptyset", QChar(0xC6)); winSymbolSymbol.insert("varnothing", QChar(0xC6)); winSymbolSymbol.insert("lceil", QChar(0xE9)); winSymbolSymbol.insert("rceil", QChar(0xF9)); winSymbolSymbol.insert("lfloor", QChar(0xEB)); winSymbolSymbol.insert("rfloor", QChar(0xFB)); winSymbolSymbol.insert("subsetnot", QChar(0xCB)); winSymbolSymbol.insert("DC", "="); winSymbolSymbol.insert("mid", "|"); winSymbolSymbol.insert("cdots", QString(3, QChar(0xD7))); winSymbolSymbol.insert("dots", QChar(0xDC)); winSymbolSymbol.insert("ldots", QChar(0xDC)); winSymbolSymbol.insert("cent", "c"); winSymbolSymbol.insert("sim", QChar(0x7E)); winSymbolSymbol.insert("infty", QChar(0xA5)); } QHash::iterator itsymbol = winSymbolSymbol.find(n); if (itsymbol!=winSymbolSymbol.end()) { props.symbol = itsymbol.value(); } else if (n == "int") { props.symbol = QChar(0xF2); props.fontFactor = mathFontFactor; props.yfactor = +0.1; } else if (n == "bbC") { props.symbol = "C"; props.bold = +1; props.italic = -1; } else if (n == "bbH") { props.symbol = "H"; props.bold = +1; props.italic = -1; } else if (n == "bbN") { props.symbol = "N"; props.bold = +1; props.italic = -1; } else if (n == "bbP") { props.symbol = "P"; props.bold = +1; props.italic = -1; } else if (n == "bbQ") { props.symbol = "Q"; props.bold = +1; props.italic = -1; } else if (n == "bbR") { props.symbol = "R"; props.bold = +1; props.italic = -1; } else if (n == "bbZ") { props.symbol = "Z"; props.bold = +1; props.italic = -1; } else if (n == "iint") { props.symbol = QString(2, QChar(0xF2)); props.fontFactor = mathFontFactor; props.yfactor = +0.1; } else if (n == "iiint") { props.symbol = QString(3, QChar(0xF2)); props.fontFactor = mathFontFactor; props.yfactor = +0.1; } else if (n == "bigcap") { props.symbol = QChar(0xC7); props.fontFactor = 2; } else if (n == "bigcup") { props.symbol = QChar(0xC8); props.fontFactor = 2; } else if (n == "bigvee") { props.symbol = QChar(0xDA); props.fontFactor = 2; } else if (n == "bighat") { props.symbol = QChar(0xD9); props.fontFactor = 2; } else { // here are text mode symbols, i.e. bold and italic won't be touched props.bold = -1; props.italic = -1; props.font = fnt.first; if (n == "_") { props.symbol = "_"; props.bold = 0; props.italic = 0; } else if (n == "}") { props.symbol = "}"; } else if (n == "{") { props.symbol = "{"; } else if (n == "hbar") { props.symbol = "h"; props.bold = 0; props.italic = 0; props.drawBar = true; } else if (n == "euro") { props.symbol = ""; props.bold = 0; props.italic = 0; } else if (n == "cent") { props.symbol = QChar(0xA2); props.bold = 0; props.italic = 0; } else if (n == "pound") { props.symbol = QChar(0xA3); props.bold = 0; props.italic = 0; } else if (n == "yen") { props.symbol = QChar(0xA5); props.bold = 0; props.italic = 0; } else if (n == "div") { props.symbol = QChar(0xF7); props.bold = 0; props.italic = 0; } else if (n == "backslash") { props.symbol = "\\"; props.bold = 0; props.italic = 0; } //else if (n=="|") { symbol="||"; bold=0; italic=0; } else if (n == "$") { props.symbol = "$"; props.bold = 0; props.italic = 0; } else if (n == "%") { props.symbol = "%"; props.bold = 0; props.italic = 0; } else if (n == "&") { props.symbol = "&"; props.bold = 0; props.italic = 0; } else if (n == "#") { props.symbol = "#"; props.bold = 0; props.italic = 0; } else if (n == "ast") { props.symbol = "*"; props.bold = 0; props.italic = 0; } else if (n == "glq") { props.symbol = "'"; props.bold = 0; props.italic = 0; } else if (n == "grq") { props.symbol = "'"; props.bold = 0; props.italic = 0; } else if (n == "glqq") { props.symbol = "\""; props.bold = 0; props.italic = 0; } else if (n == "grqq") { props.symbol = "\""; props.bold = 0; props.italic = 0; } else if (n == "flq") { props.symbol = "<"; props.bold = 0; props.italic = 0; } else if (n == "frq") { props.symbol = ">"; props.bold = 0; props.italic = 0; } else if (n == "flqq") { props.symbol = ""; props.bold = 0; props.italic = 0; } else if (n == "frqq") { props.symbol = ""; props.bold = 0; props.italic = 0; } else { return false; } } return true; } bool JKQTMathText::MTsymbolNode::getGreekSymbolProp(JKQTMathText::MTsymbolNode::SymbolProps& props, const QString &n, const MTenvironment& currentEv, double mathFontFactor) const { auto fnt=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Text); auto fntGreek=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Greek); //qDebug()<<" +--- getGreekSymbolProp("< winSymbolGreek; if (winSymbolGreek.isEmpty()) { winSymbolGreek.insert("alpha", "a"); winSymbolGreek.insert("beta", "b"); winSymbolGreek.insert("gamma", "g"); winSymbolGreek.insert("delta", "d"); winSymbolGreek.insert("epsilon", "e"); winSymbolGreek.insert("varepsilon", "e"); winSymbolGreek.insert("zeta", "z"); winSymbolGreek.insert("eta", "h"); winSymbolGreek.insert("theta", "q"); winSymbolGreek.insert("vartheta", "J"); winSymbolGreek.insert("iota", "i"); winSymbolGreek.insert("kappa", "k"); winSymbolGreek.insert("lambda", "l"); winSymbolGreek.insert("mu", "m"); winSymbolGreek.insert("nu", "n"); winSymbolGreek.insert("xi", "x"); winSymbolGreek.insert("pi", "p"); winSymbolGreek.insert("varpi", "v"); winSymbolGreek.insert("rho", "r"); winSymbolGreek.insert("sigma", "s"); winSymbolGreek.insert("varsigma", "V"); winSymbolGreek.insert("tau", "t"); winSymbolGreek.insert("upsilon", "u"); winSymbolGreek.insert("phi", "f"); winSymbolGreek.insert("varphi", "j"); winSymbolGreek.insert("chi", "c"); winSymbolGreek.insert("psi", "y"); winSymbolGreek.insert("omega", "w"); winSymbolGreek.insert("Gamma", "G"); winSymbolGreek.insert("Delta", "D"); winSymbolGreek.insert("Theta", "Q"); winSymbolGreek.insert("Lambda", "L"); winSymbolGreek.insert("Omega", "W"); winSymbolGreek.insert("Xi", "X"); winSymbolGreek.insert("Pi", "P"); winSymbolGreek.insert("Sigma", "S"); winSymbolGreek.insert("Upsilon", ""); winSymbolGreek.insert("Phi", "F"); winSymbolGreek.insert("Psi", "Y"); } static QHash unicodeGreek; if (unicodeGreek.isEmpty()) { unicodeGreek.insert("alpha", QChar(0x3B1)); unicodeGreek.insert("beta", QChar(0x3B2)); unicodeGreek.insert("gamma", QChar(0x3B3)); unicodeGreek.insert("delta", QChar(0x3B4)); unicodeGreek.insert("epsilon", QChar(0x3B5)); unicodeGreek.insert("varepsilon", QChar(0x3B5)); unicodeGreek.insert("zeta", QChar(0x3B6)); unicodeGreek.insert("eta", QChar(0x3B7)); unicodeGreek.insert("theta", QChar(0x3B8)); unicodeGreek.insert("vartheta", QChar(0x3D1)); unicodeGreek.insert("iota", QChar(0x3B9)); unicodeGreek.insert("kappa", QChar(0x3BA)); unicodeGreek.insert("lambda", QChar(0x3BB)); unicodeGreek.insert("mu", QChar(0x3BC)); unicodeGreek.insert("nu", QChar(0x3BD)); unicodeGreek.insert("xi", QChar(0x3BE)); unicodeGreek.insert("pi", QChar(0x3C0)); unicodeGreek.insert("varpi", QChar(0x3D6)); unicodeGreek.insert("rho", QChar(0x3C1)); unicodeGreek.insert("varrho", QChar(0x3F1)); unicodeGreek.insert("sigma", QChar(0x3C3)); unicodeGreek.insert("varsigma", QChar(0x3C2)); unicodeGreek.insert("tau", QChar(0x3C4)); unicodeGreek.insert("upsilon", QChar(0x3C5)); unicodeGreek.insert("phi", QChar(0x3D5)); unicodeGreek.insert("varphi", QChar(0x3C6)); unicodeGreek.insert("chi", QChar(0x3C7)); unicodeGreek.insert("psi", QChar(0x3C8)); unicodeGreek.insert("omega", QChar(0x3C9)); unicodeGreek.insert("Omega", QChar(0x3A9)); unicodeGreek.insert("Gamma", QChar(0x393)); unicodeGreek.insert("Delta", QChar(0x394)); unicodeGreek.insert("Theta", QChar(0x398)); unicodeGreek.insert("Lambda", QChar(0x39B)); unicodeGreek.insert("Xi", QChar(0x39E)); unicodeGreek.insert("Pi", QChar(0x3A0)); unicodeGreek.insert("prod", QChar(0x3A0)); unicodeGreek.insert("Sigma", QChar(0x3A3)); unicodeGreek.insert("sum", QChar(0x3A3)); unicodeGreek.insert("Upsilon", QChar(0x3A5)); unicodeGreek.insert("Phi", QChar(0x3A6)); unicodeGreek.insert("Psi", QChar(0x3A8)); } //qDebug()<<"##SEARCHING "<::iterator itgreek = unicodeGreek.find(n); if (itgreek!=unicodeGreek.end()) { //qDebug()<<"##SEARCHING "<::iterator itgreek = unicodeGreek.find(n); if (itgreek!=unicodeGreek.end()) { //qDebug()<<"##SEARCHING "<::iterator itgreek = winSymbolGreek.find(n); if (itgreek!=winSymbolGreek.end()) { props.symbol = itgreek.value(); //qDebug()<<"##SEARCHING "< unicodeBaseSymbol; if (unicodeBaseSymbol.isEmpty()) { unicodeBaseSymbol.insert("diamond", QChar(0xE0)); unicodeBaseSymbol.insert("infty", QChar(0x221E)); unicodeBaseSymbol.insert("partial", QChar(0x2202)); unicodeBaseSymbol.insert("times", QChar(0x2A2F)); unicodeBaseSymbol.insert("bullet", QChar(0x2219)); unicodeBaseSymbol.insert("copyright", QChar(0x00A9)); unicodeBaseSymbol.insert("registered", QChar(0x00AE)); unicodeBaseSymbol.insert("circledR", QChar(0x00AE)); unicodeBaseSymbol.insert("trademark", QChar(0x2122)); unicodeBaseSymbol.insert("textregistered", QChar(0x2122)); unicodeBaseSymbol.insert("cdot", QChar(0x00B7)); unicodeBaseSymbol.insert("pm", QChar(0x00B1)); unicodeBaseSymbol.insert("leq", QChar(0x2264)); unicodeBaseSymbol.insert("geq", QChar(0x2265)); unicodeBaseSymbol.insert("le", QChar(0x2264)); unicodeBaseSymbol.insert("ge", QChar(0x2265)); unicodeBaseSymbol.insert("hbar", QChar(0x210F)); unicodeBaseSymbol.insert("EUR", QChar(0x20AC)); unicodeBaseSymbol.insert("euro", QChar(0x20AC)); unicodeBaseSymbol.insert("circ", QChar(0x2218)); unicodeBaseSymbol.insert("cent", QChar(0x00A2)); unicodeBaseSymbol.insert("pound", QChar(0x00A3)); unicodeBaseSymbol.insert("yen", QChar(0x00A5)); unicodeBaseSymbol.insert("dollar", QChar(0x0024)); unicodeBaseSymbol.insert("neq", QChar(0x2260)); unicodeBaseSymbol.insert("lnot", QChar(0x2260)); unicodeBaseSymbol.insert("Angstrom", QChar(0x00AC)); unicodeBaseSymbol.insert("co", QChar(0x2105)); unicodeBaseSymbol.insert("No", QChar(0x2116)); unicodeBaseSymbol.insert("Ohm", QChar(0x2126)); unicodeBaseSymbol.insert("ohm", QChar(0x2126)); unicodeBaseSymbol.insert("tcohm", QChar(0x2126)); unicodeBaseSymbol.insert("partial", QChar(0x2202)); unicodeBaseSymbol.insert("cdots", QString(QChar(0x00B7)) + QString(QChar(0x00B7)) + QString(QChar(0x00B7))); unicodeBaseSymbol.insert("approx", QChar(0x2248)); unicodeBaseSymbol.insert("Angstroem", QChar(0x212B)); } QHash::iterator itbasesymbol = unicodeBaseSymbol.find(n); if (itbasesymbol!=unicodeBaseSymbol.end()) { props.symbol = itbasesymbol.value(); //qDebug()<<"### found "< unicodeSymbol; if (unicodeSymbol.isEmpty()) { unicodeSymbol.insert("leftrightarrow", QChar(0x2194)); unicodeSymbol.insert("leftarrow", QChar(0x2190)); unicodeSymbol.insert("rightarrow", QChar(0x2192)); unicodeSymbol.insert("to", QChar(0x2192)); unicodeSymbol.insert("uparrow", QChar(0x2191)); unicodeSymbol.insert("downarrow", QChar(0x2193)); unicodeSymbol.insert("updownarrow", QChar(0x2195)); unicodeSymbol.insert("Leftrightarrow", QChar(0x21D4)); unicodeSymbol.insert("iff", QChar(0x21D4)); unicodeSymbol.insert("Leftarrow", QChar(0x21D0)); unicodeSymbol.insert("Rightarrow", QChar(0x21D2)); unicodeSymbol.insert("Uparrow", QChar(0x21D1)); unicodeSymbol.insert("Downarrow", QChar(0x21D3)); unicodeSymbol.insert("Updownarrow", QChar(0x21D5)); unicodeSymbol.insert("mp", QChar(0x2213)); unicodeSymbol.insert("ll", QChar(0x226A)); unicodeSymbol.insert("gg", QChar(0x226B)); unicodeSymbol.insert("Alef", QChar(0x2135)); unicodeSymbol.insert("Aleph", QChar(0x2135)); unicodeSymbol.insert("Bet", QChar(0x2136)); unicodeSymbol.insert("Beth", QChar(0x2136)); unicodeSymbol.insert("Gimel", QChar(0x2137)); unicodeSymbol.insert("Dalet", QChar(0x2138)); unicodeSymbol.insert("alef", QChar(0x2135)); unicodeSymbol.insert("aleph", QChar(0x2135)); unicodeSymbol.insert("bet", QChar(0x2136)); unicodeSymbol.insert("beth", QChar(0x2136)); unicodeSymbol.insert("gimel", QChar(0x2137)); unicodeSymbol.insert("dalet", QChar(0x2138)); unicodeSymbol.insert("nexists", QChar(0x2204)); unicodeSymbol.insert("ni", QChar(0x220B)); unicodeSymbol.insert("notni", QChar(0x220C)); unicodeSymbol.insert("tilde", QChar(0x223C)); unicodeSymbol.insert("sim", QChar(0x223C)); unicodeSymbol.insert("emptyset", QChar(0x2300)); unicodeSymbol.insert("varnothing", QChar(0x2300)); unicodeSymbol.insert("odot", QChar(0x2299)); unicodeSymbol.insert("ominus", QChar(0x2296)); unicodeSymbol.insert("lceil", QChar(0x2308)); unicodeSymbol.insert("rceil", QChar(0x2309)); unicodeSymbol.insert("lfloor", QChar(0x230A)); unicodeSymbol.insert("rfloor", QChar(0x230B)); unicodeSymbol.insert("subsetnot", QChar(0x2284)); unicodeSymbol.insert("DC", QChar(0x2393)); unicodeSymbol.insert("bot", QChar(0x22A4)); unicodeSymbol.insert("perp", QChar(0x22A5)); unicodeSymbol.insert("sqcap", QChar(0x2293)); unicodeSymbol.insert("sqcup", QChar(0x2294)); unicodeSymbol.insert("triangle", QChar(0x2206)); unicodeSymbol.insert("square", QChar(0x25A1)); unicodeSymbol.insert("setminus", QChar(0x2216)); unicodeSymbol.insert("mid", QChar(0x2223)); unicodeSymbol.insert("nmid", QChar(0x2224)); unicodeSymbol.insert("vdots", QChar(0x22EE)); unicodeSymbol.insert("iddots", QChar(0x22F0)); unicodeSymbol.insert("ddots", QChar(0x22F1)); unicodeSymbol.insert("perthousand", QChar(0x2030)); unicodeSymbol.insert("leftharpoonup", QChar(0x21BC)); unicodeSymbol.insert("rightharpoonup", QChar(0x21C0)); unicodeSymbol.insert("upharpoonleft", QChar(0x21BF)); unicodeSymbol.insert("downharpoonleft", QChar(0x21C3)); unicodeSymbol.insert("leftrightharpoon", QChar(0x21CB)); unicodeSymbol.insert("rightleftharpoon", QChar(0x21CC)); unicodeSymbol.insert("leftharpoondown", QChar(0x21BD)); unicodeSymbol.insert("rightharpoondown", QChar(0x21C1)); unicodeSymbol.insert("upharpoonright", QChar(0x21BE)); unicodeSymbol.insert("downharpoonright", QChar(0x21C2)); unicodeSymbol.insert("nwarrow", QChar(0x2196)); unicodeSymbol.insert("nearrow", QChar(0x2197)); unicodeSymbol.insert("searrow", QChar(0x2198)); unicodeSymbol.insert("swarrow", QChar(0x2199)); unicodeSymbol.insert("mapsto", QChar(0x21A6)); unicodeSymbol.insert("div", QChar(0x00F7)); unicodeSymbol.insert("multimap", QChar(0x22B8)); unicodeSymbol.insert("maporiginal", QChar(0x22B6)); unicodeSymbol.insert("mapimage", QChar(0x22B7)); unicodeSymbol.insert("benzene", QChar(0x232C)); unicodeSymbol.insert("propto", QChar(0x221D)); unicodeSymbol.insert("ne", QChar(0x2260)); unicodeSymbol.insert("equiv", QChar(0x2261)); unicodeSymbol.insert("ellipsis", QChar(0x2026)); unicodeSymbol.insert("Im", QChar(0x2111)); unicodeSymbol.insert("Re", QChar(0x211C)); unicodeSymbol.insert("otimes", QChar(0x2297)); unicodeSymbol.insert("oplus", QChar(0x2295)); unicodeSymbol.insert("oslash", QChar(0x2298)); unicodeSymbol.insert("cap", QChar(0x2229)); unicodeSymbol.insert("land", QChar(0x2229)); unicodeSymbol.insert("cup", QChar(0x222A)); unicodeSymbol.insert("lor", QChar(0x222A)); unicodeSymbol.insert("supset", QChar(0x2283)); unicodeSymbol.insert("supseteq", QChar(0x2286)); unicodeSymbol.insert("supsetnot", QChar(0x2285)); unicodeSymbol.insert("subset", QChar(0x2282)); unicodeSymbol.insert("subseteq", QChar(0x2286)); unicodeSymbol.insert("in", QChar(0x2208)); unicodeSymbol.insert("notin", QChar(0x2209)); unicodeSymbol.insert("angle", QChar(0x2220)); unicodeSymbol.insert("measuredangle", QChar(0x2221)); unicodeSymbol.insert("sphericalangle", QChar(0x2222)); unicodeSymbol.insert("rightangle", QChar(0x221F)); unicodeSymbol.insert("nabla", QChar(0x2207)); unicodeSymbol.insert("parallel", QChar(0x2225)); unicodeSymbol.insert("nparallel", QChar(0x2226)); unicodeSymbol.insert("neg", QChar(0x00AC)); unicodeSymbol.insert("wedge", QChar(0x2227)); unicodeSymbol.insert("vee", QChar(0x2228)); unicodeSymbol.insert("langle", QChar(0x2329)); unicodeSymbol.insert("rangle", QChar(0x232A)); unicodeSymbol.insert("forall", QChar(0x2200)); unicodeSymbol.insert("exists", QChar(0x2203)); unicodeSymbol.insert("bot", QChar(0x22A5)); unicodeSymbol.insert("geqq", QChar(0x2267)); unicodeSymbol.insert("leqq", QChar(0x2266)); unicodeSymbol.insert("prec", QChar(0x227A)); unicodeSymbol.insert("succ", QChar(0x227B)); unicodeSymbol.insert("vartriangleleft", QChar(0x22B2)); unicodeSymbol.insert("cong", QChar(0x2245)); unicodeSymbol.insert("simeq", QChar(0x2243)); unicodeSymbol.insert("therefore", QChar(0x2234)); unicodeSymbol.insert("because", QChar(0x2235)); unicodeSymbol.insert("lightning", QChar(0x21AF)); unicodeSymbol.insert("blacksquare", QChar(0x220E)); unicodeSymbol.insert("Box", QChar(0x25A1)); unicodeSymbol.insert("celsius", QChar(0x2103)); unicodeSymbol.insert("AC", QChar(0x223F)); unicodeSymbol.insert("frown", QChar(0x2322)); unicodeSymbol.insert("smile", QChar(0x2323)); unicodeSymbol.insert("smiley", QChar(0x233A)); unicodeSymbol.insert("blacksmiley", QChar(0x233B)); unicodeSymbol.insert("frownie", QChar(0x2639)); unicodeSymbol.insert("varhexagonlrbonds", QChar(0x232C)); unicodeSymbol.insert("hexagon", QChar(0x2394)); unicodeSymbol.insert("varcarriagereturn", QChar(0x23CE)); unicodeSymbol.insert("benzenr", QChar(0x23E3)); unicodeSymbol.insert("trapezium", QChar(0x23E2)); unicodeSymbol.insert("female", QChar(0x2640)); unicodeSymbol.insert("male", QChar(0x2642)); unicodeSymbol.insert("accurrent", QChar(0x23E6)); } QHash::iterator itsymbol = unicodeSymbol.find(n); if (itsymbol!=unicodeSymbol.end()) { props.symbol = itsymbol.value(); } else if (n == "sum") { props.symbol = QChar(0x2211); props.heightIsAscent = true; props.exactAscent = true; } else if (n == "prod") { props.symbol = QChar(0x220F); props.heightIsAscent = true; props.exactAscent = true; } else if (n == "bbC") { props.symbol = QChar(0x2102); props.italic = -1; } else if (n == "bbH") { props.symbol = QChar(0x210D); props.italic = -1; } else if (n == "bbN") { props.symbol = QChar(0x2115); props.italic = -1; } else if (n == "bbP") { props.symbol = QChar(0x2119); props.italic = -1; } else if (n == "bbQ") { props.symbol = QChar(0x211A); props.italic = -1; } else if (n == "bbR") { props.symbol = QChar(0x211D); props.italic = -1; } else if (n == "bbZ") { props.symbol = QChar(0x2124); props.italic = -1; } else if (n == "iint") { props.symbol = QChar(0x222C); props.fontFactor = mathFontFactor; /*yfactor=+0.1;*/ props.heightIsAscent = true; props.exactAscent = true; } else if (n == "iiint") { props.symbol = QChar(0x222D); props.fontFactor = mathFontFactor; /*yfactor=+0.1;*/ props.heightIsAscent = true; props.exactAscent = true; } else if (n == "oint") { props.symbol = QChar(0x222E); props.fontFactor = mathFontFactor; /*yfactor=+0.1;*/ props.heightIsAscent = true; props.exactAscent = true; } else if (n == "oiint") { props.symbol = QChar(0x222F); props.fontFactor = mathFontFactor; /*yfactor=+0.1;*/ props.heightIsAscent = true; props.exactAscent = true; } else if (n == "oiiint") { props.symbol = QChar(0x2230); props.fontFactor = mathFontFactor; /*yfactor=+0.1;*/ props.heightIsAscent = true; props.exactAscent = true; } else if (n == "coprod") { props.symbol = QChar(0x2210); props.heightIsAscent = true; props.exactAscent = true; } else if (n == "bigcap") { props.symbol = QChar(0x22C2); props.heightIsAscent = true; props.exactAscent = true; props.heightIsAscent = true; props.exactAscent = true; } else if (n == "bigcup") { props.symbol = QChar(0x22C3); props.heightIsAscent = true; props.exactAscent = true; props.heightIsAscent = true; props.exactAscent = true; } else if (n == "bigvee") { props.symbol = QChar(0x22C1); props.heightIsAscent = true; props.exactAscent = true; props.heightIsAscent = true; props.exactAscent = true; } else if (n == "bighat") { props.symbol = QChar(0x22C0); props.heightIsAscent = true; props.exactAscent = true; props.heightIsAscent = true; props.exactAscent = true; } else if (n == "int") { props.symbol = QChar(0x222B); props.fontFactor = mathFontFactor; /*yfactor=+0.1;*/ props.heightIsAscent = true; props.exactAscent = true; } else {return false;} return true; } bool JKQTMathText::MTsymbolNode::getSymbolProp(JKQTMathText::MTsymbolNode::SymbolProps& props, const QString &n, const MTenvironment& currentEv, double mathFontFactor) const { auto fnt=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Text); auto fntGreek=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Greek); auto fntSym=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Symbols); //qDebug()<<"--- getSymbolProp("<getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Text); auto fntSym=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Symbols); auto fntGreek=parent->getFontData(currentEv.font, currentEv.insideMath, FontSubclass::Greek); JKQTMathText::MTsymbolNode::SymbolProps props; double mathFontFactor=1.8; props.symbol=""; props.fontFactor=1.0; props.bold=0; props.italic=-1; props.yfactor=0; props.drawBar=false; props.font=fnt.first; props.heightIsAscent=false; props.exactAscent=false; props.extendWidthInMathmode=false; QString n=symName; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // statische Lookup-Tabellen vorbereiten //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static QStringList extendWInMM; if (extendWInMM.isEmpty()) { extendWInMM <<"ll"<<"gg"<<"leq"<<"geq"<<"leftrightarrow"<<"leftarrow"<<"rightarrow"<<"to"<<"uparrow"<<"downarrow"<<"updownarrow"<<"Leftrightarrow" <<"iff"<<"Leftarrow"<<"Rightarrow"<<"Uparrow"<<"Downarrow"<<"Updownarrow"<<"pm"<<"mp"<<"nexists"<<"ni"<<"notni"<<"circ"<<"sim"<<"emptyset"<<"odot"<<"ominus" <<"subsetnot"<<"bot"<<"leftharpoonup"<<"rightharpoonup"<<"upharpoonleft"<<"downharpoonleft"<<"leftrightharpoon"<<"rightleftharpoon"<<"coprod"<<"leftharpoondown" <<"rightharpoondown"<<"upharpoonright"<<"downharpoonright"<<"nwarrow"<<"nearrow"<<"searrow"<<"swarrow"<<"mapsto"<<"div"<<"multimap"<<"maporiginal"<<"mapimage" <<"times"<<"propto"<<"bullet"<<"neq"<<"ne"<<"equiv"<<"approx"<<"otimes"<<"oplus"<<"oslash"<<"cap"<<"land"<<"cup"<<"lor"<<"supset"<<"supseteq"<<"supsetnot" <<"subset"<<"subseteq"<<"in"<<"notin"<<"cdot"<<"wedge"<<"vee"<<"cong"<<"bot"<<"mid"; } if (extendWInMM.contains(n)) { props.extendWidthInMathmode=true; } static QHash simpleTranslations; if (simpleTranslations.isEmpty()) { simpleTranslations.insert("", " "); simpleTranslations.insert("sin", "sin"); simpleTranslations.insert("cos", "cos"); simpleTranslations.insert("tan", "tan"); simpleTranslations.insert("sinh", "sinh"); simpleTranslations.insert("cosh", "cosh"); simpleTranslations.insert("tanh", "tanh"); simpleTranslations.insert("atan", "atan"); simpleTranslations.insert("acos", "acos"); simpleTranslations.insert("asin", "asin"); simpleTranslations.insert("arcsin", "arcsin"); simpleTranslations.insert("arccos", "arccos"); simpleTranslations.insert("arctan", "arctan"); simpleTranslations.insert("degree", QLatin1String("\xB0")); simpleTranslations.insert("textdegree ", QLatin1String("\xB0")); simpleTranslations.insert("ii", "i"); simpleTranslations.insert("dd", "d"); simpleTranslations.insert("exp", "exp"); simpleTranslations.insert("log", "log"); simpleTranslations.insert("ln", "ln"); simpleTranslations.insert("ld", "ld"); simpleTranslations.insert("lb", "lb"); simpleTranslations.insert("argmin", "argmin"); simpleTranslations.insert("argmax", "argmax"); simpleTranslations.insert("max", "max"); simpleTranslations.insert("mod", "mod"); simpleTranslations.insert("min", "min"); simpleTranslations.insert("median", "median"); simpleTranslations.insert("sign", "sign"); simpleTranslations.insert("sgn", "sgn"); simpleTranslations.insert("sec", "sec"); simpleTranslations.insert("gcd", "gcd"); simpleTranslations.insert("hom", "hom"); simpleTranslations.insert("ker", "ker"); simpleTranslations.insert("dim", "dim"); simpleTranslations.insert("cot", "cot"); simpleTranslations.insert("arg", "arg"); simpleTranslations.insert("det", "det"); simpleTranslations.insert("deg", "deg"); simpleTranslations.insert("Pr", "Pr"); simpleTranslations.insert("coth", "coth"); } static QHash simpleTranslations_heightIsAscent; if (simpleTranslations_heightIsAscent.isEmpty()) { simpleTranslations_heightIsAscent.insert("erf", "erf"); simpleTranslations_heightIsAscent.insert("median", "median"); simpleTranslations_heightIsAscent.insert("min", "min"); simpleTranslations_heightIsAscent.insert("max", "max"); simpleTranslations_heightIsAscent.insert("inf", "inf"); simpleTranslations_heightIsAscent.insert("sup", "sup"); simpleTranslations_heightIsAscent.insert("liminf", "liminf"); simpleTranslations_heightIsAscent.insert("limsup", "limsup"); simpleTranslations_heightIsAscent.insert("lim", "lim"); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// props.font=fnt.first; QString errorExplanation=""; QHash::iterator itsimple = simpleTranslations.find(n); if (itsimple!= simpleTranslations.end()) { props.symbol=itsimple.value(); } else { QHash::iterator itsimplehia = simpleTranslations_heightIsAscent.find(n); if (itsimplehia != simpleTranslations_heightIsAscent.end()) { props.symbol = itsimplehia.value(); props.heightIsAscent = true; } else { props.font=fnt.first; if (!getSymbolProp(props, n, currentEv, mathFontFactor)) { errorExplanation="didn't find symbol given font def:"+fnt.first+"["+encoding2String(fnt.second)+"] / sym:"+fntSym.first+"["+encoding2String(fntSym.second)+"] / grk:"+fntGreek.first+"["+encoding2String(fntGreek.second)+"]"; } } } if (addWhitespace) props.symbol+=" "; static QSet extraSymbolName = { "infty", "|", " ", "quad", "qquad", "space", ";", ":", ",", "!", "longleftarrow", "longrightarrow", "Longleftarrow", "Longrightarrow", "longleftrightarrow", "Longleftrightarrow" }; if (props.symbol.simplified().isEmpty() && !extraSymbolName.contains(n)) { parent->error_list.append(tr("unknown symbol '%1' found (%2)!").arg(n).arg(errorExplanation)); } //qDebug()<0) f.setItalic(true); if (props.bold<0) f.setBold(false); if (props.bold>0) f.setBold(true); QFontMetricsF fm(f, painter.device()); QString symb=props.symbol; width=0; if (currentEv.insideMath) width=qMax(parent->getTightBoundingRect(f, symb, painter.device()).width(),parent->getTightBoundingRect(f, "i", painter.device()).width());//fm.width(symbol); else width=fm.boundingRect(symb).width();//fm.width(symbol); width=qMax(fm.boundingRect("j").width(), width); if (symb.isEmpty()) { width=fm.boundingRect("a").width(); if (symbolName=="|") width=fm.boundingRect("1").width()*0.8; else if (symbolName=="infty") width=fm.boundingRect("M").width(); else if (symbolName=="quad" || symbolName=="qquad") width=parent->getTightBoundingRect(f, "M", painter.device()).width(); else if (symbolName==" " || symbolName=="space") width=parent->getTightBoundingRect(f, "x", painter.device()).width(); else if (symbolName==";") width=parent->getTightBoundingRect(f, "x", painter.device()).width()*0.75; else if (symbolName==":") width=parent->getTightBoundingRect(f, "x", painter.device()).width()*0.5; else if (symbolName==",") width=parent->getTightBoundingRect(f, "x", painter.device()).width()*0.25; else if (symbolName=="!") width=-parent->getTightBoundingRect(f, "x", painter.device()).width()*0.25; else if (symbolName=="longleftarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="longrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longleftarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="longleftrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longleftrightarrow") { width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.5; symb="x"; } } QRectF tbr=parent->getTightBoundingRect(f, symb, painter.device()); overallHeight=tbr.height();// fm.height(); baselineHeight=tbr.height()-tbr.bottom(); if (props.exactAscent) { //baselineHeight=fm.ascent()*0.8; } if (props.heightIsAscent) { overallHeight=baselineHeight*1.1; } if (props.exactAscent && props.heightIsAscent) { //qDebug()<getMathoperatorWidthFactor(); } double JKQTMathText::MTsymbolNode::draw(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv, const MTnodeSize* /*prevNodeSize*/) { doDrawBoxes(painter, x, y, currentEv); double width=0; double baselineHeight=0; double overallHeight=0, strikeoutPos=0; getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); QPen pold=painter.pen(); QFont fold=painter.font(); QFont f=currentEv.getFont(parent); QFont f1=f; auto props=getSymbolProp(symbolName, currentEv); f.setFamily(props.font); f.setPointSizeF(f.pointSizeF()*props.fontFactor); if (props.italic<0) f.setItalic(false); if (props.italic>0) f.setItalic(true); if (props.bold<0) f.setBold(false); if (props.bold>0) f.setBold(true); QFontMetricsF fm(f, painter.device()); QFontMetricsF fm1(f1, painter.device()); painter.setFont(f); double shift=0; if (props.extendWidthInMathmode && currentEv.insideMath) { double origwidth=width/parent->getMathoperatorWidthFactor(); shift=0.5*(width-origwidth); //width=width*parent->getMathoperatorWidthFactor(); } //std::cout<<"symbol '"<getTightBoundingRect(f, "M", painter.device()).height()-fm.xHeight())/3.0; QLineF l(xx, yy, xx+xwi/3.0+((currentEv.italic)?(xwi/3.0):0), yy); if (props.drawBar&&l.length()>0) painter.drawLine(l); // try to draw some often used special symbols, by synthesizing them from // standard characters in the current drawing font } else if (symbolName=="infty") { //std::cout<<"draw infty\n"; f1.setItalic(false); painter.setFont(f1); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.translate(x+shift+fm1.boundingRect("8").width()/3.0, y-fm1.xHeight()); painter.rotate(90); painter.drawText(QPointF(0,0), "8"); } else if (symbolName=="|") { //std::cout<<"draw infty\n"; f1.setItalic(false); painter.setFont(f1); painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); painter.translate(x+shift, y); painter.drawText(QPointF(0,0), "|"); painter.translate(fm1.boundingRect("8").width()/3.0, 0); painter.drawText(QPointF(0,0), "|"); // here are some spaces } else if (symbolName==" ") { // full space (width of x) } else if (symbolName=="space") { // full space (width of x) } else if (symbolName=="qquad") { // full space(width of M) } else if (symbolName=="quad") { // full space(width of M) } else if (symbolName==";") { // 75% space } else if (symbolName==":") { // 50% space } else if (symbolName==",") { // 25% space } else if (symbolName=="!") { // -25% space } else if (symbolName=="longleftarrow") { double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0; double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, false); painter.drawPath(path); } else if (symbolName=="longrightarrow"){ double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0; double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, false, true); painter.drawPath(path); } else if (symbolName=="Longleftarrow") { double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0; double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, false); painter.drawPath(path); } else if (symbolName=="Longrightarrow") { double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0; double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, false, true); painter.drawPath(path); } else if (symbolName=="longleftrightarrow") { double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0; double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, true); painter.drawPath(path); } else if (symbolName=="Longleftrightarrow") { double width=parent->getTightBoundingRect(f, "X", painter.device()).width()*3.0; double dx=parent->getTightBoundingRect(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTightBoundingRect(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTightBoundingRect(f, "M", painter.device()).height()*0.5, true, true); painter.drawPath(path); } else { // draw a box to indicate an unavailable symbol QRectF tbr=parent->getTightBoundingRect(f, "M", painter.device()); painter.drawRect(QRectF(x+shift,y-tbr.height(), xwi, tbr.height()*0.8)); } painter.setPen(pold); painter.setFont(fold); return x+width; } bool JKQTMathText::MTsymbolNode::toHtml(QString &html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) { bool ok=true; QString s; JKQTMathText::MTenvironment ev=currentEv; static QMap entitylut; if (entitylut.isEmpty()) { entitylut.insert("sin", "sin"); entitylut.insert("cos", "cos"); entitylut.insert("tan", "tan"); entitylut.insert("sinh", "sinh"); entitylut.insert("cosh", "cosh"); entitylut.insert("tanh", "tanh"); entitylut.insert("atan", "atan"); entitylut.insert("acos", "acos"); entitylut.insert("asin", "asin"); entitylut.insert("arcsin", "arcsin"); entitylut.insert("arccos", "arccos"); entitylut.insert("arctan", "arctan"); entitylut.insert("ii", "i"); entitylut.insert("dd", "d"); entitylut.insert("exp", "exp"); entitylut.insert("log", "log"); entitylut.insert("ln", "ln"); entitylut.insert("ld", "ld"); entitylut.insert("lb", "lb"); entitylut.insert("erf", "erf"); entitylut.insert("mod", "mod"); entitylut.insert("median", "median"); entitylut.insert("min", "min"); entitylut.insert("max", "max"); entitylut.insert("argmin", "argmin"); entitylut.insert("argmax", "argmax"); entitylut.insert("inf", "inf"); entitylut.insert("sup", "sup"); entitylut.insert("liminf", "liminf"); entitylut.insert("limsup", "limsup"); entitylut.insert("lim", "lim"); entitylut.insert("sec", "sec"); entitylut.insert("gcd", "gcd"); entitylut.insert("hom", "hom"); entitylut.insert("ker", "ker"); entitylut.insert("dim", "dim"); entitylut.insert("cot", "cot"); entitylut.insert("arg", "arg"); entitylut.insert("det", "det"); entitylut.insert("deg", "deg"); entitylut.insert("sign", "sign"); entitylut.insert("sgn", "sgn"); entitylut.insert("Pr", "Pr"); entitylut.insert("coth", "coth"); entitylut.insert("alpha", "α"); entitylut.insert("beta", "β"); entitylut.insert("gamma", "γ"); entitylut.insert("delta", "δ"); entitylut.insert("epsilon", "ε"); entitylut.insert("varepsilon", "ε"); entitylut.insert("zeta", "ζ"); entitylut.insert("eta", "η"); entitylut.insert("theta", "θ"); entitylut.insert("vartheta", "ϑ"); entitylut.insert("iota", "ι"); entitylut.insert("kappa", "κ"); entitylut.insert("lambda", "λ"); entitylut.insert("mu", "μ"); entitylut.insert("nu", "ν"); entitylut.insert("xi", "ξ"); entitylut.insert("pi", "π"); entitylut.insert("varpi", "ϖ"); entitylut.insert("rho", "ρ"); entitylut.insert("sigma", "σ"); entitylut.insert("varsigma", "ς"); entitylut.insert("tau", "τ"); entitylut.insert("upsilon", "υ"); entitylut.insert("phi", "φ"); entitylut.insert("varphi", "φ"); entitylut.insert("chi", "χ"); entitylut.insert("psi", "ψ"); entitylut.insert("omega", "ω"); entitylut.insert("Gamma", "Γ"); entitylut.insert("Delta", "Δ"); entitylut.insert("Theta", "Θ"); entitylut.insert("Lambda", "Λ"); entitylut.insert("Omega", "Ω"); entitylut.insert("Xi", "Ξ"); entitylut.insert("Pi", "Π"); entitylut.insert("Sigma", "Σ"); entitylut.insert("Upsilon", "Υ"); entitylut.insert("Phi", "Φ"); entitylut.insert("Psi", "Ψ"); entitylut.insert("leftrightarrow", "↔"); entitylut.insert("leftarrow", "←"); entitylut.insert("rightarrow", "→"); entitylut.insert("to", "→"); entitylut.insert("uparrow", "↑"); entitylut.insert("downarrow", "↓"); entitylut.insert("Leftrightarrow", "⇔"); entitylut.insert("iff", "⇔"); entitylut.insert("Leftarrow", "⇐"); entitylut.insert("Rightarrow", "⇒"); entitylut.insert("Uparrow", "⇑"); entitylut.insert("Downarrow", "⇓"); entitylut.insert("pm", "±"); entitylut.insert("leq", "≤"); entitylut.insert("geq", "≥"); entitylut.insert("times", "×"); entitylut.insert("propto", "∝"); entitylut.insert("partial", "∂"); entitylut.insert("bullet", "•"); entitylut.insert("neq", "≠"); entitylut.insert("ne", "≠"); entitylut.insert("equiv", "≡"); entitylut.insert("approx", "≈"); entitylut.insert("ellipsis", "..."); entitylut.insert("Im", "ℑ"); entitylut.insert("Re", "ℜ"); entitylut.insert("otimes", "⊗"); entitylut.insert("oplus", "⊕"); entitylut.insert("oslash", "/"); entitylut.insert("cap", "∩"); entitylut.insert("cup", "∪"); entitylut.insert("land", "∩"); entitylut.insert("lor", "∪"); entitylut.insert("supset", "⊃"); entitylut.insert("supseteq", "⊇"); entitylut.insert("supsetnot", "⊅"); entitylut.insert("subset", "⊂"); entitylut.insert("subseteq", "⊆"); entitylut.insert("in", "∈"); entitylut.insert("notin", "∉"); entitylut.insert("angle", "∠"); entitylut.insert("nabla", "∇"); entitylut.insert("copyright", "©"); entitylut.insert("registered", "®"); entitylut.insert("trademark", "™"); entitylut.insert("textregistered", "™"); entitylut.insert("cdot", "⋅"); entitylut.insert("neg", "¬"); entitylut.insert("wedge", "∧"); entitylut.insert("vee", "∨"); entitylut.insert("diamond", "◊"); entitylut.insert("langle", "⟨"); entitylut.insert("rangle", "⟩"); entitylut.insert("int", "∫"); entitylut.insert("forall", "∀"); entitylut.insert("exists", "∃"); entitylut.insert("cong", "∼"); entitylut.insert("bot", "⊥"); entitylut.insert("ll", "<<"); entitylut.insert("gg", ">>"); entitylut.insert("bbC", "C"); entitylut.insert("bbH", "H"); entitylut.insert("bbN", "N"); entitylut.insert("bbP", "P"); entitylut.insert("bbQ", "Q"); entitylut.insert("bbR", "R"); entitylut.insert("bbZ", "Z"); entitylut.insert("Alef", "ℵ"); entitylut.insert("alef", "ℵ"); entitylut.insert("tilde", "~"); entitylut.insert("iint", "∫∫"); entitylut.insert("iiint", "∫∫∫"); entitylut.insert("emptyset", "∅"); entitylut.insert("varnothing", "∅"); entitylut.insert("lceil", "⌈"); entitylut.insert("rceil", "⌉"); entitylut.insert("lfloor", "⌊"); entitylut.insert("rfloor", "⌋"); entitylut.insert("subsetnot", "⊄"); entitylut.insert("DC", "="); entitylut.insert("cdots", "⋅⋅⋅"); entitylut.insert("dots", "..."); entitylut.insert("cent", "¢"); entitylut.insert("_", "_"); entitylut.insert("}", "}"); entitylut.insert("{", "{"); entitylut.insert("hbar", "ℏ"); entitylut.insert("euro", "€"); entitylut.insert("pound", "£"); entitylut.insert("yen", "¥"); entitylut.insert("div", "÷"); entitylut.insert("backslash", "\\"); entitylut.insert("$", "$"); entitylut.insert("%", "%"); entitylut.insert("&", "&"); entitylut.insert("#", "#"); entitylut.insert("ast", "*"); entitylut.insert("glq", "'"); entitylut.insert("grq", "'"); entitylut.insert("glqq", "\""); entitylut.insert("grqq", "\""); entitylut.insert("flq", "<"); entitylut.insert("frq", ">"); entitylut.insert("flqq", ""); entitylut.insert("frqq", ""); } QMap::iterator itS = entitylut.find(symbolName); if (itS!=entitylut.end()) { s=itS.value(); } else if (symbolName == "sum") { ev.fontSize*=1.7; s="∑"; } else if (symbolName == "prod") { ev.fontSize*=1.7; s="∏"; } else if (symbolName == "bigcap") { ev.fontSize*=1.7; s="∩"; } else if (symbolName == "bigcup") { ev.fontSize*=1.7; s="∪"; } else if (symbolName == "bigvee") { ev.fontSize*=1.7; s="∨"; } else if (symbolName == "bighat") { ev.fontSize*=1.7; s="∧"; } else ok=false; if (ok) html=html+ev.toHtmlStart(defaultEv)+s+ev.toHtmlAfter(defaultEv); return ok; } QString JKQTMathText::MTsymbolNode::getSymbolName() const { return this->symbolName; } QString JKQTMathText::MTsymbolNode::getSymbolfontName() const { MTenvironment currentEv; auto props=getSymbolProp(symbolName, currentEv); return props.font; } bool JKQTMathText::MTsymbolNode::getAddWhitespace() const { return addWhitespace; } // -------------------------------------------------------------------------------------------------- // -- implementation of the JKQTMathText methods // -------------------------------------------------------------------------------------------------- JKQTMathText::JKQTMathText(QObject* parent): QObject(parent) { //std::chrono::high_resolution_clock::time_point t0=std::chrono::high_resolution_clock::now(); initJKQTMathTextResources(); //qDebug()<<"init_resoucre: "<(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now(); fontSize=10; brace_factor=1.04; subsuper_size_factor=0.7; italic_correction_factor=0.4; sub_shift_factor=0.4; super_shift_factor=0.6; brace_shrink_factor=0.6; fontColor=QColor("black"); frac_factor=0.9; frac_shift_factor=0.4; underbrace_factor=0.75; undersetFactor=0.7; decoration_height_factor=0.2; brace_y_shift_factor=0.7;//-1; operatorsubsuper_size_factor=0.65; mathoperator_width_factor=1.5; expensiveRendering=true; blackboardSimulated=true; static QString serifFont="serif"; static QString sansFont="sans"; static QString symbolFont="symbol"; static QString scriptFont="script"; static QString typewriterFont="typewriter"; static QString decorativeFont="decorative"; static QString blackboardFont="blackboard"; static QString fracturFont="fraktur"; static bool firstStart=true; if (firstStart) { //t0=std::chrono::high_resolution_clock::now(); firstStart=false; #if (QT_VERSION(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now(); auto checkForFonts=[&fonts](QString& targetfont, const QStringList& fontoptions) { for (auto& f: fontoptions) { if (fonts.contains(f)) { targetfont=f; break; } } }; checkForFonts(serifFont, QStringList {"Times New Roman", "Times", "FreeSerif", "DejaVu Serif"}); //qDebug()<<"check 1st font: "<(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; checkForFonts(sansFont, QStringList {"Arial Unicode MS", "Arial Unicode", "Lucida Sans Unicode", "Arial", "Helvetica", "FreeSans", "DejaVu Sans", "Lucida Sans"}); checkForFonts(symbolFont, QStringList {"SymbolStandard", "Symbol"}); checkForFonts(typewriterFont, QStringList {"Courier New", "Courier", "Courier Std", "FreeMono", "CMU Typewriter Text", "UM Typewriter"}); checkForFonts(blackboardFont, QStringList {"Double Stroke", "CloisterOpenFace BT", "GoudyHandtooled BT", "Castellar", "MathJax_AMS", "Castellar Standard", "MathJax_AMS Standard", "Colonna MT"}); checkForFonts(decorativeFont, QStringList {"Lucida Calligraphy", "Cookie", "Segoe Print", "Comic Sans", "Comic Sans MS", "Gabriola", "Gabriola Standard", "Lucida Handwriting Kursiv", "Lucida Handwriting", "Pristina", "Pristina Standard", "MathJax_Caligraphics"}); checkForFonts(scriptFont, QStringList {"Lucida Handwriting", "Dancing Script", "Amazone BT", "ScriptS", "ScriptC", "ScriptC Standard", "Script", "Brush Script MT", "Brush Script MT Kursiv", "MathJax_Script"}); checkForFonts(fracturFont, QStringList {"Old English Text MT", "Old English Text MT Standard", "UnifrakturMaguntia Standard", "UnifrakturMaguntia", "MathJax_Fraktur", "UnifrakturCook Fett"}); //qDebug()<<"check all font: "<(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; } //t0=std::chrono::high_resolution_clock::now(); if (serifFont!="serif") addReplacementFont("serif", serifFont); if (sansFont!="sans") addReplacementFont("sans", sansFont); if (symbolFont!="symbol") addReplacementFont("symbol", symbolFont); if (scriptFont!="script") addReplacementFont("script", scriptFont); if (typewriterFont!="typewriter") addReplacementFont("typewriter", typewriterFont); if (decorativeFont!="decorative") addReplacementFont("decorative", decorativeFont); if (fracturFont!="fraktur") addReplacementFont("fraktur", fracturFont); if (blackboardFont!="blackboard") { addReplacementFont("blackboard", blackboardFont); } //qDebug()<<"add replacement fonts: "<(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now(); setFontSans(sansFont, MTFEStandard); setFontMathSans(sansFont, MTFEStandard); setFontTypewriter(typewriterFont, MTFEStandard); setFontRoman(serifFont, MTFEStandard); setFontMathRoman(serifFont, MTFEStandard); setFontCaligraphic(decorativeFont, MTFEStandard); setFontBlackboard(blackboardFont, MTFEStandard); setFontBlackboardSimulated(blackboardFont=="blackboard"); setFontScript(scriptFont, MTFEStandard); setFontFraktur(fracturFont, MTFEStandard); //qDebug()<<"set fonts: "<(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now(); useXITS(); //qDebug()<<"useXITS: "<(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now(); useUnparsed=false; parsedNode=nullptr; unparsedNode=nullptr; currentToken=MTTnone; currentTokenName=""; currentTokenID=0; parseString=""; parsingMathEnvironment=false; } JKQTMathText::~JKQTMathText() { if (parsedNode!=nullptr) delete parsedNode; parsedNode=nullptr; if (unparsedNode!=nullptr) delete unparsedNode; unparsedNode=nullptr; } void JKQTMathText::loadSettings(const QSettings& settings, const QString& group){ fontSize=settings.value(group+"font_size", fontSize).toDouble(); fontColor=jkqtp_String2QColor(settings.value(group+"font_color", jkqtp_QColor2String(fontColor)).toString()); brace_factor=settings.value(group+"brace_factor", brace_factor).toDouble(); brace_shrink_factor=settings.value(group+"brace_shrink_factor", brace_shrink_factor).toDouble(); subsuper_size_factor=settings.value(group+"subsuper_size_factor", subsuper_size_factor).toDouble(); italic_correction_factor=settings.value(group+"italic_correction_factor", italic_correction_factor).toDouble(); super_shift_factor=settings.value(group+"super_shift_factor", super_shift_factor).toDouble(); sub_shift_factor=settings.value(group+"sub_shift_factor", sub_shift_factor).toDouble(); frac_factor=settings.value(group+"frac_factor", frac_factor).toDouble(); frac_shift_factor=settings.value(group+"frac_shift_factor", frac_shift_factor).toDouble(); underbrace_factor=settings.value(group+"underbrace_factor", underbrace_factor).toDouble(); undersetFactor=settings.value(group+"undersetFactor", undersetFactor).toDouble(); brace_y_shift_factor=settings.value(group+"brace_y_shift_factor", brace_y_shift_factor).toDouble(); decoration_height_factor=settings.value(group+"decoration_height_factor", decoration_height_factor).toDouble(); operatorsubsuper_size_factor=settings.value(group+"operatorsubsuper_size_factor", operatorsubsuper_size_factor).toDouble(); mathoperator_width_factor=settings.value(group+"mathoperator_width_factor", mathoperator_width_factor).toDouble(); if (settings.value(group+"use_stix_fonts", false).toBool()) useSTIX(); if (settings.value(group+"use_xits_fonts", false).toBool()) useXITS(); if (settings.value(group+"use_asana_fonts", false).toBool()) useASANA(); } void JKQTMathText::saveSettings(QSettings& settings, const QString& group) const{ settings.setValue(group+"font_size", fontSize); settings.setValue(group+"font_color", jkqtp_QColor2String(fontColor)); settings.setValue(group+ "brace_factor", brace_factor); settings.setValue(group+ "brace_shrink_factor", brace_shrink_factor); settings.setValue(group+ "subsuper_size_factor", subsuper_size_factor); settings.setValue(group+ "italic_correction_factor", italic_correction_factor); settings.setValue(group+ "sub_shift_factor", sub_shift_factor); settings.setValue(group+ "super_shift_factor", super_shift_factor); settings.setValue(group+ "frac_factor", frac_factor); settings.setValue(group+ "frac_shift_factor", frac_shift_factor); settings.setValue(group+ "underbrace_factor", underbrace_factor); settings.setValue(group+ "undersetFactor", undersetFactor); settings.setValue(group+ "operatorsubsuper_size_factor", operatorsubsuper_size_factor); settings.setValue(group+ "mathoperator_width_factor", mathoperator_width_factor); settings.setValue(group+ "brace_y_shift_factor", brace_y_shift_factor); settings.setValue(group+ "decoration_height_factor", decoration_height_factor); } bool JKQTMathText::useSTIX(bool mathModeOnly) { const JKQTMathTextFontSpecifier xits=JKQTMathTextFontSpecifier::getSTIXFamilies(); bool res=false; if (!mathModeOnly && !xits.fontName().isEmpty()) { setFontRoman(xits.fontName(), MTFEunicode); res=true; } if (!xits.mathFontName().isEmpty()) { setFontMathRoman(xits.mathFontName(), MTFEunicode); res=true; } else if (!xits.fontName().isEmpty()) { setFontMathRoman(xits.fontName(), MTFEunicode); res=true; } brace_shrink_factor=0.6; return res; } bool JKQTMathText::useXITS(bool mathModeOnly) { const JKQTMathTextFontSpecifier xits=JKQTMathTextFontSpecifier::getXITSFamilies(); bool res=false; if (!mathModeOnly && !xits.fontName().isEmpty()) { setFontRoman(xits.fontName(), MTFEunicode); setSymbolfontSymbol(xits.fontName(), MTFEunicode); setSymbolfontGreek(xits.fontName(), MTFEunicode); brace_shrink_factor=0.6; res=true; } if (!xits.mathFontName().isEmpty()) { setFontMathRoman(xits.mathFontName(), MTFEunicode); setSymbolfontSymbol(xits.fontName(), MTFEunicode); setSymbolfontGreek(xits.fontName(), MTFEunicode); brace_shrink_factor=0.6; res=true; } return res; } bool JKQTMathText::useASANA(bool mathModeOnly) { const JKQTMathTextFontSpecifier asana=JKQTMathTextFontSpecifier::getXITSFamilies(); bool res=false; if (!mathModeOnly && !asana.fontName().isEmpty()) { setFontRoman(asana.fontName(), MTFEunicode); res=true; } if (!asana.mathFontName().isEmpty()) { setFontMathRoman(asana.mathFontName(), MTFEunicode); res=true; } brace_shrink_factor=0.6; return res; } void JKQTMathText::useAnyUnicode(QString timesFont, const QString &sansFont, JKQTMathText::MTfontEncoding encodingTimes, JKQTMathText::MTfontEncoding encodingSans) { if (!timesFont.isEmpty()) { setFontRoman(timesFont, encodingTimes); } if (!sansFont.isEmpty()) { setFontSans(sansFont, encodingSans); } brace_shrink_factor=0.6; } QString JKQTMathText::toHtml(bool *ok, double fontPointSize) { QString s; bool okk=false; if (getTree()!=nullptr) { MTenvironment ev; ev.color=fontColor; ev.fontSize=fontPointSize; MTenvironment defaultev; defaultev.fontSize=fontPointSize; okk=getTree()->toHtml(s, ev, defaultev); } if (ok) *ok=okk; return s; } QString JKQTMathText::encoding2String(JKQTMathText::MTfontEncoding e) { switch(e) { case MTFEunicode: return "MTFEunicode"; case MTFEStandard: return "MTFEStandard"; case MTFEunicodeLimited: return "MTFEunicodeLimited"; case MTFEwinSymbol: return "MTFEwinSymbol"; } return "???"; } void JKQTMathText::setFontColor(const QColor &__value) { this->fontColor = __value; } QColor JKQTMathText::getFontColor() const { return this->fontColor; } void JKQTMathText::setFontSize(double __value) { this->fontSize = __value; } double JKQTMathText::getFontSize() const { return this->fontSize; } void JKQTMathText::addReplacementFont(const QString &nonUseFont, const QString &useFont, MTfontEncoding useFontEncoding) { fontReplacements.insert(nonUseFont, useFont); fontEncodingReplacements.insert(nonUseFont, useFontEncoding); } void JKQTMathText::addReplacementFont(const QString &nonUseFont, const QString &useFont) { fontReplacements.insert(nonUseFont, useFont); auto it=fontEncodingReplacements.find(nonUseFont); if (it!=fontEncodingReplacements.end()) fontEncodingReplacements.erase(it); } QPair JKQTMathText::getReplacementFont(const QString &nonUseFont, const QString &defaultFont, JKQTMathText::MTfontEncoding defaultFontEncoding) const { QPair res(defaultFont, defaultFontEncoding); bool foundFont=false; for (auto it=fontReplacements.begin(); it!=fontReplacements.end(); ++it) { if (it.key().toLower()==nonUseFont.toLower()) { foundFont=true; res.first=it.value(); res.second=fontEncodingReplacements.value(res.first, res.second); return res; } } return res; } QPair JKQTMathText::getFontData(JKQTMathText::MTenvironmentFont font, bool /*in_math_environment*/, FontSubclass subclass) const { const auto fd=fontDefinitions.value(font); if (subclass==FontSubclass::Greek) return QPair(fd.symbolfontGreek, fd.symbolfontGreekEncoding); if (subclass==FontSubclass::Symbols) return QPair(fd.symbolfontSymbol, fd.symbolfontSymbolEncoding); return QPair(fd.fontName, fd.fontEncoding); } void JKQTMathText::setFontRomanOrSpecial(const QString &__value, MTfontEncoding encoding) { setFontRomanOrSpecial(JKQTMathTextFontSpecifier::fromFontSpec(__value), encoding); } void JKQTMathText::setFontRomanOrSpecial(const JKQTMathTextFontSpecifier &fontName, MTfontEncoding encoding) { if (!fontName.hasMathFontName()) { if (fontName.fontName().toUpper()=="XITS") useXITS(false); else if (fontName.fontName().toUpper()=="STIX") useSTIX(false); else if (fontName.fontName().toUpper()=="ASANA") useASANA(false); else { setFontRoman(fontName.fontName(), encoding); setFontMathRoman(fontName.fontName(), encoding); } } else { if (fontName.mathFontName().toUpper()=="XITS") useXITS(true); else if (fontName.mathFontName().toUpper()=="STIX") useSTIX(true); else if (fontName.mathFontName().toUpper()=="ASANA") useASANA(true); else setFontMathRoman(fontName.mathFontName(), encoding); setFontRoman(fontName.fontName(), encoding); } } void JKQTMathText::setFontRoman(const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[MTEroman].fontName = f.first; fontDefinitions[MTEroman].fontEncoding = f.second; } QString JKQTMathText::getFontRoman() const { return fontDefinitions[MTEroman].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingRoman() const { return fontDefinitions[MTEroman].fontEncoding; } void JKQTMathText::setFontSans(const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[MTEsans].fontName = f.first; fontDefinitions[MTEsans].fontEncoding = f.second; } QString JKQTMathText::getFontSans() const { return fontDefinitions[MTEsans].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingSans() const { return fontDefinitions[MTEsans].fontEncoding; } void JKQTMathText::setFontTypewriter(const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[MTEtypewriter].fontName = f.first; fontDefinitions[MTEtypewriter].fontEncoding = f.second; } QString JKQTMathText::getFontTypewriter() const { return fontDefinitions[MTEtypewriter].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingTypewriter() const { return fontDefinitions[MTEtypewriter].fontEncoding; } void JKQTMathText::setFontScript(const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[MTEscript].fontName = f.first; fontDefinitions[MTEscript].fontEncoding = f.second; } QString JKQTMathText::getFontScript() const { return fontDefinitions[MTEscript].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingScript() const { return fontDefinitions[MTEscript].fontEncoding; } void JKQTMathText::setFontFraktur(const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[MTEfraktur].fontName = f.first; fontDefinitions[MTEfraktur].fontEncoding = f.second; } QString JKQTMathText::getFontFraktur() const { return fontDefinitions[MTEfraktur].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingFraktur() const { return fontDefinitions[MTEfraktur].fontEncoding; } void JKQTMathText::setSymbolfontGreek(MTenvironmentFont font, const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[font].symbolfontGreek = f.first; fontDefinitions[font].symbolfontGreekEncoding = f.second; } void JKQTMathText::setSymbolfontGreek(const QString &fontName, JKQTMathText::MTfontEncoding encoding) { for (int f=0; f(MTenvironmentFontCount); f++) { setSymbolfontGreek(static_cast(f), fontName, encoding); } } QString JKQTMathText::getSymbolfontGreek(MTenvironmentFont font) const { return fontDefinitions[font].symbolfontGreek; } JKQTMathText::MTfontEncoding JKQTMathText::getSymbolfontEncodingGreek(MTenvironmentFont font) const { return fontDefinitions[font].symbolfontGreekEncoding; } void JKQTMathText::setSymbolfontSymbol(MTenvironmentFont font, const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[font].symbolfontSymbol = f.first; fontDefinitions[font].symbolfontSymbolEncoding = f.second; } void JKQTMathText::setSymbolfontSymbol(const QString &fontName, JKQTMathText::MTfontEncoding encoding) { for (int f=0; f(MTenvironmentFontCount); f++) { setSymbolfontSymbol(static_cast(f), fontName, encoding); } } QString JKQTMathText::getSymbolfontSymbol(MTenvironmentFont font) const { return fontDefinitions[font].symbolfontSymbol; } JKQTMathText::MTfontEncoding JKQTMathText::getSymbolfontEncodingSymbol(MTenvironmentFont font) const { return fontDefinitions[font].symbolfontSymbolEncoding; } void JKQTMathText::setFontCaligraphic(const QString &__value, MTfontEncoding encoding) { auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[MTEcaligraphic].fontName = f.first; fontDefinitions[MTEcaligraphic].fontEncoding = f.second; } QString JKQTMathText::getFontCaligraphic() const { return fontDefinitions[MTEcaligraphic].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingCaligraphic() const { return fontDefinitions[MTEcaligraphic].fontEncoding; } void JKQTMathText::setFontMathRoman(const QString &fontName, JKQTMathText::MTfontEncoding encoding) { auto f=getReplacementFont(fontName, fontName, encoding); fontDefinitions[MTEmathRoman].fontName = f.first; fontDefinitions[MTEmathRoman].fontEncoding = f.second; } QString JKQTMathText::getFontMathRoman() const { return fontDefinitions[MTEmathRoman].fontName; } void JKQTMathText::setFontMathSans(const QString &fontName, JKQTMathText::MTfontEncoding encoding) { auto f=getReplacementFont(fontName, fontName, encoding); fontDefinitions[MTEmathSans].fontName = f.first; fontDefinitions[MTEmathSans].fontEncoding = f.second; } QString JKQTMathText::getFontMathSans() const { return fontDefinitions[MTEmathSans].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingMathSans() const { return fontDefinitions[MTEmathSans].fontEncoding; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingMathRoman() const { return fontDefinitions[MTEmathRoman].fontEncoding; } void JKQTMathText::setFontBlackboard(const QString &__value, MTfontEncoding encoding) { blackboardSimulated=false; auto f=getReplacementFont(__value, __value, encoding); fontDefinitions[MTEblackboard].fontName = f.first; fontDefinitions[MTEblackboard].fontEncoding = f.second; } void JKQTMathText::setFontBlackboardSimulated(bool doSimulate) { blackboardSimulated=doSimulate; } bool JKQTMathText::isFontBlackboardSimulated() const { return blackboardSimulated; } QString JKQTMathText::getFontBlackboard() const { return fontDefinitions[MTEblackboard].fontName; } JKQTMathText::MTfontEncoding JKQTMathText::getFontEncodingBlackboard() const { return fontDefinitions[MTEblackboard].fontEncoding; } void JKQTMathText::setBraceFactor(double __value) { this->brace_factor = __value; } double JKQTMathText::getBraceFactor() const { return this->brace_factor; } void JKQTMathText::setSubsuperSizeFactor(double __value) { this->subsuper_size_factor = __value; } double JKQTMathText::getSubsuperSizeFactor() const { return this->subsuper_size_factor; } void JKQTMathText::setItalicCorrectionFactor(double __value) { this->italic_correction_factor = __value; } double JKQTMathText::getItalicCorrectionFactor() const { return this->italic_correction_factor; } void JKQTMathText::setOperatorsubsuperSizeFactor(double __value) { this->operatorsubsuper_size_factor = __value; } double JKQTMathText::getOperatorsubsuperSizeFactor() const { return this->operatorsubsuper_size_factor; } void JKQTMathText::setMathoperatorWidthFactor(double __value) { this->mathoperator_width_factor = __value; } double JKQTMathText::getMathoperatorWidthFactor() const { return this->mathoperator_width_factor; } void JKQTMathText::setSuperShiftFactor(double __value) { this->super_shift_factor = __value; } double JKQTMathText::getSuperShiftFactor() const { return this->super_shift_factor; } void JKQTMathText::setSubShiftFactor(double __value) { this->sub_shift_factor = __value; } double JKQTMathText::getSubShiftFactor() const { return this->sub_shift_factor; } void JKQTMathText::setBraceShrinkFactor(double __value) { this->brace_shrink_factor = __value; } double JKQTMathText::getBraceShrinkFactor() const { return this->brace_shrink_factor; } void JKQTMathText::setUnderbraceFactor(double __value) { this->underbrace_factor = __value; } double JKQTMathText::getUnderbraceFactor() const { return this->underbrace_factor; } void JKQTMathText::setUndersetFactor(double __value) { this->undersetFactor = __value; } double JKQTMathText::getUndersetFactor() const { return this->undersetFactor; } void JKQTMathText::setFracFactor(double __value) { this->frac_factor = __value; } double JKQTMathText::getFracFactor() const { return this->frac_factor; } void JKQTMathText::setFracShiftFactor(double __value) { this->frac_shift_factor = __value; } double JKQTMathText::getFracShiftFactor() const { return this->frac_shift_factor; } void JKQTMathText::setBraceYShiftFactor(double __value) { this->brace_y_shift_factor = __value; } double JKQTMathText::getBraceYShiftFactor() const { return this->brace_y_shift_factor; } void JKQTMathText::setDecorationHeightFactor(double __value) { this->decoration_height_factor = __value; } double JKQTMathText::getDecorationHeightFactor() const { return this->decoration_height_factor; } void JKQTMathText::setExpensiveRendering(bool __value) { this->expensiveRendering = __value; } bool JKQTMathText::getExpensiveRendering() const { return this->expensiveRendering; } void JKQTMathText::setUseUnparsed(bool __value) { this->useUnparsed = __value; } bool JKQTMathText::isUsingUnparsed() const { return this->useUnparsed; } QStringList JKQTMathText::getErrorList() const { return this->error_list; } 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=="sfrac" || name=="slantfrac" || name=="xfrac") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMsfrac)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="stfrac" || name=="nicefrac" || name=="slanttextfrac" || name=="xtfrac") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMstfrac)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="tfrac") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMtfrac)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="stackrel") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMstackrel)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="binom") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTbraceNode(this, "(", ")", new MTfracNode(this, n1, n2, MTFMstackrel))); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="underbrace") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMunderbrace)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="underset") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMunderset)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="overbrace") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMoverbrace)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="overset") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMoverset)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="begin") { if (getToken()==MTTtext) { QString envname=currentTokenName; while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name' if (envname=="matrix" || envname=="array" || envname=="aligned" || envname=="align" || envname=="cases" || envname=="pmatrix"|| envname=="bmatrix"|| envname=="Bmatrix"|| envname=="vmatrix"|| envname=="Vmatrix") { QVector< QVector > 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; } JKQTMathText::MTnode *JKQTMathText::getParsedNode() const { return this->parsedNode; } QList JKQTMathText::tbrs=QList(); QHash JKQTMathText::tbrh=QHash(); QRectF JKQTMathText::getTightBoundingRect(const QFont &fm, const QString &text, QPaintDevice *pd) { JKQTMathText::tbrDataH dh(fm, text, pd); if (pd) { if (tbrh.contains(dh)) return tbrh[dh]; /*for (int i=0; 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; QPen pp=painter.pen(); QPen p=pp; p.setStyle(Qt::SolidLine); painter.setPen(p); getTree()->setDrawBoxes(drawBoxes); painter.setPen(p); getTree()->draw(painter, x, y, ev); painter.setPen(pp); } } void JKQTMathText::draw(QPainter& painter, unsigned int flags, QRectF rect, bool drawBoxes) { if (getTree()!=nullptr) { QPen pp=painter.pen(); QPen p=pp; p.setStyle(Qt::SolidLine); painter.setPen(p); MTenvironment ev; ev.color=fontColor; ev.fontSize=fontSize; getTree()->setDrawBoxes(drawBoxes); painter.setPen(p); double width=0; double baselineHeight=0; double overallHeight=0, strikeoutPos=0; getTree()->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); // align left top double x=rect.left(); double y=rect.top()+baselineHeight; // care for horizontal align if ((flags & Qt::AlignRight) != 0) x=x+rect.width()-width; else if ((flags & Qt::AlignHCenter) != 0) x=x+(rect.width()-width)/2.0; // care for vertical align if ((flags & Qt::AlignBottom) != 0) y=y+rect.height()-overallHeight; else if ((flags & Qt::AlignVCenter) != 0) y=y+(rect.height()-overallHeight)/2.0; // finally draw getTree()->draw(painter, x, y, ev); painter.setPen(pp); } } JKQTMathText::MTwhitespaceNode::MTwhitespaceNode(JKQTMathText *_parent): MTtextNode(_parent, " ", false, false) { } JKQTMathText::MTwhitespaceNode::~MTwhitespaceNode() = default; QString JKQTMathText::MTwhitespaceNode::getTypeName() const { return QLatin1String("MTwhitespaceNode(")+text+")"; } bool JKQTMathText::MTwhitespaceNode::toHtml(QString &html, JKQTMathText::MTenvironment /*currentEv*/, JKQTMathText::MTenvironment /*defaultEv*/) { html=html+" "; return true; } void JKQTMathText::MTnode::setDrawBoxes(bool draw) { this->drawBoxes=draw; } QString JKQTMathText::MTnode::getTypeName() const { return "MTnode"; } QString JKQTMathText::fracModeToString(JKQTMathText::MTfracMode mode) { switch(mode) { case MTFMfrac: return "frac"; case MTFMdfrac: return "dfrac"; case MTFMsfrac: return "sfrac"; case MTFMstfrac: return "stfrac"; case MTFMtfrac: return "tfrac"; case MTFMunderbrace: return "underbrace"; case MTFMoverbrace: return "overbrace"; case MTFMunderset: return "underset"; case MTFMoverset: return "overset"; case MTFMstackrel: return "stackrel"; } return "unknown"; } QString JKQTMathText::decorationToString(JKQTMathText::MTdecoration mode) { switch(mode) { case MTDvec: return "vec"; case MTDtilde: return "tilde"; case MTDhat: return "hat"; case MTDdot: return "dot"; case MTDddot: return "ddot"; case MTDbar: return "bar"; case MTDarrow: return "arrow"; case MTDoverline: return "overline"; case MTDdoubleoverline: return "double overline"; case MTDunderline: return "underline"; case MTDdoubleunderline: return "double underline"; } return "unknown"; } JKQTMathText::MTnode *JKQTMathText::getTree() const { if (useUnparsed) return unparsedNode; return parsedNode; } JKQTMathTextLabel::JKQTMathTextLabel(QWidget *parent): QLabel(parent) { m_mathText=new JKQTMathText(this); m_mathText->useXITS(); m_mathText->setFontSize(font().pointSizeF()*1.3); lastText=""; repaintDo=true; buffer=QPixmap(); } JKQTMathTextLabel::~JKQTMathTextLabel() = default; JKQTMathText *JKQTMathTextLabel::getMathText() const { return m_mathText; } void JKQTMathTextLabel::setMath(const QString &text, bool doRepaint) { if (text!=lastText || doRepaint){ lastText=text; repaintDo=true; internalPaint(); update(); } } void JKQTMathTextLabel::internalPaint() { //return; //qDebug()<<"internalPaint "<parse(lastText)<<"\n "<getErrorList().join("\n")<<"\n\n"; if (!m_mathText->parse(lastText)) { //qDebug()<<"JKQTMathTextLabel::internalPaint(): parse '"<parse(lastText)<<"\n "<getErrorList().join("\n")<<"\n\n"; } if (buffer.width()<=0 || buffer.height()<=0) { const qreal dpr = devicePixelRatioF(); buffer=QPixmap(1000*dpr,100*dpr); buffer.setDevicePixelRatio(dpr); } //qDebug()<<"internalPaint(): buffer "<getSize(p); p.end(); } const qreal dpr = devicePixelRatioF(); buffer=QPixmap(static_cast(qMax(32.0,size.width()*1.2))*dpr, static_cast(qMax(10.0,size.height()*1.1))*dpr); buffer.setDevicePixelRatio(dpr); buffer.fill(Qt::transparent); { qDebug()<<"internalPaint(): buffer.size()="<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); } JKQTMathText::tbrData::tbrData(const QFont &f, const QString &text, QPaintDevice *pd): fm(f, pd) { this->text=text; this->tbr=this->fm.tightBoundingRect(text); this->f=f; //this->pd=pd; if (pd) { ldpiX=pd->logicalDpiX(); ldpiY=pd->logicalDpiY(); pdpiX=pd->physicalDpiX(); pdpiY=pd->physicalDpiY(); } else { ldpiX=0; ldpiY=0; pdpiX=0; pdpiY=0; } } bool JKQTMathText::tbrData::operator==(const JKQTMathText::tbrData &other) const { return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f; } JKQTMathText::tbrDataH::tbrDataH(const QFont &f, const QString &text, QPaintDevice *pd) { this->text=text; this->f=f; if (pd) { ldpiX=pd->logicalDpiX(); ldpiY=pd->logicalDpiY(); pdpiX=pd->physicalDpiX(); pdpiY=pd->physicalDpiY(); } else { ldpiX=0; ldpiY=0; pdpiX=0; pdpiY=0; } } bool JKQTMathText::tbrDataH::operator==(const JKQTMathText::tbrDataH &other) const { return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f; } JKQTMathText::MTplainTextNode::MTplainTextNode(JKQTMathText *_parent, const QString& _text, bool addWhitespace, bool stripInnerWhitepace): JKQTMathText::MTtextNode(_parent, _text, addWhitespace, stripInnerWhitepace) { } QString JKQTMathText::MTplainTextNode::getTypeName() const { return QLatin1String("MTplainTextNode(")+text+")"; } QString JKQTMathText::MTplainTextNode::textTransform(const QString &_text, JKQTMathText::MTenvironment /*currentEv*/, bool /*forSize*/) { return _text; } void initJKQTMathTextResources() { static bool initialized=false; if (!initialized) { #ifdef JKQTMATHTEXT_COMPILED_WITH_XITS Q_INIT_RESOURCE(xits); #endif initialized=true; } } JKQTMathText::MTnodeSize::MTnodeSize(): width(0), baselineHeight(0),overallHeight(0),strikeoutPos() { } JKQTMathText::FontDefinition::FontDefinition(): fontName("Times New Roman"), fontEncoding(MTFEStandard), symbolfontGreek("Symbol"), symbolfontGreekEncoding(MTFEwinSymbol), symbolfontSymbol("Symbol"), symbolfontSymbolEncoding(MTFEwinSymbol) { } JKQTMathTextFontSpecifier::JKQTMathTextFontSpecifier(): m_fontName(""), m_mathFontName("") { } JKQTMathTextFontSpecifier::JKQTMathTextFontSpecifier(const QString &_fontName, const QString &_mathFontName): m_fontName(_fontName), m_mathFontName(_mathFontName) { } JKQTMathTextFontSpecifier JKQTMathTextFontSpecifier::fromFontSpec(const QString &fontSpec) { JKQTMathTextFontSpecifier s; s.setFontSpec(fontSpec); return s; } void JKQTMathTextFontSpecifier::setFontSpec(const QString &fontSpec) { QStringList splitspec=fontSpec.split('+'); if (splitspec.size()==0) { m_fontName=m_mathFontName=""; } else if (splitspec.size()==1) { m_fontName=splitspec[0]; m_mathFontName=""; } else if (splitspec.size()==2) { m_fontName=splitspec[0]; m_mathFontName=splitspec[1]; } else if (splitspec.size()>2) { m_fontName=splitspec.mid(0, splitspec.size()-1).join('+'); m_mathFontName=splitspec.last(); } } QString JKQTMathTextFontSpecifier::getFontSpec() const { QString res=m_fontName; if (m_mathFontName.size()>0) res+="+"+m_mathFontName; return res; } QString JKQTMathTextFontSpecifier::fontName() const { return transformFontName(m_fontName); } QString JKQTMathTextFontSpecifier::mathFontName() const { return transformFontName(m_mathFontName); } QString JKQTMathTextFontSpecifier::transformFontName(const QString &fontName) { const QString fnt=fontName.trimmed().toLower(); QFont testFnt; if (fnt=="serif") { testFnt.setStyleHint(QFont::StyleHint::Serif); return testFnt.defaultFamily(); } if (fnt=="sans-serif" || fnt=="sansserif" || fnt=="sans" || fnt=="sans serif") { testFnt.setStyleHint(QFont::StyleHint::SansSerif); return testFnt.defaultFamily(); } if (fnt=="cursive") { testFnt.setStyleHint(QFont::StyleHint::Cursive); return testFnt.defaultFamily(); } if (fnt=="typewriter") { testFnt.setStyleHint(QFont::StyleHint::TypeWriter); return testFnt.defaultFamily(); } if (fnt=="monospace") { testFnt.setStyleHint(QFont::StyleHint::Monospace); return testFnt.defaultFamily(); } if (fnt=="fantasy") { testFnt.setStyleHint(QFont::StyleHint::Fantasy); return testFnt.defaultFamily(); } if (fnt=="system") { testFnt.setStyleHint(QFont::StyleHint::System); return testFnt.defaultFamily(); } if (fnt=="decorative") { testFnt.setStyleHint(QFont::StyleHint::Decorative); return testFnt.defaultFamily(); } if (fnt=="default" || fnt=="app" || fnt=="application") { return QGuiApplication::font().family(); } #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) if (fnt=="fixed") { return QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont).family(); } if (fnt=="smallest_readable" || fnt=="smallestreadable" || fnt=="smallest readable" || fnt=="smallest") { return QFontDatabase::systemFont(QFontDatabase::SystemFont::SmallestReadableFont).family(); } if (fnt=="title") { return QFontDatabase::systemFont(QFontDatabase::SystemFont::TitleFont).family(); } if (fnt=="general") { return QFontDatabase::systemFont(QFontDatabase::SystemFont::GeneralFont).family(); } #elif QT_VERSION >= QT_VERSION_CHECK(5,2,0) QFontDatabase fontDB; if (fnt=="fixed") { return fontDB.systemFont(QFontDatabase::SystemFont::FixedFont).family(); } if (fnt=="smallest_readable" || fnt=="smallestreadable" || fnt=="smallest readable" || fnt=="smallest") { return fontDB.systemFont(QFontDatabase::SystemFont::SmallestReadableFont).family(); } if (fnt=="title") { return fontDB.systemFont(QFontDatabase::SystemFont::TitleFont).family(); } if (fnt=="general") { return fontDB.systemFont(QFontDatabase::SystemFont::GeneralFont).family(); } #endif return fontName; } QString JKQTMathTextFontSpecifier::transformFontNameAndDecodeSpecialFonts(const QString &fontName) { const QString fnt=fontName.toLower().trimmed(); if (fnt=="xits") { return getXITSFamilies().fontName(); } else if (fnt=="asana") { return getASANAFamilies().fontName(); } else if (fnt=="stix") { return getSTIXFamilies().fontName(); } return transformFontName(fontName); } bool JKQTMathTextFontSpecifier::hasFontName() const { return !m_fontName.isEmpty(); } bool JKQTMathTextFontSpecifier::hasMathFontName() const { return !m_mathFontName.isEmpty(); } JKQTMathTextFontSpecifier JKQTMathTextFontSpecifier::getXITSFamilies() { #if (QT_VERSION0 && fontSpec.m_fontName.size()>0) { break; } } if (fontSpec.m_mathFontName.isEmpty() && !fontSpec.m_fontName.isEmpty()) { fontSpec.m_mathFontName=fontSpec.m_fontName; } else if (!fontSpec.m_mathFontName.isEmpty() && fontSpec.m_fontName.isEmpty()) { fontSpec.m_fontName=fontSpec.m_mathFontName; } } return fontSpec; } JKQTMathTextFontSpecifier JKQTMathTextFontSpecifier::getASANAFamilies() { #if (QT_VERSION0 && fontSpec.m_fontName.size()>0) { break; } } if (fontSpec.m_mathFontName.isEmpty() && !fontSpec.m_fontName.isEmpty()) { fontSpec.m_mathFontName=fontSpec.m_fontName; } else if (!fontSpec.m_mathFontName.isEmpty() && fontSpec.m_fontName.isEmpty()) { fontSpec.m_fontName=fontSpec.m_mathFontName; } } return fontSpec; } JKQTMathTextFontSpecifier JKQTMathTextFontSpecifier::getSTIXFamilies() { static QStringList mathNames{"STIX Two Math", "STIX Math", "STIX Two Math Standard", "STIX Math Standard"}; static QStringList textNames{"STIX", "STIXGeneral", "STIX General"}; static JKQTMathTextFontSpecifier fontSpec; if (fontSpec.m_fontName.isEmpty() && fontSpec.m_mathFontName.isEmpty()) { #if (QT_VERSION0) { break; } } if (fontSpec.m_mathFontName.size()>0) { break; } } for (const QString& name:textNames) { for (int i=0; i0) { break; } } if (fontSpec.m_fontName.size()>0) { break; } } if (fontSpec.m_mathFontName.isEmpty() && !fontSpec.m_fontName.isEmpty()) { fontSpec.m_mathFontName=fontSpec.m_fontName; } else if (!fontSpec.m_mathFontName.isEmpty() && fontSpec.m_fontName.isEmpty()) { fontSpec.m_fontName=fontSpec.m_mathFontName; } } return fontSpec; }