2022-06-08 21:38:26 +08:00
|
|
|
/*
|
|
|
|
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
|
|
|
|
|
2022-08-02 18:16:10 +08:00
|
|
|
|
2022-06-08 21:38:26 +08:00
|
|
|
|
|
|
|
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/nodes/jkqtmathtexttextnode.h"
|
|
|
|
#include "jkqtmathtext/jkqtmathtexttools.h"
|
|
|
|
#include "jkqtmathtext/nodes/jkqtmathtextnode.h"
|
|
|
|
#include "jkqtmathtext/jkqtmathtext.h"
|
|
|
|
#include "jkqtcommon/jkqtpcodestructuring.h"
|
|
|
|
#include "jkqtcommon/jkqtpstringtools.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include <QFontMetricsF>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QFontDatabase>
|
|
|
|
#include <QFontInfo>
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QFont>
|
|
|
|
|
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JKQTMathTextTextBaseNode::JKQTMathTextTextBaseNode(JKQTMathText *parent, const QString &text_):
|
|
|
|
JKQTMathTextNode(parent),
|
|
|
|
text(text_)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
JKQTMathTextTextBaseNode::~JKQTMathTextTextBaseNode()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QString JKQTMathTextTextBaseNode::getText() const
|
|
|
|
{
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-08-10 18:12:30 +08:00
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
|
|
|
|
QString JKQTMathTextTextBaseNode::textTransform(const QString &text, const JKQTMathTextEnvironment &/*currentEv*/) const
|
|
|
|
{
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool JKQTMathTextTextBaseNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) {
|
|
|
|
html=html
|
|
|
|
+currentEv.toHtmlStart(defaultEv, parentMathText)
|
|
|
|
+textTransform(text, currentEv).toHtmlEscaped()
|
|
|
|
+currentEv.toHtmlAfter(defaultEv, parentMathText);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-08-10 18:12:30 +08:00
|
|
|
QHash<QChar, uint32_t> JKQTMathTextTextNode::blackboardUnicodeTable=QHash<QChar, uint32_t>();
|
|
|
|
|
|
|
|
void JKQTMathTextTextNode::fillStaticTables() {
|
|
|
|
if (blackboardUnicodeTable.size()>0) return;
|
|
|
|
|
|
|
|
blackboardUnicodeTable['C']=0x2102;
|
|
|
|
blackboardUnicodeTable['H']=0x210D;
|
|
|
|
blackboardUnicodeTable['N']=0x2115;
|
|
|
|
blackboardUnicodeTable['P']=0x2119;
|
|
|
|
blackboardUnicodeTable['Q']=0x211A;
|
|
|
|
blackboardUnicodeTable['R']=0x211D;
|
|
|
|
blackboardUnicodeTable['Z']=0x2124;
|
|
|
|
|
|
|
|
for (const QChar ch: QString("ABDEFGIJKLMOSTUVWXYZ")) {
|
|
|
|
blackboardUnicodeTable[ch]=0x1D538+(ch.unicode()-QChar('A').unicode());
|
|
|
|
}
|
|
|
|
for (const QChar ch: QString("abcdefghijklmnopqrstuvwxyz")) {
|
|
|
|
blackboardUnicodeTable[ch]=0x1D552+(ch.unicode()-QChar('a').unicode());
|
|
|
|
}
|
|
|
|
for (const QChar ch: QString("0123456789")) {
|
|
|
|
blackboardUnicodeTable[ch]=0x1D7D8+(ch.unicode()-QChar('0').unicode());
|
|
|
|
}
|
|
|
|
}
|
2022-08-03 21:23:14 +08:00
|
|
|
|
2022-06-08 21:38:26 +08:00
|
|
|
JKQTMathTextTextNode::JKQTMathTextTextNode(JKQTMathText* _parent, const QString& textIn, bool addWhitespace, bool stripInnerWhitepace):
|
2022-08-03 21:23:14 +08:00
|
|
|
JKQTMathTextTextBaseNode(_parent, "")
|
2022-06-08 21:38:26 +08:00
|
|
|
{
|
2022-08-10 18:12:30 +08:00
|
|
|
fillStaticTables();
|
2022-08-03 21:23:14 +08:00
|
|
|
QString textTransformed=textIn;
|
2022-06-08 21:38:26 +08:00
|
|
|
|
|
|
|
if (stripInnerWhitepace) {
|
2022-08-03 21:23:14 +08:00
|
|
|
textTransformed="";
|
2022-06-08 21:38:26 +08:00
|
|
|
for (int i=0; i<textIn.size(); i++) {
|
2022-08-03 21:23:14 +08:00
|
|
|
if (!textIn[i].isSpace()) textTransformed+=textIn[i];
|
2022-06-08 21:38:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
text=textTransformed;
|
2022-06-08 21:38:26 +08:00
|
|
|
// strip all whitespace from left
|
2022-08-03 21:23:14 +08:00
|
|
|
while (text.size()>1 && text[0].isSpace()) {
|
|
|
|
text=text.right(text.size()-1);
|
2022-06-08 21:38:26 +08:00
|
|
|
}
|
2022-08-03 21:23:14 +08:00
|
|
|
if (addWhitespace && (text.size()>0) && (!text[text.size()-1].isSpace())) text=text+" ";
|
2022-06-08 21:38:26 +08:00
|
|
|
//qDebug()<<"JKQTMathTextTextNode( text="<<text<<" addWhitespace="<<addWhitespace<<") [=> this->text="<<this->text<<"]";
|
|
|
|
}
|
|
|
|
|
|
|
|
JKQTMathTextTextNode::~JKQTMathTextTextNode() = default;
|
|
|
|
|
|
|
|
void JKQTMathTextTextNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* /*prevNodeSize*/) {
|
2022-08-02 18:16:10 +08:00
|
|
|
QStringList textpart;
|
2022-08-10 18:12:30 +08:00
|
|
|
QList<FontMode> fontMode;
|
2022-08-02 18:16:10 +08:00
|
|
|
QList<double> textpartXPos;
|
2022-08-10 18:12:30 +08:00
|
|
|
getSizeInternalAndData(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos,textpart, fontMode, textpartXPos);
|
2022-08-02 18:16:10 +08:00
|
|
|
}
|
|
|
|
|
2022-08-10 18:12:30 +08:00
|
|
|
void JKQTMathTextTextNode::getSizeInternalAndData(QPainter &painter, JKQTMathTextEnvironment currentEv, double &width, double &baselineHeight, double &overallHeight, double &strikeoutPos, QStringList &textpart, QList<FontMode> &fontMode, QList<double> &textpartXPos)
|
2022-08-02 18:16:10 +08:00
|
|
|
{
|
|
|
|
textpart.clear();
|
2022-08-10 18:12:30 +08:00
|
|
|
fontMode.clear();
|
2022-08-03 21:23:14 +08:00
|
|
|
const QString txt=textTransform(text, currentEv);
|
2022-08-10 18:12:30 +08:00
|
|
|
splitTextForLayout(painter, currentEv, txt, textpart, fontMode);
|
2022-08-02 18:16:10 +08:00
|
|
|
|
|
|
|
const QFont f=currentEv.getFont(parentMathText);
|
2022-08-10 18:12:30 +08:00
|
|
|
const QFont fUpright=JKQTMathTextGetNonItalic(f);
|
|
|
|
const QFont fFallbackSym=currentEv.exchangedFontFor(MTEFallbackSymbols).getFont(parentMathText);
|
|
|
|
const QFont fRoman=currentEv.exchangedFontForRoman().getFont(parentMathText);
|
|
|
|
const QFontMetricsF fmUpright(fUpright, painter.device());
|
2022-08-02 18:16:10 +08:00
|
|
|
const QFontMetricsF fm(f, painter.device());
|
2022-08-10 18:12:30 +08:00
|
|
|
const QFontMetricsF fmFallbackSym(fFallbackSym, painter.device());
|
|
|
|
const QFontMetricsF fmRoman(fRoman, painter.device());
|
2022-08-03 21:23:14 +08:00
|
|
|
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
|
|
|
|
const double sp=fm.horizontalAdvance(' ');
|
|
|
|
#else
|
|
|
|
const double sp=fm.width(' ');
|
|
|
|
#endif
|
2022-08-02 18:16:10 +08:00
|
|
|
width=0;
|
|
|
|
double ascent=0;
|
|
|
|
double descent=0;
|
|
|
|
for (int i=0; i<textpart.size(); i++) {
|
2022-08-10 18:12:30 +08:00
|
|
|
QRectF br, tbr;
|
|
|
|
switch(fontMode[i]) {
|
|
|
|
case FMasDefined:
|
|
|
|
case FMasDefinedOutline:
|
|
|
|
br=fm.boundingRect(textpart[i]);
|
|
|
|
tbr=JKQTMathTextGetTightBoundingRect(f, textpart[i], painter.device());
|
|
|
|
break;
|
|
|
|
case FMasDefinedForceUpright:
|
|
|
|
br=fmUpright.boundingRect(textpart[i]);
|
|
|
|
tbr=JKQTMathTextGetTightBoundingRect(fUpright, textpart[i], painter.device());
|
|
|
|
break;
|
|
|
|
case FMroman:
|
|
|
|
br=fmRoman.boundingRect(textpart[i]);
|
|
|
|
tbr=JKQTMathTextGetTightBoundingRect(fRoman, textpart[i], painter.device());
|
|
|
|
break;
|
|
|
|
case FMfallbackSymbol:
|
|
|
|
br=fmFallbackSym.boundingRect(textpart[i]);
|
|
|
|
tbr=JKQTMathTextGetTightBoundingRect(fFallbackSym, textpart[i], painter.device());
|
|
|
|
break;
|
|
|
|
}
|
2022-08-02 18:16:10 +08:00
|
|
|
textpartXPos.append(width);
|
|
|
|
width+=br.width();
|
2022-08-03 21:23:14 +08:00
|
|
|
if (textpart[i].size()>0 && textpart[i].at(textpart[i].size()-1).isSpace()) {
|
|
|
|
// this correction is necessary, because it seems that QFontMetricsF::boundingRect() ignores trailing spaces
|
|
|
|
width+=sp;
|
|
|
|
}
|
2022-08-02 18:16:10 +08:00
|
|
|
const double thisAscent=-tbr.top();
|
|
|
|
const double thisDescent=tbr.bottom();
|
|
|
|
ascent=qMax(ascent, thisAscent);
|
|
|
|
descent=qMax(descent, thisDescent);
|
2022-06-08 21:38:26 +08:00
|
|
|
}
|
2022-08-02 18:16:10 +08:00
|
|
|
overallHeight=(ascent+descent); //fm.height();
|
|
|
|
baselineHeight=ascent;
|
|
|
|
strikeoutPos=fm.strikeOutPos();
|
|
|
|
}
|
2022-06-08 21:38:26 +08:00
|
|
|
|
2022-08-10 18:12:30 +08:00
|
|
|
void JKQTMathTextTextNode::splitTextForLayout(QPainter &painter, JKQTMathTextEnvironment currentEv, const QString &txt, QStringList &textpart, QList<FontMode> &fontMode) const
|
2022-08-02 18:16:10 +08:00
|
|
|
{
|
|
|
|
auto isForcedUprightChar=[](const QChar& c) {
|
|
|
|
return c.isDigit()
|
|
|
|
|| c=='(' || c=='[' || c=='|' || c==']' || c==')' || c=='<' || c=='>'|| c=='{' || c=='}' || c=='|'
|
|
|
|
|| c==QChar(0x2329) || c==QChar(0x232A) || c==QChar(0x2308) || c==QChar(0x2309) || c==QChar(0x230A) || c==QChar(0x230B);
|
|
|
|
};
|
|
|
|
|
2022-08-10 18:12:30 +08:00
|
|
|
//const QFont f=currentEv.getFont(parentMathText);
|
|
|
|
//const QFont fUpright=JKQTMathTextGetNonItalic(f);
|
|
|
|
const QFont fFallbackSym=currentEv.exchangedFontFor(MTEFallbackSymbols).getFont(parentMathText);
|
|
|
|
const QFont fRoman=currentEv.exchangedFontForRoman().getFont(parentMathText);
|
|
|
|
//const QFontMetricsF fm(f, painter.device());
|
|
|
|
//const QFontMetricsF fmUpright(fUpright, painter.device());
|
|
|
|
const QFontMetricsF fmFallbackSym(fFallbackSym, painter.device());
|
|
|
|
const QFontMetricsF fmRoman(fRoman, painter.device());
|
|
|
|
const JKQTMathTextBlackboradDrawingMode bbMode=parentMathText->getFontBlackboradMode();
|
|
|
|
|
2022-08-02 18:16:10 +08:00
|
|
|
textpart.clear();
|
2022-08-10 18:12:30 +08:00
|
|
|
fontMode.clear();
|
2022-08-02 18:16:10 +08:00
|
|
|
QString currentSection="";
|
2022-08-10 18:12:30 +08:00
|
|
|
FontMode currentSectionFontMode=FMasDefined;
|
2022-08-02 18:16:10 +08:00
|
|
|
int i=0;
|
|
|
|
while (i<txt.size()) {
|
|
|
|
const QChar c=txt[i];
|
2022-08-10 18:12:30 +08:00
|
|
|
QString cs=c;
|
|
|
|
FontMode CFontMode=FMasDefined;
|
2022-08-02 18:16:10 +08:00
|
|
|
const bool CisForcedUprightChar=isForcedUprightChar(c);
|
|
|
|
const bool CisForcedUprightCharExt=CisForcedUprightChar||(c=='.')||(c==',');
|
2022-08-10 18:12:30 +08:00
|
|
|
if (currentEv.insideMath && currentEv.insideMathForceDigitsUpright && (currentEv.font==MTEroman || currentEv.font==MTEmathRoman)) {
|
|
|
|
if (currentSection.size()==0) {
|
|
|
|
if (CisForcedUprightChar) {
|
|
|
|
CFontMode=FMasDefinedForceUpright;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (CisForcedUprightCharExt) {
|
|
|
|
CFontMode=FMasDefinedForceUpright;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (currentEv.font==MTEblackboard) {
|
|
|
|
if (bbMode==MTBBDMfontDirectly) {
|
|
|
|
CFontMode=FMasDefined;
|
|
|
|
} else if (bbMode==MTBBDMsimulate) {
|
|
|
|
CFontMode=FMasDefinedOutline;
|
|
|
|
} else if (bbMode==MTBBDMunicodeCharactersOrSimulate || bbMode==MTBBDMunicodeCharactersOrFontDirectly) {
|
|
|
|
if (blackboardUnicodeTable.contains(c) && fmRoman.inFontUcs4(blackboardUnicodeTable[c])) {
|
|
|
|
cs=jkqtp_UnicodeToUTF8Q(blackboardUnicodeTable[c]);
|
|
|
|
CFontMode=FMroman;
|
|
|
|
} else if (blackboardUnicodeTable.contains(c) && fmFallbackSym.inFontUcs4(blackboardUnicodeTable[c])) {
|
|
|
|
cs=jkqtp_UnicodeToUTF8Q(blackboardUnicodeTable[c]);
|
|
|
|
CFontMode=FMfallbackSymbol;
|
|
|
|
} else {
|
|
|
|
if (bbMode==MTBBDMunicodeCharactersOrSimulate) {
|
|
|
|
CFontMode=FMasDefinedOutline;
|
|
|
|
} else if (bbMode==MTBBDMunicodeCharactersOrFontDirectly) {
|
|
|
|
CFontMode=FMasDefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-02 18:16:10 +08:00
|
|
|
if (currentSection.size()==0) {
|
|
|
|
// start new section
|
2022-08-10 18:12:30 +08:00
|
|
|
currentSectionFontMode=CFontMode;
|
|
|
|
currentSection+=cs;
|
2022-08-02 18:16:10 +08:00
|
|
|
} else {
|
|
|
|
// existing section
|
2022-08-10 18:12:30 +08:00
|
|
|
if (CFontMode==currentSectionFontMode) {
|
2022-08-02 18:16:10 +08:00
|
|
|
// continue current section
|
2022-08-10 18:12:30 +08:00
|
|
|
currentSection+=cs;
|
2022-08-02 18:16:10 +08:00
|
|
|
} else {
|
|
|
|
// start new section
|
|
|
|
textpart.append(currentSection);
|
2022-08-10 18:12:30 +08:00
|
|
|
fontMode.append(currentSectionFontMode);
|
|
|
|
currentSection=cs;
|
|
|
|
currentSectionFontMode=CFontMode;
|
2022-08-02 18:16:10 +08:00
|
|
|
}
|
|
|
|
}
|
2022-08-10 18:12:30 +08:00
|
|
|
|
2022-08-02 18:16:10 +08:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (currentSection.size()>0) {
|
|
|
|
textpart.append(currentSection);
|
2022-08-10 18:12:30 +08:00
|
|
|
fontMode.append(currentSectionFontMode);
|
2022-08-02 18:16:10 +08:00
|
|
|
}
|
2022-06-08 21:38:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTMathTextTextNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* /*prevNodeSize*/) {
|
|
|
|
doDrawBoxes(painter, x, y, currentEv);
|
|
|
|
double width=0;
|
|
|
|
double baselineHeight=0;
|
|
|
|
double overallHeight=0;
|
|
|
|
double sp=0;
|
2022-08-02 18:16:10 +08:00
|
|
|
QStringList textpart;
|
|
|
|
QList<double> textpartXPos;
|
2022-08-10 18:12:30 +08:00
|
|
|
QList<FontMode> fontMode;
|
|
|
|
getSizeInternalAndData(painter, currentEv, width, baselineHeight, overallHeight, sp, textpart, fontMode, textpartXPos);
|
2022-06-08 21:38:26 +08:00
|
|
|
|
|
|
|
|
2022-08-02 18:16:10 +08:00
|
|
|
const QFont f=currentEv.getFont(parentMathText);
|
2022-08-10 18:12:30 +08:00
|
|
|
const QFont fUpright=JKQTMathTextGetNonItalic(f);
|
|
|
|
const QFont fFallbackSym=currentEv.exchangedFontFor(MTEFallbackSymbols).getFont(parentMathText);
|
|
|
|
const QFont fRoman=currentEv.exchangedFontForRoman().getFont(parentMathText);
|
2022-08-02 18:16:10 +08:00
|
|
|
const QFontMetricsF fm(f, painter.device());
|
2022-08-10 18:12:30 +08:00
|
|
|
const QFontMetricsF fmUpright(fUpright, painter.device());
|
|
|
|
const QFontMetricsF fmFallbackSym(fFallbackSym, painter.device());
|
|
|
|
const QFontMetricsF fmRoman(fRoman, painter.device());
|
2022-06-08 21:38:26 +08:00
|
|
|
|
2022-08-02 18:16:10 +08:00
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
2022-06-08 21:38:26 +08:00
|
|
|
painter.setFont(f);
|
2022-08-10 18:12:30 +08:00
|
|
|
painter.setPen(currentEv.color);
|
2022-06-08 21:38:26 +08:00
|
|
|
|
|
|
|
//qDebug()<<"JKQTMathTextTextNode: text="<<text<<" font="<<f;
|
|
|
|
|
2022-08-02 18:16:10 +08:00
|
|
|
|
|
|
|
for (int i=0; i<textpart.size(); i++) {
|
2022-08-10 18:12:30 +08:00
|
|
|
switch(fontMode[i]) {
|
|
|
|
case FMasDefined:
|
|
|
|
painter.setFont(f);
|
|
|
|
painter.drawText(QPointF(x+textpartXPos[i], y), textpart[i]);
|
|
|
|
break;
|
|
|
|
case FMasDefinedOutline:
|
|
|
|
JKQTMathTextDrawStringSimBlackboard(painter, f, currentEv.color, x+textpartXPos[i], y, textpart[i]);
|
|
|
|
break;
|
|
|
|
case FMasDefinedForceUpright:
|
|
|
|
painter.setFont(fUpright);
|
|
|
|
painter.drawText(QPointF(x+textpartXPos[i], y), textpart[i]);
|
|
|
|
break;
|
|
|
|
case FMroman:
|
|
|
|
painter.setFont(fRoman);
|
|
|
|
painter.drawText(QPointF(x+textpartXPos[i], y), textpart[i]);
|
|
|
|
break;
|
|
|
|
case FMfallbackSymbol:
|
|
|
|
painter.setFont(fFallbackSym);
|
|
|
|
painter.drawText(QPointF(x+textpartXPos[i], y), textpart[i]);
|
|
|
|
break;
|
|
|
|
}
|
2022-06-08 21:38:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return x+width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QString JKQTMathTextTextNode::getTypeName() const
|
|
|
|
{
|
|
|
|
return QLatin1String("JKQTMathTextTextNode(")+text+")";
|
|
|
|
}
|
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
QString JKQTMathTextTextNode::textTransform(const QString &text, const JKQTMathTextEnvironment ¤tEv) const
|
2022-06-08 21:38:26 +08:00
|
|
|
{
|
|
|
|
QString txt=text;
|
2022-06-09 05:52:22 +08:00
|
|
|
auto fnt=parentMathText->getFontData(currentEv.font, currentEv.insideMath);
|
2022-08-03 21:23:14 +08:00
|
|
|
const QFontMetricsF fm(currentEv.getFont(parentMathText));
|
|
|
|
if (fnt.second==MTFELatin1 || fnt.second==MTFEUnicode) {
|
2022-06-08 21:38:26 +08:00
|
|
|
if (currentEv.insideMath) {
|
|
|
|
txt="";
|
|
|
|
for (int i=0; i<text.size(); i++) {
|
|
|
|
QChar c=text[i];
|
|
|
|
switch(c.unicode()) {
|
2022-08-03 21:23:14 +08:00
|
|
|
case '-':
|
|
|
|
if (fm.inFont(QChar(0x2212))) {
|
|
|
|
txt+=QString(QString(" ")+QChar(0x2212));
|
|
|
|
} else {
|
|
|
|
txt+=QString(QString(" -"));
|
|
|
|
}
|
|
|
|
break;
|
2022-06-08 21:38:26 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-08-10 18:12:30 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
JKQTMathTextVerbatimNode::JKQTMathTextVerbatimNode(JKQTMathText *_parent, const QString& _text, bool visibleWhitespace_, JKQTMathTextHorizontalAlignment _alignment, double _linespacingFactor, JKQTMathTextVerticalOrientation _verticalOrientation):
|
|
|
|
JKQTMathTextTextBaseNode(_parent, _text),
|
|
|
|
alignment(_alignment),
|
|
|
|
lineSpacingFactor(_linespacingFactor),
|
|
|
|
verticalOrientation(_verticalOrientation),
|
|
|
|
visibleWhitespace(visibleWhitespace_)
|
2022-06-08 21:38:26 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
QString JKQTMathTextVerbatimNode::getTypeName() const
|
2022-06-08 21:38:26 +08:00
|
|
|
{
|
2022-08-03 21:23:14 +08:00
|
|
|
return QLatin1String("JKQTMathTextVerbatimNode");
|
2022-06-08 21:38:26 +08:00
|
|
|
}
|
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
JKQTMathTextHorizontalAlignment JKQTMathTextVerbatimNode::getAlignment() const
|
|
|
|
{
|
|
|
|
return alignment;
|
|
|
|
}
|
|
|
|
|
|
|
|
JKQTMathTextVerticalOrientation JKQTMathTextVerbatimNode::getVerticalOrientation() const
|
|
|
|
{
|
|
|
|
return verticalOrientation;
|
|
|
|
}
|
2022-06-08 21:38:26 +08:00
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
double JKQTMathTextVerbatimNode::getLineSpacingFactor() const
|
2022-06-08 21:38:26 +08:00
|
|
|
{
|
2022-08-03 21:23:14 +08:00
|
|
|
return lineSpacingFactor;
|
2022-06-08 21:38:26 +08:00
|
|
|
}
|
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
bool JKQTMathTextVerbatimNode::getVisibleWhitespace() const
|
|
|
|
{
|
|
|
|
return visibleWhitespace;
|
|
|
|
}
|
2022-06-08 21:38:26 +08:00
|
|
|
|
2022-08-03 21:23:14 +08:00
|
|
|
double JKQTMathTextVerbatimNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize *prevNodeSize)
|
|
|
|
{
|
|
|
|
doDrawBoxes(painter, x, y, currentEv);
|
|
|
|
transformEnvironment(currentEv);
|
|
|
|
const LayoutInfo l=calcLayout(painter, currentEv);
|
|
|
|
QFont f=currentEv.getFont(parentMathText);
|
|
|
|
f.setStyleStrategy(QFont::PreferDefault);
|
|
|
|
f.setFixedPitch(true);
|
|
|
|
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
2022-08-10 18:12:30 +08:00
|
|
|
painter.setFont(f);
|
2022-08-03 21:23:14 +08:00
|
|
|
for (int i=0; i<l.lines.size(); i++) {
|
2022-08-10 18:12:30 +08:00
|
|
|
painter.drawText(QPointF(x+l.X.at(i).x(), y+l.X.at(i).y()), l.lines.at(i));
|
2022-08-03 21:23:14 +08:00
|
|
|
}
|
|
|
|
return x+l.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JKQTMathTextVerbatimNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv)
|
|
|
|
{
|
|
|
|
transformEnvironment(currentEv);
|
|
|
|
const bool isMultiLine=text.count('\n')>0;
|
|
|
|
html+=currentEv.toHtmlStart(defaultEv, parentMathText);
|
|
|
|
if (isMultiLine) {
|
|
|
|
if (alignment==MTHALeft) {
|
|
|
|
html+="<div align=\"left\">";
|
|
|
|
} else if (alignment==MTHACentered) {
|
|
|
|
html+="<div align=\"center\">";
|
|
|
|
} else if (alignment==MTHARight) {
|
|
|
|
html+="<div align=\"right\">";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
html+="<pre>";
|
|
|
|
html+=textTransform(text, currentEv).toHtmlEscaped();
|
|
|
|
html+="</pre>";
|
|
|
|
if (isMultiLine) html+="</div>";
|
|
|
|
html+=currentEv.toHtmlAfter(defaultEv, parentMathText);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTMathTextVerbatimNode::getSizeInternal(QPainter &painter, JKQTMathTextEnvironment currentEv, double &width, double &baselineHeight, double &overallHeight, double &strikeoutPos, const JKQTMathTextNodeSize *prevNodeSize)
|
|
|
|
{
|
|
|
|
transformEnvironment(currentEv);
|
|
|
|
const LayoutInfo l=calcLayout(painter, currentEv);
|
|
|
|
width=l.width;
|
|
|
|
overallHeight=l.overallHeight;
|
|
|
|
baselineHeight=l.baselineHeight;
|
|
|
|
strikeoutPos=l.strikeoutPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTMathTextVerbatimNode::transformEnvironment(JKQTMathTextEnvironment ¤tEv) const
|
|
|
|
{
|
|
|
|
currentEv.font=MTEtypewriter;
|
|
|
|
}
|
|
|
|
|
|
|
|
JKQTMathTextVerbatimNode::LayoutInfo JKQTMathTextVerbatimNode::calcLayout(QPainter &painter, const JKQTMathTextEnvironment& currentEv) const
|
|
|
|
{
|
|
|
|
LayoutInfo l;
|
|
|
|
QFont f=currentEv.getFont(parentMathText);
|
|
|
|
f.setStyleStrategy(QFont::PreferDefault);
|
|
|
|
f.setFixedPitch(true);
|
|
|
|
const QFontMetricsF fm(f);
|
|
|
|
const double linespacing=fm.lineSpacing()*lineSpacingFactor;
|
|
|
|
const double fleading=fm.leading();
|
|
|
|
const double synLeading=fm.lineWidth();
|
|
|
|
const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor;
|
|
|
|
|
|
|
|
if (text.size()<=0) {
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
l.lines=textTransform(text, currentEv).split('\n');
|
|
|
|
|
|
|
|
// from now on we have at least one child node!!!
|
|
|
|
|
|
|
|
QList<double> widths, heights, ascents, descents, strikeouts;
|
|
|
|
double heightSum=0;
|
|
|
|
QList<double> ysFromFirstLine; // y-position of each line, where the first line is always at y=0 (i.e. ysFromFirstLine[0]==0)
|
|
|
|
double y=0;
|
|
|
|
for (int i=0; i<l.lines.size(); i++) {
|
|
|
|
|
|
|
|
if (i==0) {
|
|
|
|
heightSum=fm.ascent();
|
|
|
|
} else if (i>0) {
|
|
|
|
const double deltaLine=qMax(linespacing, descents.last()+lineLeading+fm.ascent());
|
|
|
|
heightSum=heightSum+deltaLine;
|
|
|
|
y=y+deltaLine;
|
|
|
|
}
|
|
|
|
widths<<fm.boundingRect(l.lines[i]).width();
|
|
|
|
l.width=qMax(l.width, widths.last());
|
|
|
|
heights<<fm.height();
|
|
|
|
ascents<<fm.ascent();
|
|
|
|
descents<<fm.descent();
|
|
|
|
strikeouts<<fm.strikeOutPos();
|
|
|
|
ysFromFirstLine<<y;
|
|
|
|
}
|
|
|
|
heightSum+=descents.last();
|
|
|
|
|
|
|
|
l.overallHeight=heightSum;
|
|
|
|
double y0=0;
|
|
|
|
if (verticalOrientation==MTVOTop) {
|
|
|
|
l.baselineHeight=0;
|
|
|
|
l.strikeoutPos=0;
|
|
|
|
y0=ascents.first();
|
|
|
|
} else if (verticalOrientation==MTVOFirstLine) {
|
|
|
|
l.baselineHeight=ascents.first();
|
|
|
|
l.strikeoutPos=strikeouts.first();
|
|
|
|
y0=0;
|
|
|
|
} else if (verticalOrientation==MTVOCentered) {
|
|
|
|
l.baselineHeight=heightSum/2.0;
|
|
|
|
l.strikeoutPos=heightSum/4.0;
|
|
|
|
y0=-heightSum/2.0+ascents.first();
|
|
|
|
} else if (verticalOrientation==MTVOLastLine) {
|
|
|
|
l.baselineHeight=heightSum-descents.last();
|
|
|
|
l.strikeoutPos=strikeouts.last();
|
|
|
|
y0=-(heightSum-ascents.first()-descents.last());
|
|
|
|
} else if (verticalOrientation==MTVOBottom) {
|
|
|
|
l.baselineHeight=heightSum;
|
|
|
|
l.strikeoutPos=0;
|
|
|
|
y0=-(heightSum-ascents.first());
|
|
|
|
}
|
|
|
|
for (int i=0; i<l.lines.size(); i++) {
|
|
|
|
double x=0;
|
|
|
|
if (alignment==MTHARight) x=l.width-widths[i];
|
|
|
|
else if (alignment==MTHACentered) x=(l.width-widths[i])/2.0;
|
|
|
|
l.X<<QPointF(x,ysFromFirstLine[i]+y0);
|
|
|
|
}
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString JKQTMathTextVerbatimNode::textTransform(const QString &text, const JKQTMathTextEnvironment ¤tEv) const
|
|
|
|
{
|
|
|
|
QFont f=currentEv.getFont(parentMathText);
|
|
|
|
f.setStyleStrategy(QFont::PreferDefault);
|
|
|
|
const QFontMetricsF fm(f);
|
|
|
|
|
|
|
|
QString spRep=QChar(0xB7);
|
|
|
|
if (!fm.inFont(spRep[0])) {
|
|
|
|
spRep=QChar(0x2423);
|
|
|
|
}
|
|
|
|
QString tabRep=QString(4,QChar(0x2192));
|
|
|
|
if (!fm.inFont(tabRep[0])) {
|
|
|
|
spRep=QString(4,QChar(0xAC));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString res=JKQTMathTextTextBaseNode::textTransform(text, currentEv);
|
|
|
|
if (res.startsWith('\n')) res=res.right(res.size()-1);
|
|
|
|
if (res.endsWith('\n')) res=res.left(res.size()-1);
|
|
|
|
if (visibleWhitespace) {
|
|
|
|
res.replace(' ', spRep);
|
|
|
|
res.replace('\t', tabRep);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
JKQTMathTextVerbatimNode::LayoutInfo::LayoutInfo():
|
|
|
|
JKQTMathTextNodeSize(), lines(), X()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|