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