/* Copyright (c) 2008-2018 Jan W. Krieger () This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License (LGPL) for more details. You should have received a copy of the GNU Lesser General Public License (LGPL) along with this program. If not, see . */ #include "jkqtmathtext/jkqtmathtext.h" #include #include #include #include #include //#define JKQTP_QColor2String(color) QString(jkqtp_rgbtostring((color).red(), (color).green(), (color).blue(), (color).alpha()).c_str()) QPainterPath makeHBracePath(double x, double ybrace, double width, double bw, double cubicshrink=0.5, double cubiccontrolfac=0.3) { double xl1=x-(width)*cubicshrink+bw*cubicshrink; double xr2=x+(width)*cubicshrink-bw*cubicshrink; double xl2=x-bw*cubicshrink; double xr1=x+bw*cubicshrink; QPainterPath path; path.moveTo(xl1-bw*cubicshrink, ybrace-bw*cubicshrink); path.cubicTo(xl1-bw*cubicshrink, ybrace-bw*cubicshrink+bw*cubiccontrolfac, xl1-bw*cubiccontrolfac, ybrace, xl1, ybrace); path.lineTo(xl2, ybrace); path.cubicTo(xl2+bw*cubiccontrolfac, ybrace, (xl2+xr1)/2.0, ybrace+bw*cubicshrink-bw*cubiccontrolfac, (xl2+xr1)/2.0, ybrace+bw*cubicshrink); path.cubicTo((xl2+xr1)/2.0, ybrace+bw*cubicshrink-bw*cubiccontrolfac, xr1-bw*cubiccontrolfac, ybrace, xr1, ybrace); path.lineTo(xr2, ybrace); path.cubicTo(xr2+bw*cubiccontrolfac, ybrace, xr2+bw*cubicshrink, ybrace-bw*cubicshrink+bw*cubiccontrolfac, xr2+bw*cubicshrink, ybrace-bw*cubicshrink); return path; } QPainterPath makeArrow(double x, double y, double width, double arrowW, bool left=false, bool right=true) { double x1=x; double x2=x+width; double x3=x2-arrowW/2.0; double y3u=y-arrowW/2.0; double y3d=y+arrowW/2.0; double x3l=x+arrowW/2.0; QPainterPath path; path.moveTo(x1, y); path.lineTo(x2, y); if (right) { path.moveTo(x3, y3u); path.lineTo(x2, y); path.lineTo(x3, y3d); } if (left) { path.moveTo(x3l, y3u); path.lineTo(x1, y); path.lineTo(x3l, y3d); } return path; } QPainterPath makeDArrow(double x, double y, double width, double arrowW, bool left=false, bool right=true) { double x1=x; double x2=x+width; double dx=arrowW/4.0; double y1=y-dx; double y2=y+dx; double x3=x2-arrowW/2.0; double y3u=y-arrowW/2.0; double y3d=y+arrowW/2.0; double x3l=x+arrowW/2.0; QPainterPath path; path.moveTo(x1+dx, y1); path.lineTo(x2-dx, y1); path.moveTo(x1+dx, y2); path.lineTo(x2-dx, y2); if (right) { path.moveTo(x3, y3u); path.lineTo(x2, y); path.lineTo(x3, y3d); } if (left) { path.moveTo(x3l, y3u); path.lineTo(x1, y); path.lineTo(x3l, y3d); } return path; } // -------------------------------------------------------------------------------------------------- // -- implementation of the MTnode's methods // -------------------------------------------------------------------------------------------------- JKQTmathText::MTenvironment::MTenvironment() { color=QColor("black"); font=MTEroman; fontSize=10; bold=false; italic=false; smallCaps=false; underlined=false; overline=false; strike=false; insideMath=false; } QFont JKQTmathText::MTenvironment::getFont(JKQTmathText* parent) const { QFont f; switch (font) { case MTEsans: if (insideMath) f.setFamily(parent->get_fontMathSans()); else f.setFamily(parent->get_fontSans()); break; case MTEtypewriter: f.setFamily(parent->get_fontTypewriter()); break; case MTEscript: f.setFamily(parent->get_fontScript()); break; case MTEroman: if (insideMath) f.setFamily(parent->get_fontMathRoman()); else f.setFamily(parent->get_fontRoman()); break; case MTEcaligraphic: f.setFamily(parent->get_fontCaligraphic()); break; case MTEblackboard: f.setFamily(parent->get_fontBlackboard()); break; }; f.setBold(bold); f.setItalic(italic); f.setUnderline(underlined); f.setOverline(overline); f.setStrikeOut(strike); f.setCapitalization(QFont::MixedCase); if (smallCaps) f.setCapitalization(QFont::SmallCaps); f.setPointSizeF(fontSize); f.setStyleStrategy(QFont::NoFontMerging); return f; } QString JKQTmathText::MTenvironment::toHtmlStart(MTenvironment defaultEv) const { QString s; s=s+"font-size: "+QLocale::c().toString(fontSize)+"pt; "; if (insideMath) { if (defaultEv.italic) { if (!italic) s=s+"font-style: italic; "; if (italic) s=s+"font-style: normal; "; } else { if (!italic) s=s+"font-style: italic; "; } } else { if (!defaultEv.italic && italic) s=s+"font-style: italic; "; } if (bold && !defaultEv.bold) s=s+"font-weight: bold"; QStringList td; if (underlined && !defaultEv.underlined) td<<"underline"; if (overline && !defaultEv.overline) td<<"overline"; if (strike && !defaultEv.strike) td<<"line-through"; if (td.size()>0) s=s+"text-decoration: "+td.join(", "); return ""; } QString JKQTmathText::MTenvironment::toHtmlAfter(JKQTmathText::MTenvironment /*defaultEv*/) const { return ""; } JKQTmathText::MTnode::MTnode(JKQTmathText* parent) { this->parent=parent; drawBoxes=false; } void JKQTmathText::MTnode::getSize(QPainter &painter, JKQTmathText::MTenvironment currentEv, double &width, double &baselineHeight, double &overallHeight, double &strikeoutPos) { double w=width, b=baselineHeight, o=overallHeight, s=strikeoutPos; getSizeInternal(painter, currentEv, w, b, o, s); if (w<1e5) width=w; if (b<1e5) baselineHeight=b; if (o<1e5) overallHeight=o; if (s<1e5) strikeoutPos=s; } bool JKQTmathText::MTnode::toHtml(QString &/*html*/, JKQTmathText::MTenvironment /*currentEv*/, JKQTmathText::MTenvironment /*defaultEv*/) { return false; } void JKQTmathText::MTnode::doDrawBoxes(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { if (drawBoxes) { painter.save(); double w, oh, bh, sp; getSize(painter, currentEv, w, bh, oh, sp); QPen p=painter.pen(); p.setColor("lightcoral"); p.setWidthF(0.5); painter.setPen(p); QRectF r(x, y-bh, w, oh); painter.drawRect(r); p.setColor("lightblue"); painter.setPen(p); if (w>0) painter.drawLine(QLineF(x, y, x+w, y)); p.setColor("green"); painter.setPen(p); painter.drawEllipse(x-3.0,y-3.0,6.0,6.0); p.setColor("lightgreen"); painter.setPen(p); painter.drawLine(x-2.0, y, x+2.0, y); painter.drawLine(x, y-2, x, y+2.0); painter.restore(); } } JKQTmathText::MTtextNode::MTtextNode(JKQTmathText* parent, QString textIn, bool addWhitespace, bool stripInnerWhitepace): JKQTmathText::MTnode(parent) { QString text=textIn; if (stripInnerWhitepace) { text=""; for (int i=0; itext=text; // strip all whitespace from left while (this->text.size()>1 && this->text[0].isSpace()) { this->text=this->text.right(this->text.size()-1); } if (addWhitespace /*&& (this->text.size()>0)*/ && (!this->text[this->text.size()-1].isSpace())) this->text=this->text+" "; //qDebug()<<"MTtextNode( text="< this->text="<text<<"]"; } JKQTmathText::MTtextNode::~MTtextNode() { } void JKQTmathText::MTtextNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { QFont f=currentEv.getFont(parent); if (currentEv.insideMath && (text=="(" || text=="[" || text=="|" || text=="]" || text==")" || text=="<" || text==">" || text==QString(QChar(0x2329)) || text==QString(QChar(0x232A)) || text==QString(QChar(0x2308)) || text==QString(QChar(0x2309)) || text==QString(QChar(0x230A)) || text==QString(QChar(0x230B)))) { f.setItalic(false); f.setFamily(parent->get_fontBraces()); } QString txt=textTransform(text, currentEv, true); QFontMetricsF fm(f, painter.device()); QRectF br=fm.boundingRect(txt); QRectF tbr=parent->getTBR(f, txt, painter.device()); //fm.tightBoundingRect(txt); if (txt=="|") { br=fm.boundingRect("X"); tbr=QRect(0,0,fm.width("X"), fm.ascent());//fm.boundingRect("X"); br.setWidth(0.7*br.width()); } width=br.width();//width(text); if (txt.size()>0) { if (txt[0].isSpace() /*&& br.width()<=0*/) width=width+fm.boundingRect("I").width(); if (txt.size()>1 && txt[txt.size()-1].isSpace() /*&& (fm.boundingRect("a ").width()==fm.boundingRect("a").width())*/) width=width+fm.width("I"); } //qDebug()<<"text: "<" || text==QString(QChar(0x2329)) || text==QString(QChar(0x232A)) || text==QString(QChar(0x2308)) || text==QString(QChar(0x2309)) || text==QString(QChar(0x230A)) || text==QString(QChar(0x230B)))) { f.setItalic(false); f.setFamily(parent->get_fontBraces()); } if (onlyDigits && currentEv.insideMath) { f.setItalic(false); } painter.setFont(f); QPen p=painter.pen(); p.setColor(currentEv.color); painter.setPen(p); double dx=0; QFontMetricsF fm(f, painter.device()); /*if (txt.size()>1 && txt[txt.size()-1].isSpace()) { QFontMetricsF fm(f, painter.device()); //if ((fm.width("a ")==fm.width("a"))) dx=fm.boundingRect("I").width(); }*/ if (!hasDigits || !f.italic()) { painter.drawText(QPointF(x+dx, y), txt);//.simplified()); } else { int i=0; double xx=x+dx; QFont ff=f; QFontMetricsF fmff(ff, painter.device()); ff.setItalic(false); while (iget_fontEncoding()==MTFEunicode) { if (currentEv.insideMath) { txt=""; for (int i=0; i': txt+=QString(QString(" > ")); break; case '=': txt+=QString(QString(" = ")); break; case ';': txt+=QString(QString("; ")); break; default: txt+=c; break; } } txt=txt.replace(" ", " "); } } if (currentEv.font==MTEblackboard && parent->get_fontEncoding()==MTFEunicode) { txt=""; for (int i=0; iget_fontEncoding()==MTFEunicode) { txt=""; for (int i=0; iname=name; this->child=child; this->parameters=parameters; JKQTmathText::MTenvironment ev; if (!setupMTenvironment(ev)) { parent->error_list.append(tr("unknown instruction '%1' found!").arg(name)); } } JKQTmathText::MTinstruction1Node::~MTinstruction1Node() { if (child!=nullptr) delete child; } QString JKQTmathText::MTinstruction1Node::getTypeName() const { return QLatin1String("MTinstruction1Node(")+name+")"; } void JKQTmathText::MTinstruction1Node::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { JKQTmathText::MTenvironment ev=currentEv; setupMTenvironment(ev); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); if (name=="colorbox" || name=="fbox" || name=="boxed") { QFontMetricsF fm(ev.getFont(parent)); double xw=fm.width("x"); width+=xw; overallHeight+=xw; baselineHeight+=xw/2.0; } } double JKQTmathText::MTinstruction1Node::draw(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { doDrawBoxes(painter, x, y, currentEv); JKQTmathText::MTenvironment ev=currentEv; setupMTenvironment(ev); QPen oldPen=painter.pen(); double shiftX=0; if (name=="colorbox" || name=="fbox" || name=="boxed") { QColor fcol=currentEv.color; if (name=="colorbox") fcol=QColor(parameters.value(0, ev.color.name())); //qDebug()<<"COLOR="<getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); QPen p=painter.pen(); QFontMetricsF fm(currentEv.getFont(parent)); double xw=fm.width("x"); p.setColor(fcol); painter.setPen(p); painter.drawRect(x,y-baselineHeight-xw/2,width+xw,overallHeight+xw); shiftX=xw/2.0; } double xnew= child->draw(painter, x+shiftX, y, ev); painter.setPen(oldPen); return xnew; } bool JKQTmathText::MTinstruction1Node::toHtml(QString &html, JKQTmathText::MTenvironment currentEv, JKQTmathText::MTenvironment defaultEv) { JKQTmathText::MTenvironment ev=currentEv; setupMTenvironment(ev); return child->toHtml(html, ev, defaultEv); } void JKQTmathText::MTinstruction1Node::set_drawBoxes(bool draw) { drawBoxes=draw; child->set_drawBoxes(draw); } bool JKQTmathText::MTinstruction1Node::setupMTenvironment(JKQTmathText::MTenvironment &ev) { if (name=="bf" || name=="textbf" || name=="mathbf") ev.bold=true; else if (name=="em") ev.italic=!ev.italic; else if (name=="it" || name=="textit" || name=="mathit") ev.italic=true; else if (name=="textcolor" || name=="mathcolor" || name=="color") ev.color=QColor(parameters.value(0, ev.color.name())); else if (name=="equation") { ev.italic=true; ev.insideMath=true; } else if (name=="sc" || name=="textsc" || name=="mathsc") ev.smallCaps=true; else if (name=="ul" || name=="underline" || name=="underlined") ev.underlined=true; else if (name=="ol" || name=="overline" || name=="overlined") ev.overline=true; else if (name=="strike") ev.strike=true; else if (name=="rm" || name=="textrm") { ev.font=JKQTmathText::MTEroman; } else if (name=="mathrm" || name=="text" || name=="mbox" || name=="operatorname") { ev.font=JKQTmathText::MTEroman; ev.italic=false; } else if (name=="mat") { ev.font=JKQTmathText::MTEroman; ev.italic=false; ev.bold=true; } else if (name=="cal" || name=="textcal" || name=="mathcal") { ev.font=JKQTmathText::MTEcaligraphic; } else if (name=="bb" || name=="textbb" || name=="mathbb") { ev.font=JKQTmathText::MTEblackboard; } else if (name=="tt" || name=="texttt" || name=="mathtt") { ev.font=JKQTmathText::MTEtypewriter; } else if (name=="sf" || name=="textsf" || name=="mathsf") { ev.font=JKQTmathText::MTEsans; } else if (name=="script" || name=="textscript" || name=="mathscript") { ev.font=JKQTmathText::MTEscript; } else if (name=="displaystyle") { ev.fontSize=ev.fontSize/0.8; } else if (name=="scriptstyle") { ev.fontSize=ev.fontSize*0.8; } else if (name=="scriptscriptstyle") { ev.fontSize=ev.fontSize*0.8*0.8; } else { return false; } return true; } JKQTmathText::MTsubscriptNode::MTsubscriptNode(JKQTmathText* parent, MTnode* child): JKQTmathText::MTnode(parent) { this->child=child; } JKQTmathText::MTsubscriptNode::~MTsubscriptNode() { if (child!=nullptr) delete child; } void JKQTmathText::MTsubscriptNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { JKQTmathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->get_subsuper_size_factor(); QFontMetricsF fm(ev.getFont(parent), painter.device()); double shift=parent->get_sub_shift_factor()*parent->getTBR(ev.getFont(parent), "M", painter.device()).height(); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); QFontMetricsF fmouter(currentEv.getFont(parent), painter.device()); QRectF tbr=parent->getTBR(currentEv.getFont(parent), "M", painter.device()); overallHeight=tbr.height()+shift+(overallHeight-baselineHeight); baselineHeight=tbr.height(); strikeoutPos=fmouter.strikeOutPos(); if (currentEv.italic) width=width-double(fm.width(' '))*parent->get_italic_correction_factor(); } double JKQTmathText::MTsubscriptNode::draw(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { doDrawBoxes(painter, x, y, currentEv); JKQTmathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->get_subsuper_size_factor(); QFontMetricsF fm(ev.getFont(parent), painter.device()); double shift=parent->get_sub_shift_factor()*parent->getTBR(ev.getFont(parent), "M", painter.device()).height(); double xx=x; if (currentEv.italic) xx=xx-double(fm.width(' '))*parent->get_italic_correction_factor(); return child->draw(painter, xx, y+shift, ev);//+0.5*fm.boundingRect("A").width(); } bool JKQTmathText::MTsubscriptNode::isSubOrSuper() { return true; } QString JKQTmathText::MTsubscriptNode::getTypeName() const { return "MTsubscriptNode"; } bool JKQTmathText::MTsubscriptNode::toHtml(QString &html, JKQTmathText::MTenvironment currentEv, JKQTmathText::MTenvironment defaultEv) { html=html+""; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+""; return ok; } void JKQTmathText::MTsubscriptNode::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(draw); } JKQTmathText::MTsqrtNode::MTsqrtNode(JKQTmathText* parent, MTnode* child, int degree): JKQTmathText::MTnode(parent) { this->child=child; this->degree=degree; } JKQTmathText::MTsqrtNode::~MTsqrtNode() { if (child!=nullptr) delete child; } void JKQTmathText::MTsqrtNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { QFontMetricsF fm(currentEv.getFont(parent), painter.device()); child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); overallHeight=overallHeight*1.2;//+fm.ascent()*0.1; baselineHeight=baselineHeight*1.2;//+fm.ascent()*0.1; width=width+fm.boundingRect("A").width()*2; // 1.53 } double JKQTmathText::MTsqrtNode::draw(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { doDrawBoxes(painter, x, y, currentEv); double width=0, baselineHeight=0, overallHeight=0, sp=0; child->getSize(painter, currentEv, width, baselineHeight, overallHeight, sp); QFont f=currentEv.getFont(parent); QFont fsmall=f; QFontMetricsF fm(f, painter.device()); double w=fm.boundingRect("A").width(); double a=baselineHeight*1.15; double d=overallHeight-baselineHeight; //painter.save(); QPen p=painter.pen(); p.setColor(currentEv.color); p.setWidthF(qMax(JKQTMATHTEXT_ABS_MIN_LINEWIDTH,ceil(currentEv.fontSize/16.0))); //painter.setPen(p); QPainterPath path; if (w>0) { path.moveTo(x+0.1*w, y-0.4*a); path.lineTo(x+0.33*w, y-0.4*a); path.lineTo( x+0.66*w, y+0.5*d); path.lineTo(x+w, y-a); } if (degree!=2) { fsmall.setPointSizeF(fsmall.pointSizeF()/2.0); fsmall.setItalic(false); painter.setFont(fsmall); painter.drawText(QPointF(x+0.33*w, y-0.55*a), QLocale::c().toString(degree)); } //painter.restore(); double xnew=child->draw(painter, x+1.2*w, y, currentEv); painter.save(); painter.setPen(p); if (w>0) { path.lineTo( xnew+0.2*w, y-a); path.lineTo(xnew+0.2*w, y-0.8*a); painter.drawPath(path); } painter.restore(); return xnew+0.33*w; } bool JKQTmathText::MTsqrtNode::toHtml(QString &html, JKQTmathText::MTenvironment currentEv, JKQTmathText::MTenvironment defaultEv) { html=html+"√"; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+" "; return ok; } void JKQTmathText::MTsqrtNode::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(draw); } QString JKQTmathText::MTsqrtNode::getTypeName() const { return "MTsqrtNode"; } JKQTmathText::MTfracNode::MTfracNode(JKQTmathText* parent, MTnode* child_top, MTnode* child_bottom, MTfracMode mode): JKQTmathText::MTnode(parent) { this->child1=child_top; this->child2=child_bottom; this->mode=mode; } JKQTmathText::MTfracNode::~MTfracNode() { if (child1!=nullptr) delete child1; if (child2!=nullptr) delete child2; } QString JKQTmathText::MTfracNode::getTypeName() const { return "MTfracNode"; } void JKQTmathText::MTfracNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { QFontMetricsF fm(currentEv.getFont(parent), painter.device()); JKQTmathText::MTenvironment ev1=currentEv; JKQTmathText::MTenvironment ev2=currentEv; double xh=fm.xHeight(); //tightBoundingRect("x").height(); double sp=xh; double Ah=parent->getTBR(currentEv.getFont(parent), "M", painter.device()).height();//fm.ascent(); double xw=fm.boundingRect("x").width(); if (mode==MTFMunderbrace || mode==MTFMoverbrace) { ev2.fontSize=ev2.fontSize*parent->get_underbrace_factor(); } else if (mode==MTFMunderset || mode==MTFMoverset) { ev2.fontSize=ev2.fontSize*parent->get_underset_factor(); } else if (mode==MTFMfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor(); ev2.fontSize=ev2.fontSize*parent->get_frac_factor(); } else if (mode==MTFMtfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor()*0.7; ev2.fontSize=ev2.fontSize*parent->get_frac_factor()*0.7; } double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos1=0; double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos2=0; child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos1); child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos2); overallHeight=0; baselineHeight=0; width=0; if (mode==MTFMfrac || mode==MTFMdfrac || mode==MTFMtfrac) { //std::cout<<"\nxh="< baselineHeight="<getTBR(f, "M", painter.device()).height();//fm.ascent(); double bw=Ah/2.0; if (mode==MTFMunderbrace || mode==MTFMoverbrace) { ev2.fontSize=ev2.fontSize*parent->get_underbrace_factor(); } else if (mode==MTFMunderset || mode==MTFMoverset) { ev2.fontSize=ev2.fontSize*parent->get_underset_factor(); } else if (mode==MTFMfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor(); ev2.fontSize=ev2.fontSize*parent->get_frac_factor(); } else if (mode==MTFMtfrac) { ev1.fontSize=ev1.fontSize*parent->get_frac_factor()*0.7; ev2.fontSize=ev2.fontSize*parent->get_frac_factor()*0.7; } double width1=0, baselineHeight1=0, overallHeight1=0;//, strikeoutPos1=0; double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos=0; child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos); child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos); double ascent1=baselineHeight1; double descent1=overallHeight1-baselineHeight1; double ascent2=baselineHeight2; double descent2=overallHeight2-baselineHeight2; double yline=y-xh*0.5; //double overallHeight=overallHeight1+overallHeight2+xh; //double baselineHeight=3.0*xh/2.0+overallHeight1; double width=qMax(width1, width2); QPen p=painter.pen(); p.setColor(ev1.color); p.setStyle(Qt::SolidLine); p.setWidthF(qMax(JKQTMATHTEXT_ABS_MIN_LINEWIDTH, lw)); painter.save(); painter.setPen(p); if (mode==MTFMfrac || mode==MTFMdfrac || mode==MTFMtfrac) { QLineF l(x+xw/4.0, yline, x+width+xw/2.0, yline); if (l.length()>0) painter.drawLine(l); child1->draw(painter, x+xw/2.0+(width-width1)/2.0, yline-xh*(parent->get_frac_shift_factor())-descent1, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->get_frac_shift_factor())+ascent2, ev2); } else if (mode==MTFMstackrel) { child1->draw(painter, x+xw/2.0+(width-width1)/2.0, yline-xh*(parent->get_frac_shift_factor())-descent1, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, yline+xh*(parent->get_frac_shift_factor())+ascent2, ev2); } else if (mode==MTFMunderset) { child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y+descent1+xh/6.0+ascent2, ev2); } else if (mode==MTFMunderbrace) { double ybrace=y+descent1+bw/2.0; QPainterPath path=makeHBracePath(x+xw/2.0+(width1)/2.0, ybrace, width, bw); painter.drawPath(path); child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y+descent1+bw+ascent2, ev2); } else if (mode==MTFMoverset) { child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y-ascent1-xh/6.0-descent2, ev2); } else if (mode==MTFMoverbrace) { double ybrace=y-ascent1-bw/2.0; painter.save(); painter.translate(x+xw/2.0+(width1)/2.0, ybrace); painter.rotate(180); QPainterPath path=makeHBracePath(0,0, width, bw); painter.drawPath(path); painter.restore(); child1->draw(painter, x+xw/2.0+(width-width1)/2.0, y, ev1); child2->draw(painter, x+xw/2.0+(width-width2)/2.0, y-ascent1-bw-descent2, ev2); } painter.restore(); if (mode==MTFMstackrel) return x+width+ xw; return x+width+xw; } bool JKQTmathText::MTfracNode::toHtml(QString &/*html*/, JKQTmathText::MTenvironment /*currentEv*/, JKQTmathText::MTenvironment /*defaultEv*/) { bool ok=false; return ok; } void JKQTmathText::MTfracNode::set_drawBoxes(bool draw) { this->drawBoxes=draw; child1->set_drawBoxes(draw); child2->set_drawBoxes(draw); } JKQTmathText::MTmatrixNode::MTmatrixNode(JKQTmathText* parent, QVector > children): JKQTmathText::MTnode(parent) { this->lines=children.size(); this->columns=0; for (int i=0; ithis->columns) this->columns=children[i].size(); } this->children=children; } JKQTmathText::MTmatrixNode::~MTmatrixNode() { for (int i=0; iget_frac_factor(); QVector colwidth, rowheight; //QVector > widths, heights, baselines; double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos1=0; //widths.resize(lines); colwidth.resize(columns); for (int i=0; igetSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos1); /*widths[i].operator[](j)=width1; baselines[i].operator[](j)=baselineHeight; heights[i].operator[](j)=overallHeight1;*/ if (overallHeight1>rowheight[i]) rowheight[i]=overallHeight1; if (width1>colwidth[j]) colwidth[j]=width1; } } overallHeight=(lines-1)*xw/2.0; width=columns*xw; for (int i=0; iget_frac_factor(); QVector colwidth, rowheight, rowascent; //QVector > widths, heights, baselines; double width1=0, baselineHeight1=0, overallHeight1=0, strikeoutPos=0; //widths.resize(lines); colwidth.resize(columns); for (int i=0; igetSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos); /*widths[i].operator[](j)=width1; baselines[i].operator[](j)=baselineHeight; heights[i].operator[](j)=overallHeight1;*/ if (overallHeight1>rowheight[i]) rowheight[i]=overallHeight1; if (baselineHeight1>rowascent[i]) rowascent[i]=baselineHeight1; if (width1>colwidth[j]) colwidth[j]=width1; } } double overallHeight=(lines-1)*xw/2.0; double width=(columns)*xw; for (int i=0; i0) yy=yy+rowascent[0]; for (int i=0; idraw(painter, xx, yy, ev1); xx=xx+colwidth[j]+xw; } if (idrawBoxes=draw; for (int i=0; iset_drawBoxes(draw); } } } JKQTmathText::MTdecoratedNode::MTdecoratedNode(JKQTmathText* parent, MTdecoration decoration, MTnode* child): JKQTmathText::MTnode(parent) { this->child=child; this->decoration=decoration; } JKQTmathText::MTdecoratedNode::~MTdecoratedNode() { if (child!=nullptr) delete child; } void JKQTmathText::MTdecoratedNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { QFontMetricsF fm(currentEv.getFont(parent), painter.device()); double wc=fm.boundingRect("A").width(); double dheightfactor=1.0+parent->get_decoration_height_factor()*2.0; child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); overallHeight=overallHeight*dheightfactor; baselineHeight=baselineHeight*dheightfactor; width=width+0.3*wc; } double JKQTmathText::MTdecoratedNode::draw(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { doDrawBoxes(painter, x, y, currentEv); MTenvironment ev=currentEv; double width=0, baselineHeight=0, overallHeight=0, strikeoutPos=0; child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); QFontMetricsF fm(ev.getFont(parent), painter.device()); double w=width; double wc=fm.boundingRect("A").width(); //double ll=wc*0.8; double a=baselineHeight; //double d=overallHeight-baselineHeight; double dheightfactor=parent->get_decoration_height_factor(); double dpos=y-a*(1.0+dheightfactor); double dposb=y+qMax((overallHeight-baselineHeight)*(1.0+dheightfactor), fm.xHeight()*dheightfactor); double deltax=0;//(wc-ll)/2.0; double dheight=dheightfactor*a; if (ev.italic) deltax+=0.1*fm.boundingRect("A").width(); QPen pold=painter.pen(); QPen p=pold; p.setColor(ev.color); p.setWidthF(qMax(JKQTMATHTEXT_ABS_MIN_LINEWIDTH, fm.lineWidth()));//ceil(currentEv.fontSize/16.0)); if (decoration==MTDbar) ev.overline=true; double xnew=child->draw(painter, x, y, ev); if (decoration==MTDvec) { painter.setPen(p); QPolygonF poly; poly<0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDdoubleoverline) { painter.setPen(p); QLineF l(x+deltax, dpos, xnew+deltax-0.2*wc, dpos); if (l.length()>0) painter.drawLine(l); l=QLineF(x+deltax, dpos-2.0*p.widthF(), xnew+deltax-0.2*wc, dpos-2.0*p.widthF()); if (l.length()>0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDunderline) { painter.setPen(p); QLineF l(x+deltax, dposb, xnew+deltax-0.2*wc, dposb); if (l.length()>0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDdoubleunderline) { painter.setPen(p); QLineF l(x+deltax, dposb, xnew+deltax-0.2*wc, dposb); if (l.length()>0) painter.drawLine(l); l=QLineF(x+deltax, dposb+2.0*p.widthF(), xnew+deltax-0.2*wc, dposb+2.0*p.widthF()); if (l.length()>0) painter.drawLine(l); painter.setPen(pold); } else if (decoration==MTDarrow) { painter.setPen(p); QLineF l(x+deltax, dpos+dheight/2.0, xnew+deltax-0.2*wc, dpos+dheight/2.0); if (l.length()>0) painter.drawLine(l); QPolygonF poly; poly<toHtml(html, ev, defaultEv); return false; } void JKQTmathText::MTdecoratedNode::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(draw); } QString JKQTmathText::MTdecoratedNode::getTypeName() const { return "MTdecoratedNode"; } JKQTmathText::MTsuperscriptNode::MTsuperscriptNode(JKQTmathText* parent, MTnode* child): JKQTmathText::MTnode(parent) { this->child=child; } JKQTmathText::MTsuperscriptNode::~MTsuperscriptNode() { if (child!=nullptr) delete child; } void JKQTmathText::MTsuperscriptNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { JKQTmathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->get_subsuper_size_factor(); QFontMetricsF fm(currentEv.getFont(parent), painter.device()); child->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); double shift=0;//parent->get_super_shift_factor()*fm.ascent(); overallHeight=overallHeight+shift; strikeoutPos=fm.strikeOutPos(); if (currentEv.italic) width=width+double(fm.width(' '))*parent->get_italic_correction_factor(); } double JKQTmathText::MTsuperscriptNode::draw(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { doDrawBoxes(painter, x, y, currentEv); JKQTmathText::MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->get_subsuper_size_factor(); double cwidth, cbaselineHeight, coverallheight, cStrikeoutPos; child->getSize(painter, ev, cwidth, cbaselineHeight, coverallheight, cStrikeoutPos); QFontMetricsF fm(currentEv.getFont(parent), painter.device()); double shift=0;//parent->get_super_shift_factor()*fm.ascent(); //double shift=ev.; double xx=x; if (currentEv.italic) xx=xx+double(fm.width(' '))*parent->get_italic_correction_factor(); return child->draw(painter, xx, y-shift, ev);//+0.5*fm.boundingRect("A").width(); } bool JKQTmathText::MTsuperscriptNode::isSubOrSuper() { return true; } QString JKQTmathText::MTsuperscriptNode::getTypeName() const { return "MTsuperscriptNode"; } bool JKQTmathText::MTsuperscriptNode::toHtml(QString &html, JKQTmathText::MTenvironment currentEv, JKQTmathText::MTenvironment defaultEv) { html=html+""; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+""; return ok; } void JKQTmathText::MTsuperscriptNode::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(draw); } JKQTmathText::MTbraceNode::MTbraceNode(JKQTmathText* parent, QString openbrace, QString closebrace, MTnode* child, bool showRightBrace): JKQTmathText::MTnode(parent) { this->child=child; this->openbrace=openbrace; this->closebrace=closebrace; this->showRightBrace=showRightBrace; } JKQTmathText::MTbraceNode::~MTbraceNode() { if (child!=nullptr) delete child; } void JKQTmathText::MTbraceNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { JKQTmathText::MTenvironment ev=currentEv; child->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); double bracewidth=0, braceheight=0; getBraceWidth(painter, ev, baselineHeight, overallHeight, bracewidth, braceheight); bracewidth=bracewidth/parent->get_brace_shrink_factor(); baselineHeight=/*qMin(baselineHeight, braceheight)*/ baselineHeight*parent->get_brace_factor(); overallHeight=qMax(overallHeight, braceheight)*parent->get_brace_factor(); //fm.height(); width=width+bracewidth*2.0; } double JKQTmathText::MTbraceNode::draw(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { //std::cout<<"drawing brace-node: '"<getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); double bracewidth=0, braceheight=0; getBraceWidth(painter, ev, baselineHeight, overallHeight, bracewidth, braceheight); double cwidth=0; double cbaselineHeight=0; double coverallHeight=0, cstrikeoutPos=0; getSize(painter, currentEv, cwidth, cbaselineHeight, coverallHeight, cstrikeoutPos); double lw=qMax(0.25,ceil(currentEv.fontSize/12.0));//fm.lineWidth(); double xnew=x+lw; QPen pold=painter.pen(); QPen p=pold; p.setWidthF(lw); p.setColor(currentEv.color); painter.setPen(p); double brace_fraction=0.85; if (openbrace=="(") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.cubicTo(xnew, (y1+y2)/2.0+fabs(y1-y2)/6.0, xnew, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } else if (openbrace=="[") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.lineTo(xnew+lw/2.0, y1); path.lineTo(xnew+lw/2.0, y2); path.lineTo(xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } else if (openbrace=="{") { QPainterPath path=makeHBracePath(0,0,coverallHeight, bracewidth*brace_fraction); painter.save(); painter.translate(xnew+bracewidth*(1.0-brace_fraction), y-cbaselineHeight+coverallHeight/2.0); painter.rotate(90); painter.drawPath(path); painter.restore(); } else if (openbrace=="_") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.lineTo(xnew, y1); path.lineTo(xnew, y2); painter.drawPath(path); } else if (openbrace=="~") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew, y1); path.lineTo(xnew, y2); path.lineTo(xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } else if (openbrace=="|") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; QLineF l(xnew+brace_fraction*bracewidth, y1, xnew+brace_fraction*bracewidth, y2); if (l.length()>0) painter.drawLine(l); painter.drawPath(path); } else if (openbrace=="#" || openbrace=="||") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; QLineF l(xnew+brace_fraction*bracewidth, y1, xnew+brace_fraction*bracewidth, y2); if (l.length()>0) painter.drawLine(l); l=QLineF(xnew+brace_fraction*bracewidth-1.5*lw, y1, xnew+brace_fraction*bracewidth-1.5*lw, y2); if (l.length()>0) painter.drawLine(l); } else if (openbrace=="<") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+brace_fraction*bracewidth, y1); path.lineTo(xnew, (y2+y1)/2.0); path.lineTo(xnew+brace_fraction*bracewidth, y2); painter.drawPath(path); } painter.setPen(pold); xnew= child->draw(painter, xnew+bracewidth/parent->get_brace_shrink_factor()-lw, y, currentEv)+lw; if (showRightBrace) { painter.setPen(p); if (closebrace==")") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.cubicTo(xnew+bracewidth, (y1+y2)/2.0+fabs(y1-y2)/6.0, xnew+bracewidth, (y1+y2)/2.0-fabs(y1-y2)/6.0 , xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } else if (closebrace=="]") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.lineTo(xnew+bracewidth-lw/2.0, y1); path.lineTo(xnew+bracewidth-lw/2.0, y2); path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } else if (closebrace=="}") { QPainterPath path=makeHBracePath(0,0,coverallHeight, bracewidth*brace_fraction); painter.save(); painter.translate(xnew+bracewidth*brace_fraction, y-cbaselineHeight+coverallHeight/2.0); painter.rotate(270); painter.drawPath(path); painter.restore(); } else if (closebrace=="_") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.lineTo(xnew+bracewidth, y1); path.lineTo(xnew+bracewidth, y2); painter.drawPath(path); } else if (closebrace=="~") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+bracewidth, y1); path.lineTo(xnew+bracewidth, y2); path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } else if (closebrace=="|") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; QLineF l(xnew+(1.0-brace_fraction)*bracewidth, y1, xnew+(1.0-brace_fraction)*bracewidth, y2); if (l.length()>0) painter.drawLine(l); painter.drawPath(path); } else if (closebrace=="#" || closebrace=="||") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; QLineF l(xnew+(1.0-brace_fraction)*bracewidth, y1, xnew+(1.0-brace_fraction)*bracewidth, y2); if (l.length()>0) painter.drawLine(l); l=QLineF(xnew+(1.0-brace_fraction)*bracewidth+1.5*lw, y1, xnew+(1.0-brace_fraction)*bracewidth+1.5*lw, y2); if (l.length()>0) painter.drawLine(l); } else if (closebrace==">") { QPainterPath path; double y1=y+(coverallHeight-cbaselineHeight); double y2=y-cbaselineHeight; path.moveTo(xnew+(1.0-brace_fraction)*bracewidth, y1); path.lineTo(xnew+bracewidth, (y2+y1)/2.0); path.lineTo(xnew+(1.0-brace_fraction)*bracewidth, y2); painter.drawPath(path); } painter.setPen(pold); } //qDebug()<<" ==> "<get_brace_shrink_factor()-lw; } bool JKQTmathText::MTbraceNode::toHtml(QString &html, JKQTmathText::MTenvironment currentEv, JKQTmathText::MTenvironment defaultEv) { QString ob=openbrace; QString cb=closebrace; if (ob=="<") ob="⟨"; else if (ob=="_") ob="⌊"; else if (ob=="~") ob="⌈"; else if (ob=="||" || ob=="#") ob="||"; if (cb=="<") cb="⟩"; else if (cb=="_") cb="⌋"; else if (cb=="~") cb="⌉"; else if (cb=="||" || cb=="#") cb="||"; html=html+ob; bool ok=child->toHtml(html, currentEv, defaultEv); html=html+cb; return ok; } void JKQTmathText::MTbraceNode::set_drawBoxes(bool draw) { this->drawBoxes=draw; child->set_drawBoxes(draw); } QString JKQTmathText::MTbraceNode::getTypeName() const { return QLatin1String("MTbraceNode(")+openbrace+" "+closebrace+")"; } void JKQTmathText::MTbraceNode::getBraceWidth(QPainter &/*painter*/, JKQTmathText::MTenvironment ev, double /*baselineHeight*/, double overallHeight, double &bracewidth, double &braceheight) { /*QFont evf=ev.getFont(parent); if (ev.insideMath) evf.setItalic(false); ev.italic=false; while (ev.fontSize<10*parent->get_fontSize()) { const QFontMetricsF fme(evf, painter.device()); if (fme.ascent()>overallHeight) break; ev.fontSize+=0.5; evf.setPointSizeF(ev.fontSize); } ev.fontSize=ev.fontSize*parent->get_brace_factor(); evf.setPointSizeF(ev.fontSize); QFontMetricsF fm(evf, painter.device()); QString bc="_X"; bracewidth=fm.width("I")*parent->get_brace_shrink_factor(); braceheight=parent->getTBR(evf, bc, painter.device()).height();*/ double lw=qMax(0.25,ceil(ev.fontSize/12.0)); braceheight=overallHeight*parent->get_brace_factor(); bracewidth=0.6*pow(braceheight, 0.6); if (openbrace=="{" || closebrace=="}") bracewidth=qMax(bracewidth, lw*3.5); } JKQTmathText::MTlistNode::MTlistNode(JKQTmathText* parent): JKQTmathText::MTnode(parent) { nodes.clear(); // these operations cause sub/sup script to be typeset over/under the operator, not right besides! subsupOperations<<"sum"<<"prod"<<"coprod" <<"bigcap"<<"bigcup"<<"bigvee"<<"bighat" <<"int"<<"iint"<<"iiint"<<"oint"<<"oiint"<<"oiiint" <<"max"<<"min"<<"argmax"<<"argmin"<<"sup"<<"inf" <<"liminf"<<"limsup"<<"lim"<<"max"<<"min"; } JKQTmathText::MTlistNode::~MTlistNode() { for (int i=0; igetTBR(currentEv.getFont(parent), "M", painter.device()); double xnew=0; bool wasBrace=false; for (int i=0; igetSize(painter, currentEv, w1, bh, oh, sp); //qDebug()<<"i="<getTypeName()<<" w1="<getTypeName()<<" w2="<getTypeName()<<" w1="<getTypeName()<<" w2="<get_operatorsubsuper_size_factor(); double w1=0, w2=0, w3=0; double oh1=0, oh2=0, oh3=0; double bh1=0, bh2=0, bh3=0; double sp1=0, sp2=0, sp3=0; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp1); //qDebug()<<"sub_super: node: "<getTypeName()<<" w1="<getTypeName()<<" w2="<getTypeName()<<" w3="<overallHeight) overallHeight=oh; if (bh>baselineHeight) { baselineHeight=bh; strikeoutPos=sp1; } if (oh-bh>overallHeight-baselineHeight) { overallHeight=baselineHeight+oh-bh; } i++; i++; doDraw=false; xnew+=w; //qDebug()<<"### subsupop: sub+super2 overallHeight="<overallHeight) overallHeight=oh; if (bh>baselineHeight) { baselineHeight=bh; strikeoutPos=sp1; } if (oh-bh>overallHeight-baselineHeight) { overallHeight=baselineHeight+oh-bh; } i++; i++; doDraw=false; xnew+=w; //qDebug()<<"### subsupop: sub+super";*/ } else if (subn) { // is this subscript? MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->get_operatorsubsuper_size_factor(); double w1=0, w2=0; double oh1=0, oh2=0; double bh1=0, bh2=0; double sp1=0, sp2=0;//, sp3=0; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp1); subn->get_child()->getSize(painter, ev, w2, bh2, oh2, sp2); //double d1=oh1-bh1; //double d2=oh2-bh2; double oh=oh1+oh2; double sh=oh1-bh1+oh2*1.1; if (oh>overallHeight) overallHeight=oh; if (bh1>baselineHeight) baselineHeight=bh1; if (sh>overallHeight-baselineHeight) { overallHeight=baselineHeight+sh; } double w=qMax(w1, w2)+fm.width(" "); i++; doDraw=false; xnew+=w; //qDebug()<<"### subsupop: sub overallHeight="<get_super_shift_factor()*tbr.height()+(oh-bh);//((overallHeight-baselineHeight)+(oh-bh)); if (wasBrace) { shift=baselineHeight-parent->get_super_shift_factor()*tbr.height()+(oh-bh); } //qDebug()<<"+++ super: bh="<baselineHeight) { double lheight=overallHeight-baselineHeight; baselineHeight=shift+bh; overallHeight=baselineHeight+lheight; } //qDebug()<<"### super"; //qDebug()<<"### subsupop: super overallHeight="<overallHeight-baselineHeight) { overallHeight=baselineHeight+shift+(oh-bh); } //qDebug()<<"### sub"; //qDebug()<<"### subsupop: sub overallHeight="<getTBR(currentEv.getFont(parent), "M", painter.device()); bool wasBrace=false; for (int i=0; i(nodes[i]); // if we find a subscript/superscript node we check whether the next node is super/subscript // if so, we typeset them at the same x-psotion, so sub/superscripts appear correctly if (dynamic_cast(nodes[i])) { double ccwidth=0, ccbaselineHeight=0, ccoverallHeight=0, ccstrieoutPos=0; nodes[i]->getSize(painter, currentEv, ccwidth, ccbaselineHeight, ccoverallHeight, ccstrieoutPos); if (i+1(nodes[i+1])) { // is this subscript? double shift=-parent->get_super_shift_factor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->get_super_shift_factor()*tbr.height(); } //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccoverallHeight-ccbaselineHeight)-4,8,8); double xnew1=nodes[i]->draw(painter, xnew, ynew+shift-(ccoverallHeight-ccbaselineHeight), currentEv); i++; //painter.setPen(QPen("magenta")); //painter.drawEllipse(xnew-4,ynew-4,8,8); double xnew2=nodes[i]->draw(painter, xnew, ynew, currentEv); //i++; xnew=qMax(xnew1, xnew2); doDraw=false; } } } else if (dynamic_cast(nodes[i])) { if (i+1(nodes[i+1])) { // is this subscript? //painter.setPen(QPen("magenta")); //painter.drawEllipse(xnew-4,ynew-4,8,8); double xnew1=nodes[i]->draw(painter, xnew, ynew, currentEv); i++; double ccwidth=0, ccbaselineHeight=0, ccoverallHeight=0, ccstrieoutPos=0; nodes[i]->getSize(painter, currentEv, ccwidth, ccbaselineHeight, ccoverallHeight, ccstrieoutPos); //QRectF tbr=fm.tightBoundingRect("M"); double shift=-parent->get_super_shift_factor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->get_super_shift_factor()*tbr.height(); } //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccoverallHeight-ccbaselineHeight)-4,8,8); double xnew2=nodes[i]->draw(painter, xnew, ynew+shift-(ccoverallHeight-ccbaselineHeight), currentEv); //i++; xnew=qMax(xnew1, xnew2); doDraw=false; } } } else { if (smb) { QString s=smb->get_symbolName(); if (subsupOperations.contains(s)) { MTsubscriptNode* subn=nullptr; if (i+1(nodes[i+1]); MTsuperscriptNode* supn=nullptr; if (i+2(nodes[i+2]); //std::cout<<"symbol ='"<get_operatorsubsuper_size_factor(); double w1=0, w2=0, w3=0; double oh1=0, oh2=0, oh3=0; double bh1=0, bh2=0, bh3=0, sp; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp); subn->get_child()->getSize(painter, ev, w2, bh2, oh2, sp); supn->get_child()->getSize(painter, ev, w3, bh3, oh3, sp); double d1=oh1-bh1; //double d2=oh2-bh2; double d3=oh3-bh3; double w=qMax(qMax(w1, w2), w3); //double xnew1= double xn1=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv); i++; //double xnew2= double xn2=subn->get_child()->draw(painter, xnew+(w-w2)/2.0, ynew+bh2+d1, ev); i++; //double xnew3= double xn3=supn->get_child()->draw(painter, xnew+(w-w3)/2.0, ynew-bh1-d3-fm.xHeight()/4.0, ev); doDraw=false; xnew=qMax(qMax(xn1, xn2), xn3)+fm.width(" "); } else if (subn) { // is this subscript and not superscript? MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->get_operatorsubsuper_size_factor(); double w1=0, w2=0; double oh1=0, oh2=0; double bh1=0, bh2=0, sp=0; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp); subn->get_child()->getSize(painter, ev, w2, bh2, oh2, sp); double d1=oh1-bh1; //double d2=oh2-bh2; double w=qMax(w1, w2); //double xnew1= double xn2=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv); i++; //double xnew2= double xn1=subn->get_child()->draw(painter, xnew+(w-w2)/2.0, ynew+bh2+d1, ev)+fm.width(" "); doDraw=false; //xnew+=w; xnew=qMax(xn1, xn2); } else if (supn) { // is this subscript and superscript? MTenvironment ev=currentEv; ev.fontSize=ev.fontSize*parent->get_operatorsubsuper_size_factor(); double w1=0, w3=0; double oh1=0, oh3=0; double bh1=0, bh3=0, sp; nodes[i]->getSize(painter, currentEv, w1, bh1, oh1, sp); supn->get_child()->getSize(painter, ev, w3, bh3, oh3, sp); //double d1=oh1-bh1; //double d2=oh2-bh2; double d3=oh3-bh3; double w=qMax(w1, w3); //double xnew1= double xn1=nodes[i]->draw(painter, xnew+(w-w1)/2.0, ynew, currentEv); i++; //double xnew3= double xn3=supn->get_child()->draw(painter, xnew+(w-w3)/2.0, ynew-bh1-d3-fm.xHeight()/4.0, ev); doDraw=false; xnew=qMax(xn1, xn3)+fm.width(" "); } } } nodes[i]->getSize(painter, currentEv, cwidth, cbaselineHeight, coverallHeight, cstrieoutPos); } if (i(nodes[i])) { // is this superscript? double ccwidth=0, ccbaselineHeight=0, ccoverallHeight=0, ccstrieoutPos=0; nodes[i]->getSize(painter, currentEv, ccwidth, ccbaselineHeight, ccoverallHeight, ccstrieoutPos); //QRectF tbr=fm.tightBoundingRect("M"); double shift=-parent->get_super_shift_factor()*tbr.height(); if (wasBrace) { shift=-cbaselineHeight+parent->get_super_shift_factor()*tbr.height(); } //painter.setPen(QPen("red")); //painter.drawEllipse(xnew-4,ynew+shift-(ccoverallHeight-ccbaselineHeight)-4,8,8); xnew=nodes[i]->draw(painter, xnew, ynew+shift-(ccoverallHeight-ccbaselineHeight), currentEv); } else { xnew=nodes[i]->draw(painter, xnew, ynew, currentEv); } } wasBrace=dynamic_cast(nodes[i]); } return xnew; } bool JKQTmathText::MTlistNode::toHtml(QString &html, JKQTmathText::MTenvironment currentEv, JKQTmathText::MTenvironment defaultEv) { bool ok=true; for (int i=0; itoHtml(h, currentEv, defaultEv); html=html+h; } return ok; } void JKQTmathText::MTlistNode::set_drawBoxes(bool draw) { this->drawBoxes=draw; for (int i=0; iset_drawBoxes(draw); } } JKQTmathText::MTsymbolNode::MTsymbolNode(JKQTmathText* parent, QString name, bool addWhitespace): JKQTmathText::MTnode(parent) { double mathFontFactor=1.8; symbol = ""; symbolName=name; fontFactor=1.0; bold=0; italic=-1; yfactor=0; QString n=name; drawBar=false; font=MTSFdefault; heightIsAscent=false; exactAscent=false; extendWidthInMathmode=false; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // statische Lookup-Tabellen vorbereiten //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static QStringList extendWInMM; if (extendWInMM.isEmpty()) { extendWInMM <<"ll"<<"gg"<<"leq"<<"geq"<<"leftrightarrow"<<"leftarrow"<<"rightarrow"<<"to"<<"uparrow"<<"downarrow"<<"updownarrow"<<"Leftrightarrow" <<"iff"<<"Leftarrow"<<"Rightarrow"<<"Uparrow"<<"Downarrow"<<"Updownarrow"<<"pm"<<"mp"<<"nexists"<<"ni"<<"notni"<<"circ"<<"sim"<<"emptyset"<<"odot"<<"ominus" <<"subsetnot"<<"bot"<<"leftharpoonup"<<"rightharpoonup"<<"upharpoonleft"<<"downharpoonleft"<<"leftrightharpoon"<<"rightleftharpoon"<<"coprod"<<"leftharpoondown" <<"rightharpoondown"<<"upharpoonright"<<"downharpoonright"<<"nwarrow"<<"nearrow"<<"searrow"<<"swarrow"<<"mapsto"<<"div"<<"multimap"<<"maporiginal"<<"mapimage" <<"times"<<"propto"<<"bullet"<<"neq"<<"ne"<<"equiv"<<"approx"<<"otimes"<<"oplus"<<"oslash"<<"cap"<<"land"<<"cup"<<"lor"<<"supset"<<"supseteq"<<"supsetnot" <<"subset"<<"subseteq"<<"in"<<"notin"<<"cdot"<<"wedge"<<"vee"<<"cong"<<"bot"<<"mid"; } if (extendWInMM.contains(n)) { extendWidthInMathmode=true; } static QHash simpleTranslations; if (simpleTranslations.isEmpty()) { simpleTranslations.insert("", " "); simpleTranslations.insert("sin", "sin"); simpleTranslations.insert("cos", "cos"); simpleTranslations.insert("tan", "tan"); simpleTranslations.insert("sinh", "sinh"); simpleTranslations.insert("cosh", "cosh"); simpleTranslations.insert("tanh", "tanh"); simpleTranslations.insert("atan", "atan"); simpleTranslations.insert("acos", "acos"); simpleTranslations.insert("asin", "asin"); simpleTranslations.insert("arcsin", "arcsin"); simpleTranslations.insert("arccos", "arccos"); simpleTranslations.insert("arctan", "arctan"); simpleTranslations.insert("degree", QLatin1String("\xB0")); simpleTranslations.insert("ii", "i"); simpleTranslations.insert("dd", "d"); simpleTranslations.insert("exp", "exp"); simpleTranslations.insert("log", "log"); simpleTranslations.insert("ln", "ln"); simpleTranslations.insert("ld", "ld"); simpleTranslations.insert("lb", "lb"); simpleTranslations.insert("argmin", "argmin"); simpleTranslations.insert("argmax", "argmax"); simpleTranslations.insert("max", "max"); simpleTranslations.insert("min", "min"); simpleTranslations.insert("sec", "sec"); simpleTranslations.insert("gcd", "gcd"); simpleTranslations.insert("hom", "hom"); simpleTranslations.insert("ker", "ker"); simpleTranslations.insert("dim", "dim"); simpleTranslations.insert("cot", "cot"); simpleTranslations.insert("arg", "arg"); simpleTranslations.insert("det", "det"); simpleTranslations.insert("deg", "deg"); simpleTranslations.insert("Pr", "Pr"); simpleTranslations.insert("coth", "coth"); } static QHash simpleTranslations_heightIsAscent; if (simpleTranslations_heightIsAscent.isEmpty()) { simpleTranslations_heightIsAscent.insert("erf", "erf"); simpleTranslations_heightIsAscent.insert("min", "min"); simpleTranslations_heightIsAscent.insert("max", "max"); simpleTranslations_heightIsAscent.insert("inf", "inf"); simpleTranslations_heightIsAscent.insert("sup", "sup"); simpleTranslations_heightIsAscent.insert("liminf", "liminf"); simpleTranslations_heightIsAscent.insert("limsup", "limsup"); simpleTranslations_heightIsAscent.insert("lim", "lim"); } static QHash winSymbolGreek; if (winSymbolGreek.isEmpty()) { winSymbolGreek.insert("alpha", "a"); winSymbolGreek.insert("beta", "b"); winSymbolGreek.insert("gamma", "g"); winSymbolGreek.insert("delta", "d"); winSymbolGreek.insert("epsilon", "e"); winSymbolGreek.insert("varepsilon", "e"); winSymbolGreek.insert("zeta", "z"); winSymbolGreek.insert("eta", "h"); winSymbolGreek.insert("theta", "q"); winSymbolGreek.insert("vartheta", "J"); winSymbolGreek.insert("iota", "i"); winSymbolGreek.insert("kappa", "k"); winSymbolGreek.insert("lambda", "l"); winSymbolGreek.insert("mu", "m"); winSymbolGreek.insert("nu", "n"); winSymbolGreek.insert("xi", "x"); winSymbolGreek.insert("pi", "p"); winSymbolGreek.insert("varpi", "v"); winSymbolGreek.insert("rho", "r"); winSymbolGreek.insert("sigma", "s"); winSymbolGreek.insert("varsigma", "V"); winSymbolGreek.insert("tau", "t"); winSymbolGreek.insert("upsilon", "u"); winSymbolGreek.insert("phi", "f"); winSymbolGreek.insert("varphi", "j"); winSymbolGreek.insert("chi", "c"); winSymbolGreek.insert("psi", "y"); winSymbolGreek.insert("omega", "w"); winSymbolGreek.insert("Gamma", "G"); winSymbolGreek.insert("Delta", "D"); winSymbolGreek.insert("Theta", "Q"); winSymbolGreek.insert("Lambda", "L"); winSymbolGreek.insert("Omega", "W"); winSymbolGreek.insert("Xi", "X"); winSymbolGreek.insert("Pi", "P"); winSymbolGreek.insert("Sigma", "S"); winSymbolGreek.insert("Upsilon", ""); winSymbolGreek.insert("Phi", "F"); winSymbolGreek.insert("Psi", "Y"); } static QHash winSymbolSymbol; if (winSymbolSymbol.isEmpty()) { winSymbolSymbol.insert("leftrightarrow", QChar(0xAB)); winSymbolSymbol.insert("leftarrow", QChar(0xAC)); winSymbolSymbol.insert("rightarrow", QChar(0xAE)); winSymbolSymbol.insert("to", QChar(0xAE)); winSymbolSymbol.insert("uparrow", QChar(0xAD)); winSymbolSymbol.insert("downarrow", QChar(0xAF)); winSymbolSymbol.insert("Leftrightarrow", QChar(0xDB)); winSymbolSymbol.insert("iff", QChar(0xDB)); winSymbolSymbol.insert("Leftarrow", QChar(0xDC)); winSymbolSymbol.insert("Rightarrow", QChar(0xDE)); winSymbolSymbol.insert("Uparrow", QChar(0xDD)); winSymbolSymbol.insert("Downarrow", QChar(0xFF)); winSymbolSymbol.insert("pm", QChar(0xB1)); winSymbolSymbol.insert("leq", QChar(0xA3)); winSymbolSymbol.insert("geq", QChar(0xB3)); winSymbolSymbol.insert("times", QChar(0xB4)); winSymbolSymbol.insert("propto", QChar(0xB5)); winSymbolSymbol.insert("partial", QChar(0xB6)); winSymbolSymbol.insert("bullet", QChar(0xB7)); winSymbolSymbol.insert("neq", QChar(0xB9)); winSymbolSymbol.insert("ne", QChar(0xB9)); winSymbolSymbol.insert("equiv", QChar(0xBA)); winSymbolSymbol.insert("approx", QChar(0xBB)); winSymbolSymbol.insert("ellipsis", QChar(0xBC)); winSymbolSymbol.insert("Im", QChar(0xC1)); winSymbolSymbol.insert("Re", QChar(0xC2)); winSymbolSymbol.insert("otimes", QChar(0xC4)); winSymbolSymbol.insert("oplus", QChar(0xC5)); winSymbolSymbol.insert("oslash", QChar(0xC6)); winSymbolSymbol.insert("cap", QChar(0xC7)); winSymbolSymbol.insert("land", QChar(0xC7)); winSymbolSymbol.insert("cup", QChar(0xC8)); winSymbolSymbol.insert("lor", QChar(0xC8)); winSymbolSymbol.insert("supset", QChar(0xC9)); winSymbolSymbol.insert("supseteq", QChar(0xCA)); winSymbolSymbol.insert("supsetnot", QChar(0xCB)); winSymbolSymbol.insert("subset", QChar(0xCC)); winSymbolSymbol.insert("subseteq", QChar(0xCD)); winSymbolSymbol.insert("in", QChar(0xCE)); winSymbolSymbol.insert("notin", QChar(0xCF)); winSymbolSymbol.insert("angle", QChar(0xD0)); winSymbolSymbol.insert("nabla", QChar(0xD1)); winSymbolSymbol.insert("copyright", QChar(0xD3)); winSymbolSymbol.insert("registered", QChar(0xD2)); winSymbolSymbol.insert("trademark", QChar(0xD4)); winSymbolSymbol.insert("cdot", QChar(0xD7)); winSymbolSymbol.insert("neg", QChar(0xD8)); winSymbolSymbol.insert("wedge", QChar(0xD9)); winSymbolSymbol.insert("vee", QChar(0xDA)); winSymbolSymbol.insert("diamond", QChar(0xE0)); winSymbolSymbol.insert("langle", QChar(0xE1)); winSymbolSymbol.insert("rangle", QChar(0xF1)); winSymbolSymbol.insert("forall", QChar(0x22)); winSymbolSymbol.insert("exists", QChar(0x24)); winSymbolSymbol.insert("cong", QChar(0x40)); winSymbolSymbol.insert("bot", QChar(0x5E)); winSymbolSymbol.insert("ll", "<<"); winSymbolSymbol.insert("gg", ">>"); winSymbolSymbol.insert("Alef", QChar(0xC0)); winSymbolSymbol.insert("alef", QChar(0xC0)); winSymbolSymbol.insert("tilde", "~"); winSymbolSymbol.insert("emptyset", QChar(0xC6)); winSymbolSymbol.insert("varnothing", QChar(0xC6)); winSymbolSymbol.insert("lceil", QChar(0xE9)); winSymbolSymbol.insert("rceil", QChar(0xF9)); winSymbolSymbol.insert("lfloor", QChar(0xEB)); winSymbolSymbol.insert("rfloor", QChar(0xFB)); winSymbolSymbol.insert("subsetnot", QChar(0xCB)); winSymbolSymbol.insert("DC", "="); winSymbolSymbol.insert("mid", "|"); winSymbolSymbol.insert("cdots", QString(3, QChar(0xD7))); winSymbolSymbol.insert("dots", QChar(0xDC)); winSymbolSymbol.insert("ldots", QChar(0xDC)); winSymbolSymbol.insert("cent", "c"); } static QHash unicodeGreek; if (unicodeGreek.isEmpty()) { unicodeGreek.insert("alpha", QChar(0x3B1)); unicodeGreek.insert("beta", QChar(0x3B2)); unicodeGreek.insert("gamma", QChar(0x3B3)); unicodeGreek.insert("delta", QChar(0x3B4)); unicodeGreek.insert("epsilon", QChar(0x3B5)); unicodeGreek.insert("varepsilon", QChar(0x3B5)); unicodeGreek.insert("zeta", QChar(0x3B6)); unicodeGreek.insert("eta", QChar(0x3B7)); unicodeGreek.insert("theta", QChar(0x3B8)); unicodeGreek.insert("vartheta", QChar(0x3D1)); unicodeGreek.insert("iota", QChar(0x3B9)); unicodeGreek.insert("kappa", QChar(0x3BA)); unicodeGreek.insert("lambda", QChar(0x3BB)); unicodeGreek.insert("mu", QChar(0x3BC)); unicodeGreek.insert("nu", QChar(0x3BD)); unicodeGreek.insert("xi", QChar(0x3BE)); unicodeGreek.insert("pi", QChar(0x3C0)); unicodeGreek.insert("varpi", QChar(0x3D6)); unicodeGreek.insert("rho", QChar(0x3C1)); unicodeGreek.insert("varrho", QChar(0x3F1)); unicodeGreek.insert("sigma", QChar(0x3C3)); unicodeGreek.insert("varsigma", QChar(0x3C2)); unicodeGreek.insert("tau", QChar(0x3C4)); unicodeGreek.insert("upsilon", QChar(0x3C5)); unicodeGreek.insert("phi", QChar(0x3D5)); unicodeGreek.insert("varphi", QChar(0x3C6)); unicodeGreek.insert("chi", QChar(0x3C7)); unicodeGreek.insert("psi", QChar(0x3C8)); unicodeGreek.insert("omega", QChar(0x3C9)); unicodeGreek.insert("Omega", QChar(0x3A9)); unicodeGreek.insert("Gamma", QChar(0x393)); unicodeGreek.insert("Delta", QChar(0x394)); unicodeGreek.insert("Theta", QChar(0x398)); unicodeGreek.insert("Lambda", QChar(0x39B)); unicodeGreek.insert("Xi", QChar(0x39E)); unicodeGreek.insert("Pi", QChar(0x3A0)); unicodeGreek.insert("Sigma", QChar(0x3A3)); unicodeGreek.insert("Upsilon", QChar(0x3A5)); unicodeGreek.insert("Phi", QChar(0x3A6)); unicodeGreek.insert("Psi", QChar(0x3A8)); } static QHash unicodeSymbol; if (unicodeSymbol.isEmpty()) { unicodeSymbol.insert("leftrightarrow", QChar(0x2194)); unicodeSymbol.insert("leftarrow", QChar(0x2190)); unicodeSymbol.insert("rightarrow", QChar(0x2192)); unicodeSymbol.insert("to", QChar(0x2192)); unicodeSymbol.insert("uparrow", QChar(0x2191)); unicodeSymbol.insert("downarrow", QChar(0x2193)); unicodeSymbol.insert("updownarrow", QChar(0x2195)); unicodeSymbol.insert("Leftrightarrow", QChar(0x21D4)); unicodeSymbol.insert("iff", QChar(0x21D4)); unicodeSymbol.insert("Leftarrow", QChar(0x21D0)); unicodeSymbol.insert("Rightarrow", QChar(0x21D2)); unicodeSymbol.insert("Uparrow", QChar(0x21D1)); unicodeSymbol.insert("Downarrow", QChar(0x21D3)); unicodeSymbol.insert("Updownarrow", QChar(0x21D5)); unicodeSymbol.insert("pm", QChar(0x00B1)); unicodeSymbol.insert("mp", QChar(0x2213)); unicodeSymbol.insert("leq", QChar(0x2264)); unicodeSymbol.insert("geq", QChar(0x2265)); unicodeSymbol.insert("ll", QChar(0x226A)); unicodeSymbol.insert("gg", QChar(0x226B)); unicodeSymbol.insert("hbar", QChar(0x210F)); unicodeSymbol.insert("euro", QChar(0x20AC)); unicodeSymbol.insert("Angstrom", QChar(0x212B)); unicodeSymbol.insert("Alef", QChar(0x2135)); unicodeSymbol.insert("Bet", QChar(0x2136)); unicodeSymbol.insert("Gimel", QChar(0x2137)); unicodeSymbol.insert("Dalet", QChar(0x2138)); unicodeSymbol.insert("alef", QChar(0x2135)); unicodeSymbol.insert("bet", QChar(0x2136)); unicodeSymbol.insert("gimel", QChar(0x2137)); unicodeSymbol.insert("dalet", QChar(0x2138)); unicodeSymbol.insert("nexists", QChar(0x2204)); unicodeSymbol.insert("ni", QChar(0x220B)); unicodeSymbol.insert("notni", QChar(0x220C)); unicodeSymbol.insert("circ", QChar(0x2218)); unicodeSymbol.insert("tilde", QChar(0x223C)); unicodeSymbol.insert("emptyset", QChar(0x2300)); unicodeSymbol.insert("varnothing", QChar(0x2300)); unicodeSymbol.insert("odot", QChar(0x2299)); unicodeSymbol.insert("ominus", QChar(0x2296)); unicodeSymbol.insert("lceil", QChar(0x2308)); unicodeSymbol.insert("rceil", QChar(0x2309)); unicodeSymbol.insert("lfloor", QChar(0x230A)); unicodeSymbol.insert("rfloor", QChar(0x230B)); unicodeSymbol.insert("subsetnot", QChar(0x2284)); unicodeSymbol.insert("DC", QChar(0x2393)); unicodeSymbol.insert("bot", QChar(0x22A4)); unicodeSymbol.insert("mid", QChar(0xFF5C)); unicodeSymbol.insert("cdots", QString(QChar(0x00B7)) + QString(QChar(0x00B7)) + QString(QChar(0x00B7))); unicodeSymbol.insert("vdots", QChar(0x22EE)); unicodeSymbol.insert("iddots", QChar(0x22F0)); unicodeSymbol.insert("ddots", QChar(0x22F1)); unicodeSymbol.insert("dots", "..."); unicodeSymbol.insert("ldots", "..."); unicodeSymbol.insert("perthousand", QChar(0x2030)); unicodeSymbol.insert("leftharpoonup", QChar(0x21BC)); unicodeSymbol.insert("rightharpoonup", QChar(0x21C0)); unicodeSymbol.insert("upharpoonleft", QChar(0x21BF)); unicodeSymbol.insert("downharpoonleft", QChar(0x21C3)); unicodeSymbol.insert("leftrightharpoon", QChar(0x21CB)); unicodeSymbol.insert("rightleftharpoon", QChar(0x21CC)); unicodeSymbol.insert("leftharpoondown", QChar(0x21BD)); unicodeSymbol.insert("rightharpoondown", QChar(0x21C1)); unicodeSymbol.insert("upharpoonright", QChar(0x21BE)); unicodeSymbol.insert("downharpoonright", QChar(0x21C2)); unicodeSymbol.insert("nwarrow", QChar(0x2196)); unicodeSymbol.insert("nearrow", QChar(0x2197)); unicodeSymbol.insert("searrow", QChar(0x2198)); unicodeSymbol.insert("swarrow", QChar(0x2199)); unicodeSymbol.insert("mapsto", QChar(0x21A6)); unicodeSymbol.insert("cent", QChar(0x00A2)); unicodeSymbol.insert("pound", QChar(0x00A3)); unicodeSymbol.insert("yen", QChar(0x00A5)); unicodeSymbol.insert("div", QChar(0x00F7)); unicodeSymbol.insert("multimap", QChar(0x22B8)); unicodeSymbol.insert("maporiginal", QChar(0x22B6)); unicodeSymbol.insert("mapimage", QChar(0x22B7)); unicodeSymbol.insert("benzene", QChar(0x232C)); unicodeSymbol.insert("times", QChar(0x2A2F)); unicodeSymbol.insert("propto", QChar(0x221D)); unicodeSymbol.insert("partial", QChar(0x2202)); unicodeSymbol.insert("bullet", QChar(0x2219)); unicodeSymbol.insert("neq", QChar(0x2260)); unicodeSymbol.insert("ne", QChar(0x2260)); unicodeSymbol.insert("equiv", QChar(0x2261)); unicodeSymbol.insert("approx", QChar(0x2245)); unicodeSymbol.insert("ellipsis", QChar(0x2026)); unicodeSymbol.insert("Im", QChar(0x2111)); unicodeSymbol.insert("Re", QChar(0x211C)); unicodeSymbol.insert("otimes", QChar(0x2297)); unicodeSymbol.insert("oplus", QChar(0x2295)); unicodeSymbol.insert("oslash", QChar(0x2298)); unicodeSymbol.insert("cap", QChar(0x2229)); unicodeSymbol.insert("land", QChar(0x2229)); unicodeSymbol.insert("cup", QChar(0x222A)); unicodeSymbol.insert("lor", QChar(0x222A)); unicodeSymbol.insert("supset", QChar(0x2283)); unicodeSymbol.insert("supseteq", QChar(0x2286)); unicodeSymbol.insert("supsetnot", QChar(0x2285)); unicodeSymbol.insert("subset", QChar(0x2282)); unicodeSymbol.insert("subseteq", QChar(0x2286)); unicodeSymbol.insert("in", QChar(0x2208)); unicodeSymbol.insert("notin", QChar(0x2209)); unicodeSymbol.insert("angle", QChar(0x2221)); unicodeSymbol.insert("nabla", QChar(0x2207)); unicodeSymbol.insert("copyright", QChar(0x00A9)); unicodeSymbol.insert("registered", QChar(0x00AE)); unicodeSymbol.insert("trademark", QChar(0x2122)); unicodeSymbol.insert("cdot", QChar(0x00B7)); unicodeSymbol.insert("neg", QChar(0x00AC)); unicodeSymbol.insert("wedge", QChar(0x2227)); unicodeSymbol.insert("vee", QChar(0x2228)); unicodeSymbol.insert("diamond", QChar(0xE0)); unicodeSymbol.insert("langle", QChar(0x2329)); unicodeSymbol.insert("rangle", QChar(0x232A)); unicodeSymbol.insert("infty", QChar(0x221E)); unicodeSymbol.insert("forall", QChar(0x2200)); unicodeSymbol.insert("exists", QChar(0x2203)); unicodeSymbol.insert("cong", QChar(0x2245)); unicodeSymbol.insert("bot", QChar(0x22A5)); } static QHash latexSimpleSymbol; if (latexSimpleSymbol.isEmpty()) { latexSimpleSymbol.insert("_", "_"); latexSimpleSymbol.insert("}", "}"); latexSimpleSymbol.insert("{", "{"); latexSimpleSymbol.insert("$", "$"); latexSimpleSymbol.insert("%", "%"); latexSimpleSymbol.insert("&", "&"); latexSimpleSymbol.insert("#", "#"); latexSimpleSymbol.insert("ast", "*"); latexSimpleSymbol.insert("glq", QChar(0x27)); latexSimpleSymbol.insert("grq", QChar(0x60)); latexSimpleSymbol.insert("glqq", QChar(0x5C)); latexSimpleSymbol.insert("grqq", "\""); } static QHash latexGreek; if (latexGreek.isEmpty()) { latexGreek.insert("alpha", QChar(0xAE)); latexGreek.insert("beta", QChar(0xAF)); latexGreek.insert("gamma", QChar(0xB0)); latexGreek.insert("delta", QChar(0xB1)); latexGreek.insert("epsilon", QChar(0x22)); latexGreek.insert("varepsilon", QChar(0xB2)); latexGreek.insert("zeta", QChar(0xB3)); latexGreek.insert("eta", QChar(0xB4)); latexGreek.insert("theta", QChar(0xB5)); latexGreek.insert("vartheta", QChar(0x23)); latexGreek.insert("iota", QChar(0xB6)); latexGreek.insert("kappa", QChar(0xB7)); latexGreek.insert("lambda", QChar(0xB8)); latexGreek.insert("mu", QChar(0xB9)); latexGreek.insert("nu", QChar(0xBA)); latexGreek.insert("xi", QChar(0xBB)); latexGreek.insert("pi", QChar(0xBC)); latexGreek.insert("varpi", QChar(0x24)); latexGreek.insert("rho", QChar(0xBD)); latexGreek.insert("varrho", QChar(0x25)); latexGreek.insert("sigma", QChar(0xBE)); latexGreek.insert("varsigma", QChar(0x26)); latexGreek.insert("tau", QChar(0xBF)); latexGreek.insert("upsilon", QChar(0xC0)); latexGreek.insert("phi", QChar(0xC1)); latexGreek.insert("varphi", QChar(0x27)); latexGreek.insert("chi", QChar(0xC2)); latexGreek.insert("psi", QChar(0xC3)); latexGreek.insert("omega", QChar(0x21)); latexGreek.insert("Gamma", QChar(0xA1)); latexGreek.insert("Delta", QChar(0xA2)); latexGreek.insert("Theta", QChar(0xA3)); latexGreek.insert("Lambda", QChar(0xA4)); latexGreek.insert("Xi", QChar(0xA5)); latexGreek.insert("Pi", QChar(0xA6)); latexGreek.insert("Sigma", QChar(0xA7)); latexGreek.insert("Upsilon", QChar(0xA8)); latexGreek.insert("Phi", QChar(0xA9)); latexGreek.insert("Psi", QChar(0xAA)); latexGreek.insert("leftharpoonup", QChar(0x28)); latexGreek.insert("rightharpoonup", QChar(0x2A)); latexGreek.insert("leftharpoondown", QChar(0x29)); latexGreek.insert("rightharpoondown", QChar(0x2B)); latexGreek.insert("neg", QChar(0xAC)); latexGreek.insert("star", QChar(0x3F)); } static QHash latexSymbol; if (latexSymbol.isEmpty()) { latexSymbol.insert("leftrightarrow", QChar(0x24)); latexSymbol.insert("leftarrow", QChar(0xc3)); latexSymbol.insert("rightarrow", QChar(0x21)); latexSymbol.insert("to", QChar(0x21)); latexSymbol.insert("uparrow", QChar(0x22)); latexSymbol.insert("downarrow", QChar(0x23)); latexSymbol.insert("updownarrow", QChar(0x6c)); latexSymbol.insert("Leftrightarrow", QChar(0x2c)); latexSymbol.insert("iff", QChar(0x2c)); latexSymbol.insert("Leftarrow", QChar(0x28)); latexSymbol.insert("Rightarrow", QChar(0x29)); latexSymbol.insert("Uparrow", QChar(0x2a)); latexSymbol.insert("Downarrow", QChar(0x2b)); latexSymbol.insert("Updownarrow", QChar(0x6d)); latexSymbol.insert("pm", QChar(0xa7)); latexSymbol.insert("mp", QChar(0xa8)); latexSymbol.insert("leq", QChar(0xb7)); latexSymbol.insert("geq", QChar(0xb8)); latexSymbol.insert("ll", QChar(0xbf)); latexSymbol.insert("gg", QChar(0xc0)); latexSymbol.insert("Alef", QChar(0x40)); latexSymbol.insert("alef", QChar(0x40)); latexSymbol.insert("ni", QChar(0x33)); latexSymbol.insert("circ", QChar(0xb1)); latexSymbol.insert("tilde", QChar(0xbb)); latexSymbol.insert("emptyset", QChar(0x3b)); latexSymbol.insert("odot", QChar(0xaf)); latexSymbol.insert("ominus", QChar(0xaa)); latexSymbol.insert("odiv", QChar(0xae)); latexSymbol.insert("oplus", QChar(0xa9)); latexSymbol.insert("lceil", QChar(0x64)); latexSymbol.insert("rceil", QChar(0x65)); latexSymbol.insert("lfloor", QChar(0x62)); latexSymbol.insert("rfloor", QChar(0x63)); latexSymbol.insert("bot", QChar(0x3f)); latexSymbol.insert("cdots", QString(3, QChar(0xA2))); latexSymbol.insert("dots", "..."); latexSymbol.insert("nwarrow", QChar(0x2d)); latexSymbol.insert("nearrow", QChar(0x25)); latexSymbol.insert("searrow", QChar(0x26)); latexSymbol.insert("swarrow", QChar(0x2e)); latexSymbol.insert("div", QChar(0xa5)); latexSymbol.insert("times", QChar(0xa3)); latexSymbol.insert("propto", QChar(0x2f)); latexSymbol.insert("bullet", QChar(0x2b)); latexSymbol.insert("equiv", QChar(0xb4)); latexSymbol.insert("approx", QChar(0xbc)); latexSymbol.insert("ellipsis", "..."); latexSymbol.insert("Im", QChar(0x3D)); latexSymbol.insert("Re", QChar(0x3C)); latexSymbol.insert("oplus", QChar(0xa9)); latexSymbol.insert("oslash", QChar(0xae)); latexSymbol.insert("cap", QChar(0x5c)); latexSymbol.insert("cup", QChar(0x5b)); latexSymbol.insert("land", QChar(0x5c)); latexSymbol.insert("lor", QChar(0x5b)); latexSymbol.insert("supset", QChar(0xbe)); latexSymbol.insert("supseteq", QChar(0xb6)); latexSymbol.insert("subset", QChar(0xbd)); latexSymbol.insert("subseteq", QChar(0xb5)); latexSymbol.insert("in", QChar(0x32)); latexSymbol.insert("nabla", QChar(0x35)); latexSymbol.insert("cdot", QChar(0xa2)); latexSymbol.insert("wedge", QChar(0x5e)); latexSymbol.insert("vee", QChar(0x5f)); latexSymbol.insert("diamond", QChar(0xE0)); latexSymbol.insert("langle", QChar(0x68)); latexSymbol.insert("rangle", QChar(0x69)); latexSymbol.insert("infty", QChar(0x31)); latexSymbol.insert("forall", QChar(0x38)); latexSymbol.insert("exists", QChar(0x39)); latexSymbol.insert("cong", QChar(0xbb)); latexSymbol.insert("mid", "|"); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QHash::iterator itsimple = simpleTranslations.find(n); if (itsimple!= simpleTranslations.end()) { symbol=itsimple.value(); } else { QHash::iterator itsimplehia = simpleTranslations_heightIsAscent.find(n); if (itsimplehia != simpleTranslations_heightIsAscent.end()) { symbol = itsimplehia.value(); heightIsAscent = true; } else { if (parent->get_fontEncoding() == MTFEwinSymbol) { // first we start with greek characters font = MTSFgreek; italic = -1; QHash::iterator itgreek = winSymbolGreek.find(n); if (itgreek!=winSymbolGreek.end()) { symbol = itgreek.value(); } else if (n == "sum") { symbol = "S"; fontFactor = mathFontFactor; heightIsAscent = true; exactAscent = true; } else if (n == "prod") { symbol = "P"; fontFactor = mathFontFactor; heightIsAscent = true; exactAscent = true; } else { // now we set the symbols from the Symbol font font = MTSFsymbol; QHash::iterator itsymbol = winSymbolSymbol.find(n); if (itsymbol!=winSymbolSymbol.end()) { symbol = itsymbol.value(); } else if (n == "int") { symbol = QChar(0xF2); fontFactor = mathFontFactor; yfactor = +0.1; } else if (n == "bbC") { symbol = "C"; bold = +1; italic = -1; } else if (n == "bbH") { symbol = "H"; bold = +1; italic = -1; } else if (n == "bbN") { symbol = "N"; bold = +1; italic = -1; } else if (n == "bbP") { symbol = "P"; bold = +1; italic = -1; } else if (n == "bbQ") { symbol = "Q"; bold = +1; italic = -1; } else if (n == "bbR") { symbol = "R"; bold = +1; italic = -1; } else if (n == "bbZ") { symbol = "Z"; bold = +1; italic = -1; } else if (n == "iint") { symbol = QString(2, QChar(0xF2)); fontFactor = mathFontFactor; yfactor = +0.1; } else if (n == "iiint") { symbol = QString(3, QChar(0xF2)); fontFactor = mathFontFactor; yfactor = +0.1; } else if (n == "bigcap") { symbol = QChar(0xC7); fontFactor = 2; } else if (n == "bigcup") { symbol = QChar(0xC8); fontFactor = 2; } else if (n == "bigvee") { symbol = QChar(0xDA); fontFactor = 2; } else if (n == "bighat") { symbol = QChar(0xD9); fontFactor = 2; } else { // here are text mode symbols, i.e. bold and italic won't be touched bold = -1; italic = -1; font = MTSFdefault; if (n == "_") { symbol = "_"; bold = 0; italic = 0; } else if (n == "}") { symbol = "}"; } else if (n == "{") { symbol = "{"; } else if (n == "hbar") { symbol = "h"; bold = 0; italic = 0; drawBar = true; } else if (n == "euro") { symbol = ""; bold = 0; italic = 0; } else if (n == "cent") { symbol = QChar(0xA2); bold = 0; italic = 0; } else if (n == "pound") { symbol = QChar(0xA3); bold = 0; italic = 0; } else if (n == "yen") { symbol = QChar(0xA5); bold = 0; italic = 0; } else if (n == "div") { symbol = QChar(0xF7); bold = 0; italic = 0; } else if (n == "backslash") { symbol = "\\"; bold = 0; italic = 0; } //else if (n=="|") { symbol="||"; bold=0; italic=0; } else if (n == "$") { symbol = "$"; bold = 0; italic = 0; } else if (n == "%") { symbol = "%"; bold = 0; italic = 0; } else if (n == "&") { symbol = "&"; bold = 0; italic = 0; } else if (n == "#") { symbol = "#"; bold = 0; italic = 0; } else if (n == "ast") { symbol = "*"; bold = 0; italic = 0; } else if (n == "glq") { symbol = "'"; bold = 0; italic = 0; } else if (n == "grq") { symbol = "'"; bold = 0; italic = 0; } else if (n == "glqq") { symbol = "\""; bold = 0; italic = 0; } else if (n == "grqq") { symbol = "\""; bold = 0; italic = 0; } else if (n == "flq") { symbol = "<"; bold = 0; italic = 0; } else if (n == "frq") { symbol = ">"; bold = 0; italic = 0; } else if (n == "flqq") { symbol = ""; bold = 0; italic = 0; } else if (n == "frqq") { symbol = ""; bold = 0; italic = 0; } } //else if (n=="") { symbol=QChar(); font=MTSFdefault; } //else if (n=="") symbol=QChar(0x); } } else if (parent->get_fontEncoding() == MTFEunicode) { // use UNICODE encoding for special characters // first we start with greek characters font = MTSFdefault; //MTSFgreek; //std::cout<<"encoding unicode\n"; QHash::iterator itgreek = unicodeGreek.find(n); if (itgreek!=unicodeGreek.end()) { symbol = itgreek.value(); } else { // now we set the symbols from the Symbol font font = MTSFsymbol; QHash::iterator itsymbol = unicodeSymbol.find(n); if (itsymbol!=unicodeSymbol.end()) { symbol = itsymbol.value(); } if (n == "sum") { symbol = QChar(0x2211); heightIsAscent = true; exactAscent = true; } else if (n == "prod") { symbol = QChar(0x220F); heightIsAscent = true; exactAscent = true; } else if (n == "bbC") { symbol = QChar(0x2102); italic = -1; } else if (n == "bbH") { symbol = QChar(0x210D); italic = -1; } else if (n == "bbN") { symbol = QChar(0x2115); italic = -1; } else if (n == "bbP") { symbol = QChar(0x2119); italic = -1; } else if (n == "bbQ") { symbol = QChar(0x211A); italic = -1; } else if (n == "bbR") { symbol = QChar(0x211D); italic = -1; } else if (n == "bbZ") { symbol = QChar(0x2124); italic = -1; } else if (n == "iint") { symbol = QChar(0x222C); fontFactor = mathFontFactor; /*yfactor=+0.1;;*/ heightIsAscent = true; exactAscent = true; } else if (n == "iiint") { symbol = QChar(0x222D); fontFactor = mathFontFactor; /*yfactor=+0.1;;*/ heightIsAscent = true; exactAscent = true; } else if (n == "oint") { symbol = QChar(0x222E); fontFactor = mathFontFactor; /*yfactor=+0.1;;*/ heightIsAscent = true; exactAscent = true; } else if (n == "oiint") { symbol = QChar(0x222F); fontFactor = mathFontFactor; /*yfactor=+0.1;;*/ heightIsAscent = true; exactAscent = true; } else if (n == "oiiint") { symbol = QChar(0x2230); fontFactor = mathFontFactor; /*yfactor=+0.1;;*/ heightIsAscent = true; exactAscent = true; } else if (n == "coprod") { symbol = QChar(0x2210); heightIsAscent = true; exactAscent = true; } else if (n == "bigcap") { symbol = QChar(0x22C2); heightIsAscent = true; exactAscent = true;; heightIsAscent = true; exactAscent = true; } else if (n == "bigcup") { symbol = QChar(0x22C3); heightIsAscent = true; exactAscent = true;; heightIsAscent = true; exactAscent = true; } else if (n == "bigvee") { symbol = QChar(0x22C1); heightIsAscent = true; exactAscent = true;; heightIsAscent = true; exactAscent = true; } else if (n == "bighat") { symbol = QChar(0x22C0); heightIsAscent = true; exactAscent = true;; heightIsAscent = true; exactAscent = true; } else if (n == "int") { symbol = QChar(0x222B); fontFactor = mathFontFactor; /*yfactor=+0.1;;*/ heightIsAscent = true; exactAscent = true; } else { // here are text mode symbols, i.e. bold and italic won't be touched bold = -1; italic = -1; font = MTSFdefault; if (n == "_") { symbol = "_"; } else if (n == "}") { symbol = "}"; } else if (n == "{") { symbol = "{"; } else if (n == "backslash") { symbol = "\\"; bold = 0; italic = 0; } //else if (n=="|") { symbol=QChar(0x2016); } else if (n == "$") { symbol = "$"; } else if (n == "%") { symbol = "%"; } else if (n == "&") { symbol = "&"; } else if (n == "#") { symbol = "#"; } else if (n == "ast") { symbol = "*"; } else if (n == "glq") { symbol = QChar(0x2018); bold = 0; italic = 0; } else if (n == "grq") { symbol = QChar(0x2019); bold = 0; italic = 0; } else if (n == "glqq") { symbol = QChar(0x201C); bold = 0; italic = 0; } else if (n == "grqq") { symbol = QChar(0x201D); bold = 0; italic = 0; } else if (n == "flq") { symbol = QChar(0x2039); bold = 0; italic = 0; } else if (n == "frq") { symbol = QChar(0x203A); bold = 0; italic = 0; } else if (n == "flqq") { symbol = ""; bold = 0; italic = 0; } else if (n == "frqq") { symbol = ""; bold = 0; italic = 0; } } //else if (n=="") { symbol=QChar(); font=MTSFdefault; } //else if (n=="") symbol=QChar(0x); } } else if (parent->get_fontEncoding() == MTFElatex) { // use UNICODE encoding for special characters // first we start with greek characters font = MTSFdefault; //MTSFgreek; //std::cout<<"encoding unicode\n"; QHash::iterator itssymbol = latexSimpleSymbol.find(n); if (itssymbol!=latexSimpleSymbol.end()) { symbol = itssymbol.value(); } else if (n == "backslash") { symbol = "\\"; bold = 0; italic = 0; } else { font = MTSFgreek; QHash::iterator itgreek = latexGreek.find(n); if (itgreek!=latexGreek.end()) { symbol = itgreek.value(); } else { // now we set the symbols from the Symbol font font = MTSFsymbol; QHash::iterator itsymbol = latexSymbol.find(n); if (itsymbol!=latexSymbol.end()) { symbol = itsymbol.value(); } else if (n == "int") { symbol = QChar(0x73); fontFactor = mathFontFactor; yfactor = +0.1; } else { // here are text mode symbols, i.e. bold and italic won't be touched font = MTSFbraces; if (n == "bigcap") { symbol = QChar(0x5c); heightIsAscent = true; exactAscent = true; } else if (n == "bigcup") { symbol = QChar(0x5b); heightIsAscent = true; exactAscent = true; } else if (n == "bigvee") { symbol = QChar(0x5F); heightIsAscent = true; exactAscent = true; } else if (n == "bighat") { symbol = QChar(0x5E); heightIsAscent = true; exactAscent = true; } else if (n == "oint") { symbol = QChar(0x49); yfactor = +0.1; } else if (n == "coprod") { symbol = QChar(0x61); heightIsAscent = true; exactAscent = true; } else if (n == "iint") { symbol = QString(2, QChar(0x5A)); yfactor = +0.1; } else if (n == "iiint") { symbol = QString(3, QChar(0x5A)); yfactor = +0.1; } else if (n == "sum") { symbol = QChar(0x58); heightIsAscent = true; exactAscent = true; } else if (n == "prod") { symbol = QChar(0x59); heightIsAscent = true; exactAscent = true; } } } } } } } if (addWhitespace) symbol=symbol+" "; static QSet extraSymbolName = { "infty", "|", " ", "quad", ";", ":", ",", "!", "longleftarrow", "longrightarrow", "Longleftarrow", "Longrightarrow", "longleftrightarrow", "Longleftrightarrow" }; if (symbol.simplified().isEmpty() && !extraSymbolName.contains(n)) { parent->error_list.append(tr("unknown symbol '%1' found!").arg(n)); } //std::cout<<"symbol node '"<get_fontGreek()); break; case MTSFsymbol: fr.setFamily(parent->get_fontSymbol()); break; case MTSFbraces: fr.setFamily(parent->get_fontBraces()); break; case MTSFintegrals: fr.setFamily(parent->get_fontIntegrals()); break; case MTSFcaligraphic: fr.setFamily(parent->get_fontCaligraphic()); break; case MTSFblackboard: fr.setFamily(parent->get_fontBlackboard()); break; default: break; } return fr; } void JKQTmathText::MTsymbolNode::getSizeInternal(QPainter& painter, JKQTmathText::MTenvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos) { QFont f=currentEv.getFont(parent); f=getFontName(font, f); f.setPointSizeF(f.pointSizeF()*fontFactor); if (italic<0) f.setItalic(false); if (italic>0) f.setItalic(true); if (bold<0) f.setBold(false); if (bold>0) f.setBold(true); QFontMetricsF fm(f, painter.device()); QString symb=symbol; width=0; if (currentEv.insideMath) width=qMax(parent->getTBR(f, symb, painter.device()).width(),parent->getTBR(f, "i", painter.device()).width());//fm.width(symbol); else width=fm.boundingRect(symb).width();//fm.width(symbol); width=qMax(fm.width("j"), width); if (symb.isEmpty()) { width=fm.width("a"); if (symbolName=="|") width=fm.width("1")*0.8; else if (symbolName=="infty") width=fm.width("M"); else if (symbolName=="quad") width=parent->getTBR(f, "M", painter.device()).width(); else if (symbolName==" ") width=parent->getTBR(f, "x", painter.device()).width(); else if (symbolName==";") width=parent->getTBR(f, "x", painter.device()).width()*0.75; else if (symbolName==":") width=parent->getTBR(f, "x", painter.device()).width()*0.5; else if (symbolName==",") width=parent->getTBR(f, "x", painter.device()).width()*0.25; else if (symbolName=="!") width=-parent->getTBR(f, "x", painter.device()).width()*0.25; else if (symbolName=="longleftarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="longrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longleftarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="longleftrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } else if (symbolName=="Longleftrightarrow") { width=parent->getTBR(f, "X", painter.device()).width()*3.5; symb="x"; } } QRectF tbr=parent->getTBR(f, symb, painter.device()); overallHeight=tbr.height();// fm.height(); baselineHeight=tbr.height()-tbr.bottom(); if (exactAscent) { //baselineHeight=fm.ascent()*0.8; } if (heightIsAscent) { overallHeight=baselineHeight*1.1; } if (exactAscent && heightIsAscent) { //qDebug()<get_mathoperator_width_factor(); } double JKQTmathText::MTsymbolNode::draw(QPainter& painter, double x, double y, JKQTmathText::MTenvironment currentEv) { doDrawBoxes(painter, x, y, currentEv); double width=0; double baselineHeight=0; double overallHeight=0, strikeoutPos=0; getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos); QPen pold=painter.pen(); QFont fold=painter.font(); QFont f=currentEv.getFont(parent); QFont f1=f; f=getFontName(font, f); f.setPointSizeF(f.pointSizeF()*fontFactor); if (italic<0) f.setItalic(false); if (italic>0) f.setItalic(true); if (bold<0) f.setBold(false); if (bold>0) f.setBold(true); QFontMetricsF fm(f, painter.device()); QFontMetricsF fm1(f1, painter.device()); painter.setFont(f); double shift=0; if (extendWidthInMathmode && currentEv.insideMath) { double origwidth=width/parent->get_mathoperator_width_factor(); shift=0.5*(width-origwidth); //width=width*parent->get_mathoperator_width_factor(); } //std::cout<<"symbol '"<getTBR(f, "M", painter.device()).height()-fm.xHeight())/3.0; QLineF l(xx, yy, xx+xwi/3.0+((currentEv.italic)?(xwi/3.0):0), yy); if (drawBar&&l.length()>0) painter.drawLine(l); // try to draw some often used special symbols, by synthesizing them from // standard characters in the current drawing font } else if (symbolName=="infty") { //std::cout<<"draw infty\n"; f1.setItalic(false); painter.setFont(f1); painter.save(); painter.translate(x+shift+fm1.width("8")/3.0, y-fm1.xHeight()); painter.rotate(90); painter.drawText(QPointF(0,0), "8"); painter.restore(); } else if (symbolName=="|") { //std::cout<<"draw infty\n"; f1.setItalic(false); painter.setFont(f1); painter.save(); painter.translate(x+shift, y); painter.drawText(QPointF(0,0), "|"); painter.translate(fm1.width("8")/3.0, 0); painter.drawText(QPointF(0,0), "|"); painter.restore(); // here are some spaces } else if (symbolName==" ") { // full space } else if (symbolName=="quad") { // 75% space } else if (symbolName==";") { // 75% space } else if (symbolName==":") { // 50% space } else if (symbolName==",") { // 25% space } else if (symbolName=="!") { // -25% space } else if (symbolName=="longleftarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, false); painter.drawPath(path); } else if (symbolName=="longrightarrow"){ double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, false, true); painter.drawPath(path); } else if (symbolName=="Longleftarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, false); painter.drawPath(path); } else if (symbolName=="Longrightarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, false, true); painter.drawPath(path); } else if (symbolName=="longleftrightarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, true); painter.drawPath(path); } else if (symbolName=="Longleftrightarrow") { double width=parent->getTBR(f, "X", painter.device()).width()*3.0; double dx=parent->getTBR(f, "X", painter.device()).width()*0.25; double ypos=y-parent->getTBR(f, "x", painter.device()).height()/2.0; QPainterPath path=makeDArrow(x+shift+dx, ypos, width, parent->getTBR(f, "M", painter.device()).height()*0.5, true, true); painter.drawPath(path); } else { // draw a box to indicate an unavailable symbol QRectF tbr=parent->getTBR(f, "M", painter.device()); painter.drawRect(QRectF(x+shift,y-tbr.height(), xwi, tbr.height()*0.8)); } painter.setPen(pold); painter.setFont(fold); return x+width; } bool JKQTmathText::MTsymbolNode::toHtml(QString &html, JKQTmathText::MTenvironment currentEv, JKQTmathText::MTenvironment defaultEv) { bool ok=true; QString s; JKQTmathText::MTenvironment ev=currentEv; static QMap entitylut; if (entitylut.isEmpty()) { entitylut.insert("sin", "sin"); entitylut.insert("cos", "cos"); entitylut.insert("tan", "tan"); entitylut.insert("sinh", "sinh"); entitylut.insert("cosh", "cosh"); entitylut.insert("tanh", "tanh"); entitylut.insert("atan", "atan"); entitylut.insert("acos", "acos"); entitylut.insert("asin", "asin"); entitylut.insert("arcsin", "arcsin"); entitylut.insert("arccos", "arccos"); entitylut.insert("arctan", "arctan"); entitylut.insert("ii", "i"); entitylut.insert("dd", "d"); entitylut.insert("exp", "exp"); entitylut.insert("log", "log"); entitylut.insert("ln", "ln"); entitylut.insert("ld", "ld"); entitylut.insert("lb", "lb"); entitylut.insert("erf", "erf"); entitylut.insert("min", "min"); entitylut.insert("max", "max"); entitylut.insert("argmin", "argmin"); entitylut.insert("argmax", "argmax"); entitylut.insert("inf", "inf"); entitylut.insert("sup", "sup"); entitylut.insert("liminf", "liminf"); entitylut.insert("limsup", "limsup"); entitylut.insert("lim", "lim"); entitylut.insert("max", "max"); entitylut.insert("min", "min"); entitylut.insert("sec", "sec"); entitylut.insert("gcd", "gcd"); entitylut.insert("hom", "hom"); entitylut.insert("ker", "ker"); entitylut.insert("dim", "dim"); entitylut.insert("cot", "cot"); entitylut.insert("arg", "arg"); entitylut.insert("det", "det"); entitylut.insert("deg", "deg"); entitylut.insert("Pr", "Pr"); entitylut.insert("coth", "coth"); entitylut.insert("alpha", "α"); entitylut.insert("beta", "β"); entitylut.insert("gamma", "γ"); entitylut.insert("delta", "δ"); entitylut.insert("epsilon", "ε"); entitylut.insert("varepsilon", "ε"); entitylut.insert("zeta", "ζ"); entitylut.insert("eta", "η"); entitylut.insert("theta", "θ"); entitylut.insert("vartheta", "ϑ"); entitylut.insert("iota", "ι"); entitylut.insert("kappa", "κ"); entitylut.insert("lambda", "λ"); entitylut.insert("mu", "μ"); entitylut.insert("nu", "ν"); entitylut.insert("xi", "ξ"); entitylut.insert("pi", "π"); entitylut.insert("varpi", "ϖ"); entitylut.insert("rho", "ρ"); entitylut.insert("sigma", "σ"); entitylut.insert("varsigma", "ς"); entitylut.insert("tau", "τ"); entitylut.insert("upsilon", "υ"); entitylut.insert("phi", "φ"); entitylut.insert("varphi", "φ"); entitylut.insert("chi", "χ"); entitylut.insert("psi", "ψ"); entitylut.insert("omega", "ω"); entitylut.insert("Gamma", "Γ"); entitylut.insert("Delta", "Δ"); entitylut.insert("Theta", "Θ"); entitylut.insert("Lambda", "Λ"); entitylut.insert("Omega", "Ω"); entitylut.insert("Xi", "Ξ"); entitylut.insert("Pi", "Π"); entitylut.insert("Sigma", "Σ"); entitylut.insert("Upsilon", "Υ"); entitylut.insert("Phi", "Φ"); entitylut.insert("Psi", "Ψ"); entitylut.insert("leftrightarrow", "↔"); entitylut.insert("leftarrow", "←"); entitylut.insert("rightarrow", "→"); entitylut.insert("to", "→"); entitylut.insert("uparrow", "↑"); entitylut.insert("downarrow", "↓"); entitylut.insert("Leftrightarrow", "⇔"); entitylut.insert("iff", "⇔"); entitylut.insert("Leftarrow", "⇐"); entitylut.insert("Rightarrow", "⇒"); entitylut.insert("Uparrow", "⇑"); entitylut.insert("Downarrow", "⇓"); entitylut.insert("pm", "±"); entitylut.insert("leq", "≤"); entitylut.insert("geq", "≥"); entitylut.insert("times", "×"); entitylut.insert("propto", "∝"); entitylut.insert("partial", "∂"); entitylut.insert("bullet", "•"); entitylut.insert("neq", "≠"); entitylut.insert("ne", "≠"); entitylut.insert("equiv", "≡"); entitylut.insert("approx", "≈"); entitylut.insert("ellipsis", "..."); entitylut.insert("Im", "ℑ"); entitylut.insert("Re", "ℜ"); entitylut.insert("otimes", "⊗"); entitylut.insert("oplus", "⊕"); entitylut.insert("oslash", "/"); entitylut.insert("cap", "∩"); entitylut.insert("cup", "∪"); entitylut.insert("land", "∩"); entitylut.insert("lor", "∪"); entitylut.insert("supset", "⊃"); entitylut.insert("supseteq", "⊇"); entitylut.insert("supsetnot", "⊅"); entitylut.insert("subset", "⊂"); entitylut.insert("subseteq", "⊆"); entitylut.insert("in", "∈"); entitylut.insert("notin", "∉"); entitylut.insert("angle", "∠"); entitylut.insert("nabla", "∇"); entitylut.insert("copyright", "©"); entitylut.insert("registered", "®"); entitylut.insert("trademark", "™"); entitylut.insert("cdot", "⋅"); entitylut.insert("neg", "¬"); entitylut.insert("wedge", "∧"); entitylut.insert("vee", "∨"); entitylut.insert("diamond", "◊"); entitylut.insert("langle", "⟨"); entitylut.insert("rangle", "⟩"); entitylut.insert("int", "∫"); entitylut.insert("forall", "∀"); entitylut.insert("exists", "∃"); entitylut.insert("cong", "∼"); entitylut.insert("bot", "⊥"); entitylut.insert("ll", "<<"); entitylut.insert("gg", ">>"); entitylut.insert("bbC", "C"); entitylut.insert("bbH", "H"); entitylut.insert("bbN", "N"); entitylut.insert("bbP", "P"); entitylut.insert("bbQ", "Q"); entitylut.insert("bbR", "R"); entitylut.insert("bbZ", "Z"); entitylut.insert("Alef", "ℵ"); entitylut.insert("alef", "ℵ"); entitylut.insert("tilde", "~"); entitylut.insert("iint", "∫∫"); entitylut.insert("iiint", "∫∫∫"); entitylut.insert("emptyset", "∅"); entitylut.insert("varnothing", "∅"); entitylut.insert("lceil", "⌈"); entitylut.insert("rceil", "⌉"); entitylut.insert("lfloor", "⌊"); entitylut.insert("rfloor", "⌋"); entitylut.insert("subsetnot", "⊄"); entitylut.insert("DC", "="); entitylut.insert("cdots", "⋅⋅⋅"); entitylut.insert("dots", "..."); entitylut.insert("cent", "¢"); entitylut.insert("_", "_"); entitylut.insert("}", "}"); entitylut.insert("{", "{"); entitylut.insert("hbar", "ℏ"); entitylut.insert("euro", "€"); entitylut.insert("pound", "£"); entitylut.insert("yen", "¥"); entitylut.insert("div", "÷"); entitylut.insert("backslash", "\\"); entitylut.insert("$", "$"); entitylut.insert("%", "%"); entitylut.insert("&", "&"); entitylut.insert("#", "#"); entitylut.insert("ast", "*"); entitylut.insert("glq", "'"); entitylut.insert("grq", "'"); entitylut.insert("glqq", "\""); entitylut.insert("grqq", "\""); entitylut.insert("flq", "<"); entitylut.insert("frq", ">"); entitylut.insert("flqq", ""); entitylut.insert("frqq", ""); } QMap::iterator itS = entitylut.find(symbolName); if (itS!=entitylut.end()) { s=itS.value(); } else if (symbolName == "sum") { ev.fontSize*=1.7; s="∑"; } else if (symbolName == "prod") { ev.fontSize*=1.7; s="∏"; } else if (symbolName == "bigcap") { ev.fontSize*=1.7; s="∩"; } else if (symbolName == "bigcup") { ev.fontSize*=1.7; s="∪"; } else if (symbolName == "bigvee") { ev.fontSize*=1.7; s="∨"; } else if (symbolName == "bighat") { ev.fontSize*=1.7; s="∧"; } else ok=false; if (ok) html=html+ev.toHtmlStart(defaultEv)+s+ev.toHtmlAfter(defaultEv); return ok; } // -------------------------------------------------------------------------------------------------- // -- implementation of the JKQTmathText methods // -------------------------------------------------------------------------------------------------- JKQTmathText::JKQTmathText(QObject* parent): QObject(parent) { Q_INIT_RESOURCE(xits); QFontDatabase fontdb; QString serifFont="Serif"; QString sansFont="Sans"; QString symbolFont="Symbol"; QString scriptFont="Script"; QString typewriterFont="typewriter"; QString decorativeFont="decorative"; QStringList fonts=fontdb.families(); //qDebug()<<"fonts:\n"<toHtml(s, ev, defaultev); } if (ok) *ok=okk; return s; } void JKQTmathText::useAnyUnicode(QString timesFont, QString sansFont) { if (!timesFont.isEmpty()) { fontMathRoman=timesFont; fontRoman=timesFont; } if (!sansFont.isEmpty()) { fontMathSans=sansFont; fontSans=sansFont; } useSTIXfonts=false; useXITSfonts=false; useASANAfonts=false; fontGreek=fontMathRoman; fontSymbol=fontMathRoman; fontBraces=fontMathRoman; fontIntegrals=fontMathRoman; fontEncoding=MTFEunicode; brace_shrink_factor=0.6; } JKQTmathText::tokenType JKQTmathText::getToken() { currentTokenID++; if (currentTokenID>parseString.size()-1) return currentToken=MTTnone; QChar c=parseString[currentTokenID]; currentTokenName=""; if (c=='\\') { // read an instruction name currentTokenID++; if (currentTokenID>=parseString.size()-1) return currentToken=MTTnone; c=parseString[currentTokenID]; /*if (c=='_' || c=='\\' || c=='$' || c=='%' || c=='&' || c=='#' || c=='}' || c=='{') { currentTokenName=c; // parse special one-symbol instructions like \\, \& ... // that may be directly converted to text return currentToken=MTTtext; } else*/ if (c=='|' || c==';' || c==':' || c=='!' || c==',' || c=='_' || c=='\\' || c=='$' || c=='%' || c=='&' || c=='#' || c=='}' || c=='{' || c==' ') { currentTokenName=c; // parse one-symbol instructions like \\, \& ... //std::cout<<"found text node '"<addNode(new MTtextNode(this, text, addWhite, parsingMathEnvironment)); } else if (currentToken==MTTinstruction) { QString name=currentTokenName; if (name=="\\") break; // break on linebrak character getToken(); // look at next token if (currentToken==MTTopenbrace) { //std::cout<<"found '{' after '"<addNode(new MTsqrtNode(this, parseLatexString(true))); } else if (name=="cbrt") { nl->addNode(new MTsqrtNode(this, parseLatexString(true), 3)); } else if (name=="verb") { QString text=""; currentTokenID++; if (currentTokenID<=parseString.size()-1) { QChar c=parseString[currentTokenID]; while (c!='}' && (currentTokenIDaddNode(new MTtextNode(this, text, false)); } } else if (name=="frac") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMfrac)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="dfrac") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMdfrac)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="tfrac") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMtfrac)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="stackrel") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMstackrel)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="binom") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTbraceNode(this, "(", ")", new MTfracNode(this, n1, n2, MTFMstackrel))); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="underbrace") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMunderbrace)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="underset") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMunderset)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="overbrace") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMoverbrace)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="overset") { MTnode* n1=parseLatexString(true); MTnode* n2=nullptr; if (getToken()==MTTopenbrace) n2=parseLatexString(true); if (n1 && n2) nl->addNode(new MTfracNode(this, n1, n2, MTFMoverset)); else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); } else if (name=="begin") { if (getToken()==MTTtext) { QString envname=currentTokenName; while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name' if (envname=="matrix" || envname=="array" || envname=="aligned" || envname=="align" || envname=="cases" || envname=="pmatrix"|| envname=="bmatrix"|| envname=="Bmatrix"|| envname=="vmatrix"|| envname=="Vmatrix") { QVector< QVector > items; //int lines=0; //int cols=0; bool first=true; QVector line; //std::cout<<"found \\begin{matrix}\n"; while (first || currentToken==MTTampersand || (currentToken==MTTinstruction && currentTokenName=="\\")) { MTnode* it=parseLatexString(true, "", envname); if (currentToken==MTTampersand) { //std::cout<<" appending item\n"; line.append(it); } else { line.append(it); //std::cout<<" appending item and line with "<addNode(new MTbraceNode(this, "(", ")", new MTmatrixNode(this, items))); else if (envname=="cases") nl->addNode(new MTbraceNode(this, "{", "", new MTmatrixNode(this, items))); else if (envname=="bmatrix") nl->addNode(new MTbraceNode(this, "[", "]", new MTmatrixNode(this, items))); else if (envname=="Bmatrix") nl->addNode(new MTbraceNode(this, "{", "}", new MTmatrixNode(this, items))); else if (envname=="vmatrix") nl->addNode(new MTbraceNode(this, "|", "|", new MTmatrixNode(this, items))); else if (envname=="Vmatrix") nl->addNode(new MTbraceNode(this, "||", "||", new MTmatrixNode(this, items))); else nl->addNode(new MTmatrixNode(this, items)); //std::cout<<" creating matrix-node ... done!\n"; } else { error_list.append(tr("error @ ch. %1: unknown environment '%2'").arg(currentTokenID).arg(envname)); } } else { // find next '}' error_list.append(tr("error @ ch. %1: text after '\\begin{' expected!").arg(currentTokenID)); while (currentToken!=MTTclosebrace) getToken(); getNew=true; } } else if (name=="end") { if (getToken()==MTTtext) { QString envname=currentTokenName; while (currentToken!=MTTclosebrace) getToken(); // find closing brace '}' after '\\begin{name' if (envname==quitOnEnvironmentEnd) { break; } else { error_list.append(tr("error @ ch. %1: '\\end{%2}' widthout preceding '\\begin{%3}'").arg(currentTokenID).arg(envname).arg(envname)); } } else { // find next '}' error_list.append(tr("error @ ch. %1: text after '\\begin{' expected!").arg(currentTokenID)); while (currentToken!=MTTclosebrace) getToken(); getNew=true; } } else if (name=="vec") { nl->addNode(new MTdecoratedNode(this, MTDvec, parseLatexString(true))); } else if (name=="overline"||name=="oline"||name=="ol") { nl->addNode(new MTdecoratedNode(this, MTDoverline, parseLatexString(true))); } else if (name=="underline"||name=="uline"||name=="ul") { nl->addNode(new MTdecoratedNode(this, MTDunderline, parseLatexString(true))); } else if (name=="uuline"||name=="uul") { nl->addNode(new MTdecoratedNode(this, MTDdoubleunderline, parseLatexString(true))); } else if (name=="ooline"||name=="ool") { nl->addNode(new MTdecoratedNode(this, MTDdoubleoverline, parseLatexString(true))); } else if (name=="arrow") { nl->addNode(new MTdecoratedNode(this, MTDarrow, parseLatexString(true))); } else if (name=="hat") { nl->addNode(new MTdecoratedNode(this, MTDhat, parseLatexString(true))); } else if (name=="bar") { nl->addNode(new MTdecoratedNode(this, MTDbar, parseLatexString(true))); } else if (name=="dot") { nl->addNode(new MTdecoratedNode(this, MTDdot, parseLatexString(true))); } else if (name=="tilde") { nl->addNode(new MTdecoratedNode(this, MTDtilde, parseLatexString(true))); } else if (name=="ddot") { nl->addNode(new MTdecoratedNode(this, MTDddot, parseLatexString(true))); } else { if (name=="textcolor" || name=="mathcolor" || name=="color" || name=="colorbox") { bool foundError=true; QString col=""; if (getToken()==MTTtext) { col=currentTokenName; if (getToken()==MTTclosebrace) { if (getToken()==MTTopenbrace) { foundError=false; } } } if (foundError) error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(name)); else nl->addNode(new MTinstruction1Node(this, name, parseLatexString(true), QStringList(col))); } else { nl->addNode(new MTinstruction1Node(this, name, parseLatexString(true))); } } } else { //std::cout<<"did not find '{' after '"<0) { if (QString(currentTokenName[0])==quitOnClosingBrace || quitOnClosingBrace=="any" || QString(currentTokenName[0])==".") { //std::cout<<"found \\right '"<" && (currentTokenName=="rangle" || QString(currentTokenName[0])==".")) { showRightBrace=(QString(currentTokenName[0])!="."); currentTokenName=currentTokenName.right(currentTokenName.size()-1); break; } else if (quitOnClosingBrace=="any") { showRightBrace=(QString(currentTokenName[0])!="."); //currentTokenName=currentTokenName.right(currentTokenName.size()-1); break; } } else { getNew=false; } } else if (name=="left") { if (currentToken==MTTtext) { if (currentTokenName.size()>0) { if (currentTokenName[0]=='(') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); // we already used the first character from the text token! nl->addNode(new MTbraceNode(this, "(", ")", parseLatexString(currentTokenName.size()<=0, ")"), showRightBrace)); } else if (currentTokenName[0]=='[') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "[", "]", parseLatexString(currentTokenName.size()<=0, "]"), showRightBrace)); } else if (currentTokenName[0]=='{') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "{", "}", parseLatexString(currentTokenName.size()<=0, "}"), showRightBrace)); } else if (currentTokenName[0]=='<') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "<", ">", parseLatexString(currentTokenName.size()<=0, ">"), showRightBrace)); } else if (currentTokenName[0]=='|') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "|", "|", parseLatexString(currentTokenName.size()<=0, "|"), showRightBrace)); } else if (currentTokenName[0]=='~') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "~", "~", parseLatexString(currentTokenName.size()<=0, "~"), showRightBrace)); } else if (currentTokenName[0]=='_') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "_", "_", parseLatexString(currentTokenName.size()<=0, "_"), showRightBrace)); } else if (currentTokenName[0]=='#') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "#", "#", parseLatexString(currentTokenName.size()<=0, "#"), showRightBrace)); } else if (currentTokenName[0]=='.') { currentTokenName=currentTokenName.right(currentTokenName.size()-1); JKQTmathText::MTnode* cn=parseLatexString(currentTokenName.size()<=0, "any"); nl->addNode(new MTbraceNode(this, ".", currentTokenName, cn, showRightBrace)); } else { getNew=false; } } } else if (currentToken==MTTinstruction && currentTokenName=="langle") { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "<", ">", parseLatexString(true, ">"), showRightBrace)); } else if (currentToken==MTTinstruction && currentTokenName=="{") { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "{", "}", parseLatexString(currentTokenName.size()<=0, "}"), showRightBrace)); } else if (currentToken==MTTinstruction && currentTokenName=="lfloor") { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "_", "_", parseLatexString(true, "_"), showRightBrace)); } else if (currentToken==MTTinstruction && currentTokenName=="lceil") { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "~", "~", parseLatexString(true, "~"), showRightBrace)); } else if (currentToken==MTTinstruction && currentTokenName=="|") { currentTokenName=currentTokenName.right(currentTokenName.size()-1); nl->addNode(new MTbraceNode(this, "#", "#", parseLatexString(currentTokenName.size()<=0, "#"), showRightBrace)); } else if (currentToken==MTTinstruction && currentTokenName==quitOnClosingBrace) { break; } } else { //bool addWhite=(currentToken==MTTwhitespace); //getNew=addWhite; getNew=false; bool done=false; if (name.size()==2) { QChar n0=name[0]; QChar n1=name[1]; if (n0=='v' && n1.isLetter()) { done=true; //std::cout<<"found \\v... command\n"; nl->addNode(new MTdecoratedNode(this, MTDvec, new MTtextNode(this, QString(n1), false, parsingMathEnvironment))); } else if (n0=='c' && n1.isLetter()) { done=true; //std::cout<<"found \\v... command\n"; nl->addNode(new MTinstruction1Node(this, "mathcal", new MTtextNode(this, QString(n1), false, parsingMathEnvironment))); } } else if (name.size()==3) { QString n0=name.left(2); QChar n1=name[name.size()-1]; if (n0=="bb" && n1.isLetter()) { done=true; //std::cout<<"found \\v... command\n"; nl->addNode(new MTinstruction1Node(this, "mathbb", new MTtextNode(this, QString(n1), false, parsingMathEnvironment))); } } if (!done) nl->addNode(new MTsymbolNode(this, name, false));//, addWhite)); } } } else if (currentToken==MTTwhitespace) { if (!parsingMathEnvironment) nl->addNode(new MTwhitespaceNode(this)); } else if (currentToken==MTTunderscore) { getToken(); MTnode* child=nullptr; MTnode* child2=nullptr; if (currentToken==MTTinstruction) { QString name=currentTokenName; getToken(); // look at next token if (currentToken==MTTopenbrace) { child=new MTinstruction1Node(this, name, parseLatexString(true)); } else { //bool addWhite=(currentToken==MTTwhitespace); //getNew=addWhite; //child=new MTsymbolNode(this, name, addWhite); getNew=false; child=new MTsymbolNode(this, name, false); } } else if (currentToken==MTTopenbrace) { child=parseLatexString(true); } else if (currentToken==MTTtext) { if (currentTokenName.size()<=1) { child=new MTtextNode(this, currentTokenName, false, parsingMathEnvironment); } else { child=new MTtextNode(this, QString(currentTokenName[0]), false, parsingMathEnvironment); child2=new MTtextNode(this, currentTokenName.right(currentTokenName.size()-1), false, parsingMathEnvironment); } } else { getNew=false; } if (child!=nullptr) nl->addNode(new MTsubscriptNode(this, child)); if (child2!=nullptr) nl->addNode(child2); } else if (currentToken==MTThat) { getToken(); MTnode* child=nullptr; MTnode* child2=nullptr; if (currentToken==MTTinstruction) { QString name=currentTokenName; getToken(); // look at next token if (currentToken==MTTopenbrace) { child=new MTinstruction1Node(this, name, parseLatexString(true)); } else { //bool addWhite=(currentToken==MTTwhitespace); //getNew=addWhite; //child=new MTsymbolNode(this, name, addWhite); getNew=false; child=new MTsymbolNode(this, name, false); } } else if (currentToken==MTTopenbrace) { child=parseLatexString(true); } else if (currentToken==MTTtext) { if (currentTokenName.size()<=1) { child=new MTtextNode(this, currentTokenName, false, parsingMathEnvironment); } else { child=new MTtextNode(this, QString(currentTokenName[0]), false, parsingMathEnvironment); child2=new MTtextNode(this, currentTokenName.right(currentTokenName.size()-1), false, parsingMathEnvironment); } } else { getNew=false; } if (child!=nullptr) nl->addNode(new MTsuperscriptNode(this, child)); if (child2!=nullptr) nl->addNode(child2); } else if (currentToken==MTTopenbrace) { nl->addNode(parseLatexString(true)); } else if (currentToken==MTTclosebrace) { break; } else if (currentToken==MTTampersand) { break; } else if (currentToken==MTTdollar) { if (parsingMathEnvironment) { // reached end of math environment parsingMathEnvironment=false; break; } else { // starting math environment parsingMathEnvironment=true; nl->addNode(new MTinstruction1Node(this, "equation", parseLatexString(true))); } } if (getNew) getToken(); } //std::cout<<" leaving parseLatexString()\n"; return nl; } QList JKQTmathText::tbrs=QList(); QHash JKQTmathText::tbrh=QHash(); QRectF JKQTmathText::getTBR(const QFont &fm, const QString &text, QPaintDevice *pd) { JKQTmathText::tbrDataH dh(fm, text, pd); if (pd) { if (tbrh.contains(dh)) return tbrh[dh]; /*for (int i=0; ilogicalDpiX() && tbrs[i].ldpiY==pd->logicalDpiY() && tbrs[i].pdpiX==pd->physicalDpiX() && tbrs[i].pdpiY==pd->physicalDpiY())) { //qDebug()<<" ### "<getSize(painter, ev, width, ascent, overallHeight, strikeoutPos); descent=overallHeight-ascent; ascent=ascent*1.1; descent=qMax(ascent*0.1, descent*1.1); strikeoutPos=strikeoutPos*1.1; } } void JKQTmathText::draw(QPainter& painter, double x, double y, bool drawBoxes){ if (getTree()!=nullptr) { MTenvironment ev; ev.color=fontColor; ev.fontSize=fontSize; getTree()->set_drawBoxes(drawBoxes); getTree()->draw(painter, x, y, ev); } } void JKQTmathText::draw(QPainter& painter, int flags, QRectF rect, bool drawBoxes) { if (getTree()!=nullptr) { MTenvironment ev; ev.color=fontColor; ev.fontSize=fontSize; getTree()->set_drawBoxes(drawBoxes); double width=0; double baselineHeight=0; double overallHeight=0, strikeoutPos=0; getTree()->getSize(painter, ev, width, baselineHeight, overallHeight, strikeoutPos); // align left top double x=rect.left(); double y=rect.top()+baselineHeight; // care for horizontal align if ((flags & Qt::AlignRight) != 0) x=x+rect.width()-width; else if ((flags & Qt::AlignHCenter) != 0) x=x+(rect.width()-width)/2.0; // care for vertical align if ((flags & Qt::AlignBottom) != 0) y=y+rect.height()-overallHeight; else if ((flags & Qt::AlignVCenter) != 0) y=y+(rect.height()-overallHeight)/2.0; // finally draw getTree()->draw(painter, x, y, ev); } } JKQTmathText::MTwhitespaceNode::MTwhitespaceNode(JKQTmathText *parent): MTtextNode(parent, " ", false, false) { } JKQTmathText::MTwhitespaceNode::~MTwhitespaceNode() { } QString JKQTmathText::MTwhitespaceNode::getTypeName() const { return QLatin1String("MTwhitespaceNode(")+text+")"; } bool JKQTmathText::MTwhitespaceNode::toHtml(QString &html, JKQTmathText::MTenvironment /*currentEv*/, JKQTmathText::MTenvironment /*defaultEv*/) { html=html+" "; return true; } void JKQTmathText::MTnode::set_drawBoxes(bool draw) { this->drawBoxes=draw; } QString JKQTmathText::MTnode::getTypeName() const { return "MTnode"; } QString JKQTmathText::fracModeToString(JKQTmathText::MTfracMode mode) { switch(mode) { case MTFMfrac: return "frac"; case MTFMdfrac: return "dfrac"; case MTFMtfrac: return "tfrac"; case MTFMunderbrace: return "underbrace"; case MTFMoverbrace: return "overbrace"; case MTFMunderset: return "underset"; case MTFMoverset: return "overset"; case MTFMstackrel: return "stackrel"; } return "unknown"; } QString JKQTmathText::decorationToString(JKQTmathText::MTdecoration mode) { switch(mode) { case MTDvec: return "vec"; case MTDtilde: return "tilde"; case MTDhat: return "hat"; case MTDdot: return "dot"; case MTDddot: return "ddot"; case MTDbar: return "bar"; case MTDarrow: return "arrow"; case MTDoverline: return "overline"; case MTDdoubleoverline: return "double overline"; case MTDunderline: return "underline"; case MTDdoubleunderline: return "double underline"; } return "unknown"; } JKQTMathTextLabel::JKQTMathTextLabel(QWidget *parent): QLabel(parent) { m_mathText=new JKQTmathText(this); m_mathText->useXITS(); m_mathText->set_fontSize(font().pointSizeF()*1.3); lastText=""; repaintDo=true; buffer=QPixmap(); } JKQTMathTextLabel::~JKQTMathTextLabel() { } JKQTmathText *JKQTMathTextLabel::getMathText() const { return m_mathText; } void JKQTMathTextLabel::setMath(const QString &text, bool doRepaint) { if (text!=lastText || doRepaint){ lastText=text; repaintDo=true; internalPaint(); update(); } } void JKQTMathTextLabel::internalPaint() { //return; //qDebug()<<"internalPaint "<parse(lastText)<<"\n "<get_error_list().join("\n")<<"\n\n"; if (!m_mathText->parse(lastText)) { qDebug()<<"JKQTMathTextLabel::internalPaint(): parse '"<parse(lastText)<<"\n "<get_error_list().join("\n")<<"\n\n"; } if (buffer.width()<=0 || buffer.height()<=0) buffer=QPixmap(1000,100); //qDebug()<<"internalPaint(): buffer "<getSize(p); p.end(); } buffer=QPixmap(qMax(32.0,size.width()*1.2), qMax(10.0,size.height()*1.1)); buffer.fill(Qt::transparent); { //qDebug()<<"internalPaint(): "<draw(p,alignment(), QRectF(QPointF(0,0), size)); p.end(); } setPixmap(buffer); //} //qDebug()<<"internalPaint(): setPixmap"; QApplication::processEvents(); //qDebug()<<"internalPaint(): DONE"; } void JKQTMathTextLabel::paintEvent(QPaintEvent *event) { //QLabel::paintEvent(event); //return; //qDebug()<<"paintEvent: "<text=text; this->tbr=this->fm.tightBoundingRect(text); this->f=f; //this->pd=pd; if (pd) { ldpiX=pd->logicalDpiX(); ldpiY=pd->logicalDpiY(); pdpiX=pd->physicalDpiX(); pdpiY=pd->physicalDpiY(); } else { ldpiX=0; ldpiY=0; pdpiX=0; pdpiY=0; } } bool JKQTmathText::tbrData::operator==(const JKQTmathText::tbrData &other) const { return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f; } JKQTmathText::tbrDataH::tbrDataH(const QFont &f, const QString &text, QPaintDevice *pd) { this->text=text; this->f=f; if (pd) { ldpiX=pd->logicalDpiX(); ldpiY=pd->logicalDpiY(); pdpiX=pd->physicalDpiX(); pdpiY=pd->physicalDpiY(); } else { ldpiX=0; ldpiY=0; pdpiX=0; pdpiY=0; } } bool JKQTmathText::tbrDataH::operator==(const JKQTmathText::tbrDataH &other) const { return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f; } JKQTmathText::MTplainTextNode::MTplainTextNode(JKQTmathText *parent, QString text, bool addWhitespace, bool stripInnerWhitepace): JKQTmathText::MTtextNode(parent, text, addWhitespace, stripInnerWhitepace) { } QString JKQTmathText::MTplainTextNode::getTypeName() const {return QLatin1String("MTplainTextNode(")+text+")"; } QString JKQTmathText::MTplainTextNode::textTransform(const QString &text, JKQTmathText::MTenvironment /*currentEv*/, bool /*forSize*/) { return text; } void initJKQtMathTextResources() { Q_INIT_RESOURCE(xits); }