JKQtPlotter/lib/jkqtmathtext/jkqtmathtext.cpp
2022-08-17 22:56:57 +02:00

2519 lines
107 KiB
C++

/*
Copyright (c) 2008-2022 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 "jkqtmathtext/nodes/jkqtmathtextnode.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtmathtext/nodes/jkqtmathtexttextnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextbracenode.h"
#include "jkqtmathtext/nodes/jkqtmathtextdecoratednode.h"
#include "jkqtmathtext/nodes/jkqtmathtextfracnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextinstructionnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextlistnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextmatrixnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextsqrtnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextsubsupernode.h"
#include "jkqtmathtext/nodes/jkqtmathtextsymbolnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextwhitespacenode.h"
#include "jkqtmathtext/nodes/jkqtmathtextnodetools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
#include <QFontDatabase>
#include <typeinfo>
#include <QApplication>
#include <QPainterPath>
const double JKQTMathText::ABS_MIN_LINEWIDTH=0.02;
// --------------------------------------------------------------------------------------------------
// -- implementation of the JKQTMathText methods
// --------------------------------------------------------------------------------------------------
JKQTMathText::JKQTMathText(QObject* parent):
QObject(parent)
{
//std::chrono::high_resolution_clock::time_point t0=std::chrono::high_resolution_clock::now();
initJKQTMathTextResources();
//qDebug()<<"init_resoucre: "<<std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now();
fontSize=10;
fontSizeUnits=JKQTMathTextEnvironment::POINTS;
fontColor=QColor("black");
brace_factor=1.04;
brace_y_shift_factor=0.7;//-1;
subsuper_size_factor=0.65;
subsuper_mode_selection_by_size_factor=1.01;
sub_shift_factor=0.4;
super_shift_factor=0.7;
special_sub_shift_factor=0.4;
special_super_shift_factor=0.4;
frac_factor=1.0;
frac_nested_factor=0.7;
frac_shift_factor=0.4;
underbrace_factor=0.75;
underbrace_separation_xfactor=0.25;
underbrace_bracesize_xfactor=0.5;
underset_factor=0.7;
decoration_height_factor=0.3;
decoration_width_reduction_Xfactor=0.2;
decoration_separation_factor=0.1;
operatorsubsuper_size_factor=0.65;
operatorsubsuper_distance_factor=0.35;
operatorsubsuper_extraspace_factor=0.5;
intsubsuper_xcorrection_factor=0.25;
intsubbesides_xcorrection_xfactor=0.33;
mathoperator_width_factor=1.5;
bigmathoperator_font_factor=1.8;
sqrt_width_Xfactor=0.8;
sqrt_height_factor=1.2;
sqrt_smallfont_factor=0.57;
matrix_linewidth_thin_factor=0.4;
matrix_linewidth_heavy_factor=1.5;
matrix_line_separation_factor=2.0;
matrix_xSeparation_factor=0.5;
matrix_ySeparation_factor=0.5;
matrix_xPadding_factor=0.5;
matrix_yPadding_factor=0.5;
blackboradFontMode=MTBBDMdefault;
static QString serifFont="serif";
static QString sansFont="sans";
static QString symbolFont="symbol";
static QString scriptFont="script";
static QString typewriterFont="typewriter";
static QString decorativeFont="decorative";
static QString blackboardFont="blackboard";
static QString fracturFont="fraktur";
static bool firstStart=true;
if (firstStart) {
//t0=std::chrono::high_resolution_clock::now();
firstStart=false;
#if (QT_VERSION<QT_VERSION_CHECK(6, 0, 0))
QFontDatabase fdb;
const auto fonts=fdb.families();
#else
const auto fonts=QFontDatabase::families();
#endif
auto checkForFonts=[&fonts](QString& targetfont, const QStringList& fontoptions) {
for (auto& f: fontoptions) {
if (fonts.contains(f)) {
targetfont=f;
break;
}
}
};
checkForFonts(serifFont, QStringList {"Times New Roman", "Times", "FreeSerif", "DejaVu Serif"});
//qDebug()<<"check 1st font: "<<std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms";
checkForFonts(sansFont, QStringList {"Arial Unicode MS", "Arial Unicode", "Lucida Sans Unicode", "Arial", "Helvetica", "FreeSans", "DejaVu Sans", "Lucida Sans"});
checkForFonts(symbolFont, QStringList {"SymbolStandard", "Symbol"});
checkForFonts(typewriterFont, QStringList {"Courier New", "Courier", "Courier Std", "FreeMono", "CMU Typewriter Text", "UM Typewriter"});
checkForFonts(blackboardFont, QStringList {"Double Stroke", "CloisterOpenFace BT", "GoudyHandtooled BT", "Castellar", "MathJax_AMS", "Castellar Standard", "MathJax_AMS Standard", "Colonna MT"});
checkForFonts(decorativeFont, QStringList {"Lucida Calligraphy", "Cookie", "Segoe Print", "Comic Sans", "Comic Sans MS", "Gabriola", "Gabriola Standard", "Lucida Handwriting Kursiv", "Lucida Handwriting", "Pristina", "Pristina Standard", "MathJax_Caligraphics"});
checkForFonts(scriptFont, QStringList {"Lucida Handwriting", "Dancing Script", "Amazone BT", "ScriptS", "ScriptC", "ScriptC Standard", "Script", "Brush Script MT", "Brush Script MT Kursiv", "MathJax_Script"});
checkForFonts(fracturFont, QStringList {"Old English Text MT", "Old English Text MT Standard", "UnifrakturMaguntia Standard", "UnifrakturMaguntia", "MathJax_Fraktur", "UnifrakturCook Fett"});
//qDebug()<<"check all font: "<<std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms";
}
//t0=std::chrono::high_resolution_clock::now();
if (serifFont!="serif") addReplacementFont("serif", serifFont);
if (sansFont!="sans") addReplacementFont("sans", sansFont);
if (symbolFont!="symbol") addReplacementFont("symbol", symbolFont);
if (scriptFont!="script") addReplacementFont("script", scriptFont);
if (typewriterFont!="typewriter") addReplacementFont("typewriter", typewriterFont);
if (decorativeFont!="decorative") addReplacementFont("decorative", decorativeFont);
if (fracturFont!="fraktur") addReplacementFont("fraktur", fracturFont);
if (blackboardFont!="blackboard") {
addReplacementFont("blackboard", blackboardFont);
}
//qDebug()<<"add replacement fonts: "<<std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now();
setFontSans(sansFont, estimateJKQTMathTextFontEncoding(sansFont));
setFontMathSans(sansFont, estimateJKQTMathTextFontEncoding(sansFont));
setFontTypewriter(typewriterFont, estimateJKQTMathTextFontEncoding(typewriterFont));
setFontRoman(serifFont, estimateJKQTMathTextFontEncoding(serifFont));
setFontMathRoman(serifFont, estimateJKQTMathTextFontEncoding(serifFont));
setFontCaligraphic(decorativeFont, estimateJKQTMathTextFontEncoding(decorativeFont));
if (blackboardFont!="blackboard") {
setFontBlackboard(blackboardFont, estimateJKQTMathTextFontEncoding(blackboardFont));
setFontBlackboradMode(MTBBDMunicodeCharactersOrFontDirectly);
} else {
setFontBlackboard(sansFont, estimateJKQTMathTextFontEncoding(sansFont));
setFontBlackboradMode(MTBBDMunicodeCharactersOrSimulate);
}
setFontScript(scriptFont, estimateJKQTMathTextFontEncoding(scriptFont));
setFontFraktur(fracturFont, estimateJKQTMathTextFontEncoding(fracturFont));
setFallbackFontSymbols(symbolFont, estimateJKQTMathTextFontEncoding(symbolFont));
//qDebug()<<"set fonts: "<<std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now();
useXITS();
//qDebug()<<"useXITS: "<<std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()-t0).count()/1000.0<<"ms"; t0=std::chrono::high_resolution_clock::now();
parsedNode=nullptr;
currentToken=MTTnone;
currentTokenName="";
currentTokenID=0;
parseString="";
parsingMathEnvironment=false;
}
JKQTMathText::~JKQTMathText() {
if (parsedNode!=nullptr) delete parsedNode;
parsedNode=nullptr;
}
void JKQTMathText::loadSettings(const QSettings& settings, const QString& group){
fontSize=settings.value(group+"font_size", fontSize).toDouble();
fontSizeUnits=JKQTMathTextEnvironment::String2FontSizeUnit(settings.value(group+"font_size_units", JKQTMathTextEnvironment::FontSizeUnit2String(fontSizeUnits)).toString());
fontColor=jkqtp_String2QColor(settings.value(group+"font_color", jkqtp_QColor2String(fontColor)).toString());
brace_factor=settings.value(group+"brace_factor", brace_factor).toDouble();
subsuper_size_factor=settings.value(group+"subsuper_size_factor", subsuper_size_factor).toDouble();
subsuper_mode_selection_by_size_factor=settings.value(group+"subsuper_mode_selection_by_size_factor", subsuper_mode_selection_by_size_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();
special_super_shift_factor=settings.value(group+"special_super_shift_factor", special_super_shift_factor).toDouble();
special_sub_shift_factor=settings.value(group+"special_sub_shift_factor", special_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();
underbrace_bracesize_xfactor=settings.value(group+"underbrace_bracesize_xfactor", underbrace_bracesize_xfactor).toDouble();
underbrace_separation_xfactor=settings.value(group+"underbrace_separation_xfactor", underbrace_separation_xfactor).toDouble();
underset_factor=settings.value(group+"underset_factor", underset_factor).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();
decoration_separation_factor=settings.value(group+"decoration_separation_factor", decoration_separation_factor).toDouble();
decoration_width_reduction_Xfactor=settings.value(group+"decoration_width_reduction_xfactor", decoration_width_reduction_Xfactor).toDouble();
operatorsubsuper_size_factor=settings.value(group+"operatorsubsuper_size_factor", operatorsubsuper_size_factor).toDouble();
operatorsubsuper_distance_factor=settings.value(group+"operatorsubsuper_distance_factor", operatorsubsuper_distance_factor).toDouble();
operatorsubsuper_extraspace_factor=settings.value(group+"operatorsubsuper_extraspace_factor", operatorsubsuper_extraspace_factor).toDouble();
mathoperator_width_factor=settings.value(group+"mathoperator_width_factor", mathoperator_width_factor).toDouble();
intsubsuper_xcorrection_factor=settings.value(group+"intsubsuper_xcorrection_factor", intsubsuper_xcorrection_factor).toDouble();
intsubbesides_xcorrection_xfactor=settings.value(group+"intsubbesides_xcorrection_xfactor", intsubbesides_xcorrection_xfactor).toDouble();
sqrt_width_Xfactor=settings.value(group+"sqrt_width_Xfactor", sqrt_width_Xfactor).toDouble();
sqrt_height_factor=settings.value(group+"sqrt_height_factor", sqrt_height_factor).toDouble();
sqrt_smallfont_factor=settings.value(group+"sqrt_smallfont_factor", sqrt_smallfont_factor).toDouble();
bigmathoperator_font_factor=settings.value(group+"bigmathoperator_font_factor", bigmathoperator_font_factor).toDouble();
frac_nested_factor=settings.value(group+"frac_nested_factor", frac_nested_factor).toDouble();
matrix_linewidth_thin_factor=settings.value(group+"matrix_linewidth_thin_factor", matrix_linewidth_thin_factor).toDouble();
matrix_linewidth_heavy_factor=settings.value(group+"matrix_linewidth_heavy_factor", matrix_linewidth_heavy_factor).toDouble();
matrix_line_separation_factor=settings.value(group+"matrix_line_separation_factor", matrix_line_separation_factor).toDouble();
matrix_xSeparation_factor=settings.value(group+"matrix_xSeparation_factor", matrix_xSeparation_factor).toDouble();
matrix_ySeparation_factor=settings.value(group+"matrix_ySeparation_factor", matrix_ySeparation_factor).toDouble();
matrix_xPadding_factor=settings.value(group+"matrix_xPadding_factor", matrix_xPadding_factor).toDouble();
matrix_yPadding_factor=settings.value(group+"matrix_yPadding_factor", matrix_yPadding_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_size_units", JKQTMathTextEnvironment::FontSizeUnit2String(fontSizeUnits));
settings.setValue(group+"font_color", jkqtp_QColor2String(fontColor));
settings.setValue(group+ "brace_factor", brace_factor);
settings.setValue(group+ "subsuper_size_factor", subsuper_size_factor);
settings.setValue(group+ "subsuper_mode_selection_by_size_factor", subsuper_mode_selection_by_size_factor);
settings.setValue(group+ "sub_shift_factor", sub_shift_factor);
settings.setValue(group+ "super_shift_factor", super_shift_factor);
settings.setValue(group+ "special_sub_shift_factor", special_sub_shift_factor);
settings.setValue(group+ "special_super_shift_factor", special_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+ "underbrace_bracesize_xfactor", underbrace_bracesize_xfactor);
settings.setValue(group+ "underbrace_separation_xfactor", underbrace_separation_xfactor);
settings.setValue(group+ "underset_factor", underset_factor);
settings.setValue(group+ "operatorsubsuper_size_factor", operatorsubsuper_size_factor);
settings.setValue(group+ "operatorsubsuper_distance_factor", operatorsubsuper_distance_factor);
settings.setValue(group+ "operatorsubsuper_extraspace_factor", operatorsubsuper_extraspace_factor);
settings.setValue(group+ "mathoperator_width_factor", mathoperator_width_factor);
settings.setValue(group+ "intsubsuper_xcorrection_factor", intsubsuper_xcorrection_factor);
settings.setValue(group+ "intsubbesides_xcorrection_xfactor", intsubbesides_xcorrection_xfactor);
settings.setValue(group+ "brace_y_shift_factor", brace_y_shift_factor);
settings.setValue(group+ "decoration_height_factor", decoration_height_factor);
settings.setValue(group+ "decoration_separation_factor", decoration_separation_factor);
settings.setValue(group+ "decoration_width_reduction_xfactor", decoration_width_reduction_Xfactor);
settings.setValue(group+ "sqrt_width_Xfactor", sqrt_width_Xfactor);
settings.setValue(group+ "sqrt_height_factor", sqrt_height_factor);
settings.setValue(group+ "sqrt_smallfont_factor", sqrt_smallfont_factor);
settings.setValue(group+ "bigmathoperator_font_factor", bigmathoperator_font_factor);
settings.setValue(group+ "frac_nested_factor", frac_nested_factor);
settings.setValue(group+ "matrix_linewidth_thin_factor", matrix_linewidth_thin_factor);
settings.setValue(group+ "matrix_linewidth_heavy_factor", matrix_linewidth_heavy_factor);
settings.setValue(group+ "matrix_line_separation_factor", matrix_line_separation_factor);
settings.setValue(group+ "matrix_xSeparation_factor", matrix_xSeparation_factor);
settings.setValue(group+ "matrix_ySeparation_factor", matrix_ySeparation_factor);
settings.setValue(group+ "matrix_xPadding_factor", matrix_xPadding_factor);
settings.setValue(group+ "matrix_yPadding_factor", matrix_yPadding_factor);
}
bool JKQTMathText::useSTIX(bool mathModeOnly) {
const JKQTMathTextFontSpecifier stixs=JKQTMathTextFontSpecifier::getSTIXFamilies();
bool res=false;
if (!mathModeOnly && !stixs.fontName().isEmpty()) {
setFontRoman(stixs.fontName(), MTFEUnicode);
res=true;
}
if (!stixs.mathFontName().isEmpty()) {
setFontMathRoman(stixs.mathFontName(), MTFEUnicode);
setFallbackFontSymbols(stixs.mathFontName(), MTFEUnicode);
res=true;
} else if (!stixs.fontName().isEmpty()) {
setFontMathRoman(stixs.fontName(), MTFEUnicode);
setFallbackFontSymbols(stixs.fontName(), MTFEUnicode);
res=true;
}
return res;
}
bool JKQTMathText::useXITS(bool mathModeOnly)
{
const JKQTMathTextFontSpecifier xits=JKQTMathTextFontSpecifier::getXITSFamilies();
bool res=false;
if (!mathModeOnly && !xits.fontName().isEmpty()) {
setFontRoman(xits.fontName(), MTFEUnicode);
setFallbackFontSymbols(xits.fontName(), MTFEUnicode);
res=true;
}
if (!xits.mathFontName().isEmpty()) {
setFontMathRoman(xits.mathFontName(), MTFEUnicode);
setFallbackFontSymbols(xits.mathFontName(), MTFEUnicode);
res=true;
}
return res;
}
bool JKQTMathText::useASANA(bool mathModeOnly)
{
const JKQTMathTextFontSpecifier asana=JKQTMathTextFontSpecifier::getXITSFamilies();
bool res=false;
if (!mathModeOnly && !asana.fontName().isEmpty()) {
setFontRoman(asana.fontName(), MTFEUnicode);
setFallbackFontSymbols(asana.fontName(), MTFEUnicode);
res=true;
}
if (!asana.mathFontName().isEmpty()) {
setFontMathRoman(asana.mathFontName(), MTFEUnicode);
setFallbackFontSymbols(asana.mathFontName(), MTFEUnicode);
res=true;
}
return res;
}
void JKQTMathText::useAnyUnicode(QString timesFont, const QString &sansFont, JKQTMathTextFontEncoding encodingTimes, JKQTMathTextFontEncoding encodingSans)
{
if (!timesFont.isEmpty()) {
setFontRoman(timesFont, encodingTimes);
setFontMathRoman(timesFont, encodingTimes);
}
if (!sansFont.isEmpty()) {
setFontSans(sansFont, encodingSans);
setFontMathSans(sansFont, encodingSans);
}
}
void JKQTMathText::useAnyUnicodeForMathOnly(QString timesFont, const QString &sansFont, JKQTMathTextFontEncoding encodingTimes, JKQTMathTextFontEncoding encodingSans)
{
if (!timesFont.isEmpty()) { setFontMathRoman(timesFont, encodingTimes); }
if (!sansFont.isEmpty()) { setFontMathSans(sansFont, encodingSans); }
}
void JKQTMathText::useAnyUnicodeForTextOnly(QString timesFont, const QString &sansFont, JKQTMathTextFontEncoding encodingTimes, JKQTMathTextFontEncoding encodingSans)
{
if (!timesFont.isEmpty()) { setFontRoman(timesFont, encodingTimes); }
if (!sansFont.isEmpty()) { setFontSans(sansFont, encodingSans); }
}
QString JKQTMathText::toHtml(bool *ok, double fontPointSize) {
QString s;
bool okk=false;
if (getNodeTree()!=nullptr) {
JKQTMathTextEnvironment ev;
ev.color=fontColor;
ev.fontSize=fontPointSize;
ev.fontSizeUnit=JKQTMathTextEnvironment::POINTS;
JKQTMathTextEnvironment defaultev;
defaultev.fontSize=fontPointSize;
defaultev.fontSizeUnit=JKQTMathTextEnvironment::POINTS;
okk=getNodeTree()->toHtml(s, ev, defaultev);
}
if (ok) *ok=okk;
return s;
}
void JKQTMathText::setFontColor(const QColor &__value)
{
this->fontColor = __value;
}
QColor JKQTMathText::getFontColor() const
{
return this->fontColor;
}
void JKQTMathText::setFontSize(double __value)
{
setFontPointSize(__value);
}
void JKQTMathText::setFontPointSize(double __value)
{
fontSize = __value;
fontSizeUnits=JKQTMathTextEnvironment::POINTS;
}
void JKQTMathText::setFontSizePixels(double __value)
{
fontSize = __value;
fontSizeUnits=JKQTMathTextEnvironment::PIXELS;
}
double JKQTMathText::getFontSize() const
{
return getFontPointSize();
}
double JKQTMathText::getFontPointSize() const
{
if (fontSizeUnits==JKQTMathTextEnvironment::POINTS) return fontSize;
else return -1;
}
double JKQTMathText::getFontSizePixels() const
{
if (fontSizeUnits==JKQTMathTextEnvironment::PIXELS) return fontSize;
else return -1;
}
void JKQTMathText::addReplacementFont(const QString &nonUseFont, const QString &useFont, JKQTMathTextFontEncoding 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,JKQTMathTextFontEncoding> JKQTMathText::getReplacementFont(const QString &nonUseFont, const QString &defaultFont, JKQTMathTextFontEncoding defaultFontEncoding) const {
QPair<QString,JKQTMathTextFontEncoding> res(defaultFont, defaultFontEncoding);
for (auto it=fontReplacements.begin(); it!=fontReplacements.end(); ++it) {
if (it.key().toLower()==nonUseFont.toLower()) {
res.first=it.value();
res.second=fontEncodingReplacements.value(res.first, res.second);
return res;
}
}
return res;
}
QPair<QString, JKQTMathTextFontEncoding> JKQTMathText::getFontData(JKQTMathTextEnvironmentFont font, bool in_math_environment) const
{
if (in_math_environment) {
if (font==MTEroman) font=MTEmathRoman;
if (font==MTEsans) font=MTEmathSans;
}
const auto fd=fontDefinitions.value(font);
return QPair<QString, JKQTMathTextFontEncoding>(fd.fontName, fd.fontEncoding);
}
void JKQTMathText::setFontRomanOrSpecial(const QString &__value, JKQTMathTextFontEncoding encoding)
{
setFontRomanOrSpecial(JKQTMathTextFontSpecifier::fromFontSpec(__value), encoding);
}
void JKQTMathText::setFontRomanOrSpecial(const JKQTMathTextFontSpecifier &fontName, JKQTMathTextFontEncoding encoding)
{
if (!fontName.hasMathFontName()) {
if (fontName.fontName().toUpper()=="XITS") useXITS(false);
else if (fontName.fontName().toUpper()=="STIX") useSTIX(false);
else if (fontName.fontName().toUpper()=="ASANA") useASANA(false);
else {
setFontRoman(fontName.fontName(), encoding);
setFontMathRoman(fontName.fontName(), encoding);
}
} else {
if (fontName.mathFontName().toUpper()=="XITS") useXITS(true);
else if (fontName.mathFontName().toUpper()=="STIX") useSTIX(true);
else if (fontName.mathFontName().toUpper()=="ASANA") useASANA(true);
else setFontMathRoman(fontName.mathFontName(), encoding);
setFontRoman(fontName.fontName(), encoding);
}
}
void JKQTMathText::setFontRoman(const QString &__value, JKQTMathTextFontEncoding 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;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingRoman() const
{
return fontDefinitions[MTEroman].fontEncoding;
}
void JKQTMathText::setFontSans(const QString &__value, JKQTMathTextFontEncoding 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;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingSans() const
{
return fontDefinitions[MTEsans].fontEncoding;
}
void JKQTMathText::setFontTypewriter(const QString &__value, JKQTMathTextFontEncoding 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;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingTypewriter() const
{
return fontDefinitions[MTEtypewriter].fontEncoding;
}
void JKQTMathText::setFontScript(const QString &__value, JKQTMathTextFontEncoding 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;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingScript() const
{
return fontDefinitions[MTEscript].fontEncoding;
}
void JKQTMathText::setFontFraktur(const QString &__value, JKQTMathTextFontEncoding 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;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingFraktur() const
{
return fontDefinitions[MTEfraktur].fontEncoding;
}
void JKQTMathText::setFallbackFontSymbols(const QString &fontName, JKQTMathTextFontEncoding encoding)
{
auto f=getReplacementFont(fontName, fontName, encoding);
fontDefinitions[MTEFallbackSymbols].fontName = f.first;
fontDefinitions[MTEFallbackSymbols].fontEncoding = f.second;
}
QString JKQTMathText::getFallbackFontSymbols() const
{
return fontDefinitions[MTEFallbackSymbols].fontName;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingFallbackFontSymbols() const
{
return fontDefinitions[MTEFallbackSymbols].fontEncoding;
}
void JKQTMathText::setFontCaligraphic(const QString &__value, JKQTMathTextFontEncoding 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;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingCaligraphic() const
{
return fontDefinitions[MTEcaligraphic].fontEncoding;
}
void JKQTMathText::setFontMathRoman(const QString &fontName, JKQTMathTextFontEncoding 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, JKQTMathTextFontEncoding 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;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingMathSans() const
{
return fontDefinitions[MTEmathSans].fontEncoding;
}
JKQTMathTextFontEncoding JKQTMathText::getFontEncodingMathRoman() const
{
return fontDefinitions[MTEmathRoman].fontEncoding;
}
void JKQTMathText::setFontBlackboard(const QString &__value, JKQTMathTextFontEncoding encoding)
{
auto f=getReplacementFont(__value, __value, encoding);
fontDefinitions[MTEblackboard].fontName = f.first;
fontDefinitions[MTEblackboard].fontEncoding = f.second;
}
JKQTMathTextBlackboradDrawingMode JKQTMathText::getFontBlackboradMode() const
{
return blackboradFontMode;
}
void JKQTMathText::setFontBlackboradMode(JKQTMathTextBlackboradDrawingMode mode)
{
blackboradFontMode=mode;
}
QString JKQTMathText::getFontBlackboard() const
{
return fontDefinitions[MTEblackboard].fontName;
}
JKQTMathTextFontEncoding 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::setSubsuperModeSelectionBySizeFactor(double __value)
{
subsuper_mode_selection_by_size_factor=__value;
}
double JKQTMathText::getSubsuperModeSelectionBySizeFactor() const
{
return subsuper_mode_selection_by_size_factor;
}
void JKQTMathText::setOperatorsubsuperSizeFactor(double __value)
{
this->operatorsubsuper_size_factor = __value;
}
double JKQTMathText::getOperatorsubsuperSizeFactor() const
{
return this->operatorsubsuper_size_factor;
}
void JKQTMathText::setOperatorsubsuperDistanceFactor(double __value)
{
this->operatorsubsuper_distance_factor = __value;
}
double JKQTMathText::getOperatorsubsuperDistanceFactor() const
{
return this->operatorsubsuper_distance_factor;
}
void JKQTMathText::setOperatorsubsuperExtraSpaceFactor(double __value)
{
operatorsubsuper_extraspace_factor=__value;
}
double JKQTMathText::getOperatorsubsuperExtraSpaceFactor() const
{
return operatorsubsuper_extraspace_factor;
}
void JKQTMathText::setMathoperatorWidthFactor(double __value)
{
this->mathoperator_width_factor = __value;
}
double JKQTMathText::getMathoperatorWidthFactor() const
{
return this->mathoperator_width_factor;
}
void JKQTMathText::setIntSubSuperXCorrectionFactor(double __value)
{
intsubsuper_xcorrection_factor=__value;
}
double JKQTMathText::getIntSubSuperXCorrectionFactor() const
{
return intsubsuper_xcorrection_factor;
}
void JKQTMathText::setIntSubBesidesXCorrectionXFactor(double __value)
{
intsubbesides_xcorrection_xfactor=__value;
}
double JKQTMathText::getIntSubBesidesXCorrectionXFactor() const
{
return intsubbesides_xcorrection_xfactor;
}
void JKQTMathText::setBigMathoperatorFontFactor(double __value)
{
bigmathoperator_font_factor=__value;
}
double JKQTMathText::getBigMathoperatorFontFactor() const
{
return bigmathoperator_font_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;
}
double JKQTMathText::getSpecialSuperShiftFactor() const
{
return special_super_shift_factor;
}
void JKQTMathText::setSpecialSuperShiftFactor(double __value)
{
special_super_shift_factor=__value;
}
void JKQTMathText::setSpecialSubShiftFactor(double __value)
{
special_sub_shift_factor=__value;
}
double JKQTMathText::getSpecialSubShiftFactor() const
{
return special_sub_shift_factor;
}
void JKQTMathText::setUnderbraceFactor(double __value)
{
this->underbrace_factor = __value;
}
double JKQTMathText::getUnderbraceFactor() const
{
return this->underbrace_factor;
}
void JKQTMathText::setUnderbraceSeparationXFactor(double __value)
{
underbrace_separation_xfactor=__value;
}
double JKQTMathText::getUnderbraceSeparationXFactor() const
{
return underbrace_separation_xfactor;
}
void JKQTMathText::setUnderbraceBraceSizeXFactor(double __value)
{
underbrace_bracesize_xfactor=__value;
}
double JKQTMathText::getUnderbraceBraceSizeXFactor() const
{
return underbrace_bracesize_xfactor;
}
void JKQTMathText::setUndersetFactor(double __value)
{
this->underset_factor = __value;
}
double JKQTMathText::getUndersetFactor() const
{
return this->underset_factor;
}
void JKQTMathText::setFracFactor(double __value)
{
this->frac_factor = __value;
}
double JKQTMathText::getFracFactor() const
{
return this->frac_factor;
}
void JKQTMathText::setFracNestedFactor(double __value)
{
frac_nested_factor=__value;
}
double JKQTMathText::getFracNestedFactor() const
{
return frac_nested_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::setDecorationSeparationXFactor(double __value)
{
decoration_separation_factor=__value;
}
double JKQTMathText::getDecorationSeparationFactor() const
{
return decoration_separation_factor;
}
void JKQTMathText::setDecorationWidthReductionFactor(double __value)
{
decoration_width_reduction_Xfactor=__value;
}
double JKQTMathText::getDecorationWidthReductionXFactor() const
{
return decoration_width_reduction_Xfactor;
}
void JKQTMathText::setSqrtWidthXFactor(double __value)
{
sqrt_width_Xfactor=__value;
}
double JKQTMathText::getSqrtWidthXFactor() const
{
return sqrt_width_Xfactor;
}
void JKQTMathText::setSqrtHeightFactor(double __value)
{
sqrt_height_factor=__value;
}
double JKQTMathText::getSqrtHeightFactor() const
{
return sqrt_height_factor;
}
void JKQTMathText::setSqrtSmallFontFactor(double __value)
{
sqrt_smallfont_factor=__value;
}
double JKQTMathText::getSqrtSmallFontFactor() const
{
return sqrt_smallfont_factor;
}
double JKQTMathText::getMatrixLinewidthThinFactor()
{
return matrix_linewidth_thin_factor;
}
void JKQTMathText::setMatrixLinewidthThinFactor(double factor)
{
matrix_linewidth_thin_factor=factor;
}
double JKQTMathText::getMatrixLinewidthHeavyFactor()
{
return matrix_linewidth_heavy_factor;
}
void JKQTMathText::setMatrixLinewidthHeavyFactor(double factor)
{
matrix_linewidth_heavy_factor=factor;
}
double JKQTMathText::getMatrixLineSeparationFactor()
{
return matrix_line_separation_factor;
}
void JKQTMathText::setMatrixLineSeparationFactor(double factor)
{
matrix_line_separation_factor=factor;
}
double JKQTMathText::getMatrixXSeparationFactor()
{
return matrix_xSeparation_factor;
}
void JKQTMathText::setMatrixXSeparationFactor(double factor)
{
matrix_xSeparation_factor=factor;
}
double JKQTMathText::getMatrixYSeparationFactor()
{
return matrix_ySeparation_factor;
}
void JKQTMathText::setMatrixYSeparationFactor(double factor)
{
matrix_ySeparation_factor=factor;
}
double JKQTMathText::getMatrixXPaddingFactor()
{
return matrix_xPadding_factor;
}
void JKQTMathText::setMatrixXPaddingFactor(double factor)
{
matrix_xPadding_factor=factor;
}
double JKQTMathText::getMatrixYPaddingFactor()
{
return matrix_yPadding_factor;
}
void JKQTMathText::setMatrixYPaddingFactor(double factor)
{
matrix_yPadding_factor=factor;
}
QStringList JKQTMathText::getErrorList() const {
return this->error_list;
}
bool JKQTMathText::hadErrors() const
{
return error_list.size()>0;
}
void JKQTMathText::addToErrorList(const QString &error)
{
error_list.append(error);
}
JKQTMathText::tokenType JKQTMathText::getToken() {
currentTokenID++;
if (currentTokenID>parseString.size()-1) return currentToken=MTTnone;
QChar c=parseString[currentTokenID];
currentTokenName="";
//----------------------------------------------------------
// define some static sets for easy character lookup/identificattion
static QSet<QChar> TokenCharacters;
static QSet<QChar> mathEnvironmentSpecialChars, mathEnvironmentSpecialEndChars;
static QSet<QChar> SingleCharInstructions;
static QHash<QString, QChar> accentLetters;
static QSet<int> accentLetters_LenBackslash;
static QSet<int> accentLetters_LenCurly;
if (TokenCharacters.size()==0) {
mathEnvironmentSpecialChars<<'(' << '[' << '|' << ')' << ']' << '+' << '-' << '*' << '/' << '<' << '>' << '=';
mathEnvironmentSpecialEndChars<<'(' << '&' << '[' << '|' << ')' << ']' << '\\' << '$' << '{' << '}' << '_' << '^' << '+' << '-' << '/' << '*' << '=' << '<' << '>';
TokenCharacters<<'-'<<'_'<<'^'<<'\\'<<'$'<<'&'<<'}'<<'{'<<'['<<']';
SingleCharInstructions<<'|'<<';'<<':'<<'!'<<','<<'_'<<'\\'<<'$'<<'%'<<'&'<<'#'<<'}'<<'{'<<' '<<'['<<']';
auto fAddUml=[](const QString& cmd, const QChar& letter, const QChar& ch) {
QString i;
if (cmd.size()>0 && !letter.isNull()) {
if (cmd.size()==1 && !cmd[0].isLetter()) {
i="\\"+cmd+letter;
accentLetters[i]=ch; accentLetters_LenBackslash.insert(i.size());
}
i="{\\"+cmd+letter+"}";
accentLetters[i]=ch; accentLetters_LenCurly.insert(i.size());
i="\\"+cmd+"{"+letter+"}";
accentLetters[i]=ch; accentLetters_LenBackslash.insert(i.size());
} else if (cmd.size()>0 && letter.isNull()) {
i="\\"+cmd+" ";
accentLetters[i]=ch; accentLetters_LenBackslash.insert(i.size());
i="\\"+cmd+"\t";
accentLetters[i]=ch; accentLetters_LenBackslash.insert(i.size());
i="\\"+cmd+"\n";
accentLetters[i]=ch; accentLetters_LenBackslash.insert(i.size());
i="\\"+cmd+"\\";
accentLetters[i]=ch; accentLetters_LenBackslash.insert(i.size());
i="{\\"+cmd+"}";
accentLetters[i]=ch; accentLetters_LenCurly.insert(i.size());
}
};
// instructions like \"{a}
fAddUml("\"", 'A', QChar(0xC4));
fAddUml("\"", 'E', QChar(0xCB));
fAddUml("\"", 'I', QChar(0xCF));
fAddUml("\"", 'O', QChar(0xD6));
fAddUml("\"", 'U', QChar(0xDC));
fAddUml("\"", 'Y', QChar(0x178));
fAddUml("\"", 'a', QChar(0xE4));
fAddUml("\"", 'e', QChar(0xEB));
fAddUml("\"", 'i', QChar(0xEF));
fAddUml("\"", 'o', QChar(0xF6));
fAddUml("\"", 'u', QChar(0xFC));
fAddUml("\"", 'y', QChar(0xFF));
fAddUml("'", 'A', QChar(0xC1));
fAddUml("'", 'E', QChar(0xC9));
fAddUml("'", 'I', QChar(0xCD));
fAddUml("'", 'O', QChar(0xD3));
fAddUml("'", 'U', QChar(0xDA));
fAddUml("'", 'Y', QChar(0xDD));
fAddUml("'", 'a', QChar(0xE1));
fAddUml("'", 'e', QChar(0xE9));
fAddUml("'", 'i', QChar(0xED));
fAddUml("'", 'o', QChar(0xF3));
fAddUml("'", 'u', QChar(0xFA));
fAddUml("'", 'y', QChar(0xFD));
fAddUml("'", 'C', QChar(0x106));
fAddUml("'", 'c', QChar(0x107));
fAddUml("'", 'L', QChar(0x139));
fAddUml("'", 'l', QChar(0x13A));
fAddUml("'", 'N', QChar(0x143));
fAddUml("'", 'n', QChar(0x144));
fAddUml("'", 'R', QChar(0x154));
fAddUml("'", 'r', QChar(0x155));
fAddUml("'", 'S', QChar(0x15A));
fAddUml("'", 's', QChar(0x15B));
fAddUml("'", 'Z', QChar(0x179));
fAddUml("'", 'z', QChar(0x17A));
fAddUml("'", 'G', QChar(0x1F4));
fAddUml("'", 'g', QChar(0x1F5));
fAddUml("`", 'A', QChar(0xC0));
fAddUml("`", 'E', QChar(0xC8));
fAddUml("`", 'I', QChar(0xCC));
fAddUml("`", 'O', QChar(0xD2));
fAddUml("`", 'U', QChar(0xD9));
fAddUml("`", 'a', QChar(0xE0));
fAddUml("`", 'e', QChar(0xE8));
fAddUml("`", 'i', QChar(0xEC));
fAddUml("`", 'o', QChar(0xF2));
fAddUml("`", 'u', QChar(0xF9));
fAddUml("`", 'N', QChar(0x1F8));
fAddUml("`", 'n', QChar(0x1F9));
fAddUml("^", 'A', QChar(0xC2));
fAddUml("^", 'E', QChar(0xCA));
fAddUml("^", 'I', QChar(0xCE));
fAddUml("^", 'O', QChar(0xD4));
fAddUml("^", 'U', QChar(0xDB));
fAddUml("^", 'a', QChar(0xE2));
fAddUml("^", 'e', QChar(0xEA));
fAddUml("^", 'i', QChar(0xEE));
fAddUml("^", 'o', QChar(0xF4));
fAddUml("^", 'u', QChar(0xFB));
fAddUml("^", 'C', QChar(0x108));
fAddUml("^", 'c', QChar(0x109));
fAddUml("^", 'G', QChar(0x11C));
fAddUml("^", 'g', QChar(0x11D));
fAddUml("^", 'H', QChar(0x124));
fAddUml("^", 'h', QChar(0x125));
fAddUml("^", 'J', QChar(0x134));
fAddUml("^", 'j', QChar(0x135));
fAddUml("^", 'S', QChar(0x15C));
fAddUml("^", 's', QChar(0x15D));
fAddUml("^", 'W', QChar(0x174));
fAddUml("^", 'w', QChar(0x175));
fAddUml("^", 'Y', QChar(0x176));
fAddUml("^", 'y', QChar(0x177));
fAddUml("v", 'C', QChar(0x10C));
fAddUml("v", 'c', QChar(0x10D));
fAddUml("v", 'D', QChar(0x10E));
fAddUml("v", 'd', QChar(0x10F));
fAddUml("v", 'E', QChar(0x11A));
fAddUml("v", 'e', QChar(0x11B));
fAddUml("v", 'L', QChar(0x13D));
fAddUml("v", 'l', QChar(0x13E));
fAddUml("v", 'N', QChar(0x147));
fAddUml("v", 'n', QChar(0x148));
fAddUml("v", 'R', QChar(0x158));
fAddUml("v", 'r', QChar(0x159));
fAddUml("v", 'S', QChar(0x160));
fAddUml("v", 's', QChar(0x161));
fAddUml("v", 'T', QChar(0x164));
fAddUml("v", 't', QChar(0x165));
fAddUml("v", 'Z', QChar(0x17D));
fAddUml("v", 'z', QChar(0x17E));
fAddUml("v", 'A', QChar(0x1CD));
fAddUml("v", 'a', QChar(0x1CE));
fAddUml("v", 'I', QChar(0x1CF));
fAddUml("v", 'i', QChar(0x1D0));
fAddUml("v", 'O', QChar(0x1D1));
fAddUml("v", 'o', QChar(0x1D2));
fAddUml("v", 'U', QChar(0x1D3));
fAddUml("v", 'u', QChar(0x1D4));
fAddUml("v", 'G', QChar(0x1E6));
fAddUml("v", 'g', QChar(0x1E7));
fAddUml("v", 'K', QChar(0x1E8));
fAddUml("v", 'k', QChar(0x1E9));
fAddUml("v", 'j', QChar(0x1F0));
fAddUml("v", 'H', QChar(0x21E));
fAddUml("v", 'h', QChar(0x21F));
fAddUml("~", 'A', QChar(0xC3));
fAddUml("~", 'N', QChar(0xD1));
fAddUml("~", 'O', QChar(0xD5));
fAddUml("~", 'a', QChar(0xE3));
fAddUml("~", 'n', QChar(0xF1));
fAddUml("~", 'o', QChar(0xF5));
fAddUml("~", 'I', QChar(0x128));
fAddUml("~", 'i', QChar(0x129));
fAddUml("~", 'U', QChar(0x168));
fAddUml("~", 'u', QChar(0x169));
fAddUml("r", 'A', QChar(0xC5));
fAddUml("r", 'a', QChar(0xE5));
fAddUml("r", 'U', QChar(0x16E));
fAddUml("r", 'u', QChar(0x16F));
fAddUml("=", 'A', QChar(0xC2));
fAddUml("=", 'E', QChar(0xCA));
fAddUml("=", 'I', QChar(0xCE));
fAddUml("=", 'O', QChar(0xD4));
fAddUml("=", 'U', QChar(0xDB));
fAddUml("=", 'a', QChar(0xE2));
fAddUml("=", 'e', QChar(0xEA));
fAddUml("=", 'i', QChar(0xEE));
fAddUml("=", 'o', QChar(0xF4));
fAddUml("=", 'u', QChar(0xFB));
fAddUml("=", 'Y', QChar(0x108));
fAddUml("=", 'y', QChar(0x109));
fAddUml(".", 'C', QChar(0x10A));
fAddUml(".", 'c', QChar(0x10B));
fAddUml(".", 'E', QChar(0x116));
fAddUml(".", 'e', QChar(0x117));
fAddUml(".", 'G', QChar(0x120));
fAddUml(".", 'g', QChar(0x121));
fAddUml(".", 'I', QChar(0x130));
fAddUml(".", 'Z', QChar(0x17B));
fAddUml(".", 'z', QChar(0x17C));
fAddUml(".", 'A', QChar(0x226));
fAddUml(".", 'a', QChar(0x227));
fAddUml(".", 'O', QChar(0x22E));
fAddUml(".", 'o', QChar(0x22F));
fAddUml(".", 'B', QChar(0x1E02));
fAddUml(".", 'b', QChar(0x1E03));
fAddUml(".", 'D', QChar(0x1E0A));
fAddUml(".", 'd', QChar(0x1E0B));
fAddUml(".", 'F', QChar(0x1E1E));
fAddUml(".", 'f', QChar(0x1E1F));
fAddUml(".", 'H', QChar(0x1E22));
fAddUml(".", 'h', QChar(0x1E23));
fAddUml(".", 'M', QChar(0x1E40));
fAddUml(".", 'm', QChar(0x1E41));
fAddUml(".", 'N', QChar(0x1E44));
fAddUml(".", 'n', QChar(0x1E45));
fAddUml(".", 'P', QChar(0x1E56));
fAddUml(".", 'p', QChar(0x1E57));
fAddUml(".", 'R', QChar(0x1E58));
fAddUml(".", 'r', QChar(0x1E59));
fAddUml(".", 'S', QChar(0x1E60));
fAddUml(".", 's', QChar(0x1E61));
fAddUml(".", 'T', QChar(0x1E6A));
fAddUml(".", 't', QChar(0x1E6B));
fAddUml(".", 'W', QChar(0x1E86));
fAddUml(".", 'w', QChar(0x1E87));
fAddUml(".", 'X', QChar(0x1E8A));
fAddUml(".", 'x', QChar(0x1E8B));
fAddUml(".", 'Y', QChar(0x1E8E));
fAddUml(".", 'y', QChar(0x1E8F));
fAddUml("u", 'A', QChar(0x102));
fAddUml("u", 'a', QChar(0x103));
fAddUml("u", 'E', QChar(0x114));
fAddUml("u", 'e', QChar(0x115));
fAddUml("u", 'G', QChar(0x11E));
fAddUml("u", 'g', QChar(0x11F));
fAddUml("u", 'I', QChar(0x12C));
fAddUml("u", 'i', QChar(0x12D));
fAddUml("u", 'O', QChar(0x14E));
fAddUml("u", 'o', QChar(0x14F));
fAddUml("u", 'U', QChar(0x16C));
fAddUml("u", 'u', QChar(0x16D));
fAddUml("c", 'C', QChar(0xC7));
fAddUml("c", 'c', QChar(0xE7));
fAddUml("c", 'G', QChar(0x122));
fAddUml("c", 'g', QChar(0x123));
fAddUml("c", 'K', QChar(0x136));
fAddUml("c", 'k', QChar(0x137));
fAddUml("c", 'L', QChar(0x13B));
fAddUml("c", 'l', QChar(0x13C));
fAddUml("c", 'N', QChar(0x145));
fAddUml("c", 'n', QChar(0x146));
fAddUml("c", 'R', QChar(0x156));
fAddUml("c", 'r', QChar(0x157));
fAddUml("c", 'S', QChar(0x15E));
fAddUml("c", 's', QChar(0x15F));
fAddUml("c", 'T', QChar(0x162));
fAddUml("c", 't', QChar(0x163));
fAddUml("c", 'E', QChar(0x228));
fAddUml("c", 'e', QChar(0x229));
fAddUml("c", 'D', QChar(0x1E10));
fAddUml("c", 'd', QChar(0x1E11));
fAddUml("c", 'H', QChar(0x1E28));
fAddUml("c", 'h', QChar(0x1E29));
fAddUml("H", 'O', QChar(0x150));
fAddUml("H", 'o', QChar(0x151));
fAddUml("H", 'U', QChar(0x170));
fAddUml("H", 'u', QChar(0x171));
fAddUml("H", 'Y', QChar(0x4F2));
fAddUml("H", 'y', QChar(0x4F3));
fAddUml("k", 'A', QChar(0x104));
fAddUml("k", 'a', QChar(0x105));
fAddUml("k", 'E', QChar(0x118));
fAddUml("k", 'e', QChar(0x119));
fAddUml("k", 'I', QChar(0x12E));
fAddUml("k", 'i', QChar(0x12F));
fAddUml("k", 'U', QChar(0x172));
fAddUml("k", 'u', QChar(0x173));
fAddUml("k", 'O', QChar(0x1EA));
fAddUml("k", 'u', QChar(0x1EB));
// ligatures, instructions without {letter}
fAddUml("ss", QChar(), QChar(0xDF));
fAddUml("ae", QChar(), QChar(0xE6));
fAddUml("AE", QChar(), QChar(0xC6));
fAddUml("oe", QChar(), QChar(0x153));
fAddUml("OE", QChar(), QChar(0x152));
fAddUml("o", QChar(), QChar(0xF8));
fAddUml("O", QChar(), QChar(0xD8));
fAddUml("S", QChar(), QChar(0xA7));
fAddUml("l", QChar(), QChar(0x142));
fAddUml("L", QChar(), QChar(0x141));
fAddUml("aa", QChar(), QChar(0xE5));
fAddUml("AA", QChar(), QChar(0xC5));
}
//----------------------------------------------------------
// check for emdash "---" or endash "--"
if (c=='-' && !parsingMathEnvironment) {
if (parseString.mid(currentTokenID, 3)=="---") {
currentTokenID+=2;
currentTokenName="---";
return currentToken=MTTemdash;
} else if (parseString.mid(currentTokenID, 2)=="--") {
currentTokenID+=1;
currentTokenName="--";
return currentToken=MTTendash;
} else {
currentTokenName="-";
return currentToken=MTThyphen;
}
}
//----------------------------------------------------------
// read an instruction name
if (c=='\\') {
//----------------------------------------------------------
// parsing accent instructions like \ss \"{a} ...
const QString next5=parseString.mid(currentTokenID, 5);
if (!parsingMathEnvironment && next5!="\\char"){
for (int len: accentLetters_LenBackslash) {
const QString acc=parseString.mid(currentTokenID, len);
if (acc.size()==len && accentLetters.contains(acc)) {
currentTokenName=accentLetters[acc];
currentTokenID+=acc.trimmed().size()-1; // forward the instruction, omit trailing whitespace in instruction
if (acc.endsWith('\\')) currentTokenID--;
return currentToken=MTTtext;
}
}
}
currentTokenID++;
if (currentTokenID>=parseString.size()-1) return currentToken=MTTnone;
c=parseString[currentTokenID];
//----------------------------------------------------------
// recognize linebreak "\\"
if (c=='\\') {
currentTokenName=c; // parse one-symbol instructions like \\, \& ...
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTinstructionNewline;
}
//----------------------------------------------------------
// parsing single-character instruction
if (SingleCharInstructions.contains(c)) {
currentTokenName=c; // parse one-symbol instructions like \\, \& ...
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTinstruction;
//----------------------------------------------------------
// letter-only instruction name
} else {
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";
if (currentTokenName.size()==0) error_list.append(tr("error @ ch. %1: parser encountered empty istruction").arg(currentTokenID));
else if (currentTokenName=="newline") return MTTinstructionNewline;
else if (currentTokenName=="linebreak") return MTTinstructionNewline;
else if (currentTokenName=="char") {
QString num="";
currentTokenID++;
c=parseString[currentTokenID];
if (c=='"') {
// match '\char"HEXDIGITS'
currentTokenID++;
c=parseString[currentTokenID];
while ((currentTokenID<parseString.size()) && (c.isDigit() || QString("aAbBcCdDeEfF").contains(c))) {
num+=c;
currentTokenID++;
c=parseString[currentTokenID];
}
if (currentTokenID<parseString.size()) currentTokenID--;
currentTokenName=QString::fromStdString(jkqtp_UnicodeToUTF8(num.toLongLong(nullptr, 16)));
return currentToken=MTTtext;
} else if (c=='`' || c=='\'') {
// match '\char"OCTALDIGITS'
currentTokenID++;
c=parseString[currentTokenID];
while ((currentTokenID<parseString.size()) && (QString("01234567").contains(c))) {
num+=c;
currentTokenID++;
if (currentTokenID<parseString.size()) c=parseString[currentTokenID];
else c=QChar();
}
if (currentTokenID<parseString.size()) currentTokenID--;
currentTokenName=QString::fromStdString(jkqtp_UnicodeToUTF8(num.toLongLong(nullptr, 8)));
return currentToken=MTTtext;
} else if (c.isDigit()) {
// match '\charDECIMALDIGITS'
while ((currentTokenID<parseString.size()) && (c.isDigit())) {
num+=c;
currentTokenID++;
c=parseString[currentTokenID];
}
if (currentTokenID<parseString.size()) currentTokenID--;
currentTokenName=QString::fromStdString(jkqtp_UnicodeToUTF8(num.toLongLong(nullptr, 10)));
return currentToken=MTTtext;
}
} else if (currentTokenName.startsWith("verb")) {
if (currentTokenName.size()>4) currentTokenID-=(currentTokenName.size()-4);
currentTokenID++;
const QString verbEndChar=parseString.mid(currentTokenID, 1);
currentTokenName=readUntil(true, verbEndChar);
return currentToken=MTTinstructionVerbatim;
} else if (currentTokenName=="begin") {
currentTokenID++;
if (parseString[currentTokenID]!='{') error_list.append(tr("error @ ch. %1: didn't find '{' after '\\begin'").arg(currentTokenID)); // find closing brace '}' after '\\begin{name');
currentTokenName=readUntil(true, "}");
if (currentTokenName=="verbatim") {
currentTokenName=readUntil(true, "\\end{verbatim}", true);
return currentToken=MTTinstructionVerbatim;
} else if (currentTokenName=="verbatim*") {
currentTokenName=readUntil(true, "\\end{verbatim*}", true);
return currentToken=MTTinstructionVerbatimVisibleSpace;
} else if (currentTokenName=="lstlisting") {
currentTokenName=readUntil(true, "\\end{lstlisting}", true);
return currentToken=MTTinstructionVerbatim;
}
return currentToken=MTTinstructionBegin;
} else if (currentTokenName=="end") {
currentTokenID++;
if (currentTokenID>=parseString.size() || parseString[currentTokenID]!='{') error_list.append(tr("error @ ch. %1: didn't find '{' after '\\end'").arg(currentTokenID)); // find closing brace '}' after '\\begin{name');
currentTokenName=readUntil(true, "}");
return currentToken=MTTinstructionEnd;
}
return currentToken=MTTinstruction;
//----------------------------------------------------------
// check for $ character
} else if (c=='$') {
//std::cout<<"found dollar\n";
return currentToken=MTTdollar;
//----------------------------------------------------------
// check for & character
} else if (c=='&') {
//std::cout<<"found ampersand\n";
return currentToken=MTTampersand;
//----------------------------------------------------------
// check for { character
} else if (c=='{') {
//----------------------------------------------------------
// parsing accent instructions like {\ss}
if (!parsingMathEnvironment){
for (int len: accentLetters_LenCurly) {
const QString acc=parseString.mid(currentTokenID, len);
if (acc.size()==len && accentLetters.contains(acc)) {
currentTokenName=accentLetters[acc];
currentTokenID+=acc.trimmed().size()-1; // forward the instruction, omit trailing whitespace in instruction
if (acc.endsWith('\\')) currentTokenID--;
return currentToken=MTTtext;
}
}
}
return currentToken=MTTopenbrace;
//----------------------------------------------------------
// check for } character
} else if (c=='}') {
return currentToken=MTTclosebrace;
//----------------------------------------------------------
// check for [ character
} else if (c=='[') {
return currentToken=MTTopenbracket;
//----------------------------------------------------------
// check for ] character
} else if (c==']') {
return currentToken=MTTclosebracket;
//----------------------------------------------------------
// check for _ character
} else if (c=='_') {
return currentToken=MTTunderscore;
//----------------------------------------------------------
// check for ^ character
} else if (c=='^') {
return currentToken=MTThat;
//----------------------------------------------------------
// check for whitespace character
} 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 {
//----------------------------------------------------------
// no instruction or special character => parse text
if (parsingMathEnvironment) {
// inside math environments we split texts at every brace {[(|)]} so that
// braces form their own JKQTMathTextTextNode and may be formated accordingly
if (mathEnvironmentSpecialChars.contains(c)) {
currentTokenName=c;
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTtext;
}
while (!mathEnvironmentSpecialEndChars.contains(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 (mathEnvironmentSpecialEndChars.contains(c) || c.isSpace()) currentTokenID--;
//currentTokenName=currentTokenName.trimmed();
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTtext;
} else {
while ((!c.isSpace()) && !TokenCharacters.contains(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 (TokenCharacters.contains(c) || c.isSpace()) currentTokenID--;
//currentTokenName=currentTokenName.trimmed();
//std::cout<<"found text node '"<<currentTokenName.toStdString()<<"'\n";
return currentToken=MTTtext;
}
}
return currentToken=MTTnone;
}
void JKQTMathText::giveBackToTokenizer(size_t count)
{
currentTokenID-=count;
}
JKQTMathTextNode* JKQTMathText::parseLatexString(bool get, JKQTMathTextBraceType quitOnClosingBrace, const QString& quitOnEnvironmentEnd, bool quitOnClosingBracket) {
QMap<QString,size_t> countLine;
//std::cout<<" entering parseLatexString()\n";
JKQTMathTextHorizontalListNode* nl=new JKQTMathTextHorizontalListNode(this);
if (get) getToken();
//----------------------------------------------------------
// initialize some static sets for easy and fast character lookup
static QSet<QString> mathEnvironmentSpecialText;
if (mathEnvironmentSpecialText.size()==0) {
mathEnvironmentSpecialText<<"+"<<"-"<<"="<<"*"<<"<"<<">";
}
bool getNew=true;
while (currentToken!=MTTnone) {
getNew=true;
if (currentToken==MTTtext) {
QString text=currentTokenName;
bool addWhite=false;
if (!parsingMathEnvironment) {
getToken();
getNew=false;
while (currentToken==MTTtext || currentToken==MTTwhitespace) {
if (currentToken==MTTtext) {
text+=currentTokenName;
getNew=true;
} else if (currentToken==MTTwhitespace) {
text+=" ";
getNew=true;
}
getToken();
getNew=false;
}
if (text.size()>0 && text[text.size()-1].isSpace()) {
addWhite=true;
text=text.left(text.size()-1);
}
}
if (parsingMathEnvironment) {
if (mathEnvironmentSpecialText.contains(text.trimmed()) && JKQTMathTextSymbolNode::hasSymbol(text.trimmed())) {
nl->addChild(new JKQTMathTextSymbolNode(this, text.trimmed()));
} else {
nl->addChild(new JKQTMathTextTextNode(this, text, addWhite, parsingMathEnvironment));
}
} else {
nl->addChild(new JKQTMathTextTextNode(this, text, addWhite, parsingMathEnvironment));
}
} else if (currentToken==MTTinstructionNewline) {
break;
} else if (currentToken==MTTwhitespace) {
if (!parsingMathEnvironment) nl->addChild(new JKQTMathTextWhitespaceNode(this));
} else if (currentToken==MTTendash) {
nl->addChild(new JKQTMathTextSymbolNode(this, "endash"));
} else if (currentToken==MTTemdash) {
nl->addChild(new JKQTMathTextSymbolNode(this, "emdash"));
} else if (currentToken==MTThyphen) {
nl->addChild(new JKQTMathTextSymbolNode(this, "hyphen"));
} else if (currentToken==MTTinstruction) {
const QString currentInstructionName=currentTokenName;
if (currentInstructionName=="\\") break; // break on linebrak character
if (currentInstructionName=="limits") {
if (nl->hasChildren()) nl->getLastChild()->setSubSuperscriptAboveBelowNode(true);
} else if (currentInstructionName=="nolimits") {
if (nl->hasChildren()) nl->getLastChild()->setSubSuperscriptAboveBelowNode(false);
} else if (currentInstructionName=="hline" || currentInstructionName=="midrule") {
countLine["hline"]=countLine.value("hline",0)+1;
} else if (currentInstructionName=="hdashline") {
countLine["hdashline"]=countLine.value("hdashline",0)+1;
} else if (currentInstructionName=="toprule" || currentInstructionName=="bottomrule") {
countLine["heavyline"]=countLine.value("heavyline",0)+1;
} else if (currentInstructionName=="right") {
getToken();
if (currentToken==MTTtext) {
if (currentTokenName.size()>0) {
bool tokenWasNoBrace=false;
const QString firstTokenChar(currentTokenName[0]);
if (TokenNameMatchesJKQTMathTextBraceType(firstTokenChar, quitOnClosingBrace, true, &tokenWasNoBrace)) {
lastRightBraceType=TokenName2JKQTMathTextBraceType(firstTokenChar);
if (quitOnClosingBrace!=MTBTAny) currentTokenName=currentTokenName.right(currentTokenName.size()-1);
break;
} else {
getNew=false;
}
}
} else if (currentToken==MTTinstruction) {
if (InstructionNameMatchesJKQTMathTextBraceType(currentTokenName, quitOnClosingBrace, true)) {
lastRightBraceType=InstructionName2JKQTMathTextBraceType(currentTokenName);
break;
}
} else if (currentToken==MTTclosebracket) {
if (quitOnClosingBrace==MTBTSquareBracket || quitOnClosingBrace==MTBTAny) {
lastRightBraceType=MTBTSquareBracket;
break;
}
} else {
error_list.append(tr("error @ ch. %1: unexpected token after \\left").arg(currentTokenID));
}
} else if (currentInstructionName=="left") {
getToken();
if (currentToken==MTTtext) {
if (currentTokenName.size()>0) {
const QString firstTokenChar(currentTokenName[0]);
const JKQTMathTextBraceType bracetype=TokenName2JKQTMathTextBraceType(firstTokenChar);
if (bracetype==MTBTNone) {
currentTokenName=currentTokenName.right(currentTokenName.size()-1);
JKQTMathTextNode* cn=parseLatexString(currentTokenName.size()<=0, MTBTAny);
nl->addChild(new JKQTMathTextBraceNode(this, MTBTNone, lastRightBraceType, cn));
} else if (isPrintableJKQTMathTextBraceType(bracetype)) {
currentTokenName=currentTokenName.right(currentTokenName.size()-1); // we already used the first character from the text token!
JKQTMathTextNode* c=parseLatexString(currentTokenName.size()<=0, bracetype);
nl->addChild(new JKQTMathTextBraceNode(this, bracetype, lastRightBraceType, c));
} else {
getNew=false;
}
}
} else if (currentToken==MTTinstruction) {
const JKQTMathTextBraceType bracetypeopening=InstructionName2OpeningJKQTMathTextBraceType(currentTokenName);
if (bracetypeopening!=MTBTUnknown) {
JKQTMathTextNode* c=parseLatexString(true, bracetypeopening);
nl->addChild(new JKQTMathTextBraceNode(this, bracetypeopening, lastRightBraceType, c));
} else if (currentToken==MTTinstruction && TokenNameMatchesJKQTMathTextBraceType(currentTokenName, quitOnClosingBrace, true)) {
break;
}
} else if (currentToken==MTTopenbracket) {
JKQTMathTextNode* c=parseLatexString(true, MTBTSquareBracket);
nl->addChild(new JKQTMathTextBraceNode(this, MTBTSquareBracket, lastRightBraceType, c));
} else {
error_list.append(tr("error @ ch. %1: unexpected token after \\left").arg(currentTokenID));
}
} else {
bool foundError=false;
JKQTMathTextNode* node=parseInstruction(&foundError, &getNew);
if (node) {
if (foundError) {
delete node;
node=nullptr;
} else {
nl->addChild(node);
}
}
}
} else if (currentToken==MTTunderscore) {
getToken();
JKQTMathTextNode* child=nullptr;
JKQTMathTextNode* child2=nullptr;
if (currentToken==MTTinstruction) {
child=parseInstruction(nullptr, &getNew);
} else if (currentToken==MTTopenbrace) {
child=parseLatexString(true);
} else if (currentToken==MTTtext) {
if (currentTokenName.size()<=1) {
child=new JKQTMathTextTextNode(this, currentTokenName, false, parsingMathEnvironment);
} else {
child=new JKQTMathTextTextNode(this, QString(currentTokenName[0]), false, parsingMathEnvironment);
child2=new JKQTMathTextTextNode(this, currentTokenName.right(currentTokenName.size()-1), false, parsingMathEnvironment);
}
} else {
getNew=false;
}
if (child!=nullptr) nl->addChild(new JKQTMathTextSubscriptNode(this, child));
if (child2!=nullptr) nl->addChild(child2);
} else if (currentToken==MTThat) {
getToken();
JKQTMathTextNode* child=nullptr;
JKQTMathTextNode* child2=nullptr;
if (currentToken==MTTinstruction) {
child=parseInstruction(nullptr, &getNew);
} else if (currentToken==MTTopenbrace) {
child=parseLatexString(true);
} else if (currentToken==MTTtext) {
if (currentTokenName.size()<=1) {
child=new JKQTMathTextTextNode(this, currentTokenName, false, parsingMathEnvironment);
} else {
child=new JKQTMathTextTextNode(this, QString(currentTokenName[0]), false, parsingMathEnvironment);
child2=new JKQTMathTextTextNode(this, currentTokenName.right(currentTokenName.size()-1), false, parsingMathEnvironment);
}
} else {
getNew=false;
}
if (child!=nullptr) nl->addChild(new JKQTMathTextSuperscriptNode(this, child));
if (child2!=nullptr) nl->addChild(child2);
} else if (currentToken==MTTopenbrace) {
nl->addChild(parseLatexString(true));
} else if (currentToken==MTTclosebrace) {
break;
} else if (currentToken==MTTopenbracket) {
nl->addChild(new JKQTMathTextTextNode(this, "[", false));
} else if (currentToken==MTTinstructionVerbatim) {
nl->addChild(new JKQTMathTextVerbatimNode(this, currentTokenName, false));
} else if (currentToken==MTTinstructionVerbatimVisibleSpace) {
nl->addChild(new JKQTMathTextVerbatimNode(this, currentTokenName, true));
} else if (currentToken==MTTinstructionBegin) {
const QString envname=currentTokenName;
if (envname=="matrix" || envname=="array" || envname=="aligned" || envname=="align" || envname=="cases" || envname=="pmatrix"|| envname=="bmatrix"|| envname=="Bmatrix"|| envname=="vmatrix"|| envname=="Vmatrix" || envname=="tabular") {
QString colspec="";
if (envname=="tabular" || envname=="array") {
if (getToken()==MTTopenbrace) {
colspec=readUntil(true, "}");
} else {
error_list.append(tr("error @ ch. %1: expected {COLUMNSPEC} after '\\begin{%2}'").arg(currentTokenID).arg(envname));
}
}
JKQTMathTextMatrixNode* matrixNode=new JKQTMathTextMatrixNode(this, colspec);
QVector< QVector<JKQTMathTextNode*> > items;
//int lines=0;
//int cols=0;
bool first=true;
bool firstLine=true;
QVector<JKQTMathTextNode*> line;
size_t colCount=0;
//std::cout<<"found \\begin{matrix}\n";
while (first || currentToken==MTTampersand || currentToken==MTTinstructionNewline) {
while (getToken()==MTTwhitespace) ; // eat whitespace
JKQTMathTextNode* it=simplifyAndTrimJKQTMathTextNode(parseLatexString(false, MTBTAny, envname));
if (firstLine) {
if (lastLineCount.value("hline",0)==1) {
matrixNode->setTopLine(JKQTMathTextMatrixNode::LTline);
} else if (lastLineCount.value("hline",0)>1) {
matrixNode->setTopLine(JKQTMathTextMatrixNode::LTdoubleline);
} else if (lastLineCount.value("heavyline",0)>0) {
matrixNode->setTopLine(JKQTMathTextMatrixNode::LTheavyline);
} else if (lastLineCount.value("hdashline",0)==1) {
matrixNode->setTopLine(JKQTMathTextMatrixNode::LTdashed);
} else if (lastLineCount.value("hdashline",0)>1) {
matrixNode->setTopLine(JKQTMathTextMatrixNode::LTdoubleDashed);
}
} else {
if (lastLineCount.value("hline",0)==1) {
matrixNode->setRowBottomLine(items.size()-1, JKQTMathTextMatrixNode::LTline);
} else if (lastLineCount.value("hline",0)>1) {
matrixNode->setRowBottomLine(items.size()-1, JKQTMathTextMatrixNode::LTdoubleline);
} else if (lastLineCount.value("heavyline",0)>0) {
matrixNode->setRowBottomLine(items.size()-1, JKQTMathTextMatrixNode::LTheavyline);
} else if (lastLineCount.value("hdashline",0)==1) {
matrixNode->setRowBottomLine(items.size()-1, JKQTMathTextMatrixNode::LTdashed);
} else if (lastLineCount.value("hdashline",0)>1) {
matrixNode->setRowBottomLine(items.size()-1, JKQTMathTextMatrixNode::LTdoubleDashed);
}
}
if (currentToken==MTTampersand) {
//std::cout<<" appending item\n";
line.append(it);
} else {
//std::cout<<" appending item and line with "<<line.size()<<" items.\n";
if (currentToken==MTTinstructionEnd) {
JKQTMathTextMultiChildNode* mnc=dynamic_cast<JKQTMathTextMultiChildNode*>(it);
if (mnc && mnc->childCount()>0) {
line.append(it);
} else {
line.append(it);
}
} else {
line.append(it);
}
if (currentToken==MTTinstructionNewline || line.size()>0) {
colCount=qMax(colCount, static_cast<size_t>(line.size()));
if (line.size()==0 || (line.size()>1 && line.size()==colCount)) {
items.append(line);
} else if (line.size()>1 && line.size()!=colCount) {
error_list.append(tr("error @ ch. %1: wrong number of entries widthin '\\begin{%2}...\\end{%2}'").arg(currentTokenID).arg(envname));
}
}
line.clear();
firstLine=false;
}
first=false;
}
//std::cout<<" creating matrix-node with "<<items.size()<<" items.\n";
matrixNode->setChildren(items);
if (envname=="pmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTParenthesis, MTBTParenthesis, matrixNode));
else if (envname=="cases") nl->addChild(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTNone, matrixNode));
else if (envname=="bmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTSquareBracket, MTBTSquareBracket, matrixNode));
else if (envname=="Bmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTCurlyBracket, MTBTCurlyBracket, matrixNode));
else if (envname=="vmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTSingleLine, MTBTSingleLine, matrixNode));
else if (envname=="Vmatrix") nl->addChild(new JKQTMathTextBraceNode(this, MTBTDoubleLine, MTBTDoubleLine, matrixNode));
else nl->addChild(matrixNode);
//std::cout<<" creating matrix-node ... done!\n";
} else if (envname=="center" || envname=="document" || envname=="flushleft" || envname=="flushright") {
JKQTMathTextHorizontalAlignment alignment=MTHALeft;
if (envname=="document") alignment=MTHALeft;
else alignment=String2JKQTMathTextHorizontalAlignment(envname);
nl->addChild(parseMultilineLatexString(true, envname, alignment, 1.0, MTSMDefaultSpacing, MTVOFirstLine));
} else if (envname=="framed" || envname=="shaded" || envname=="snugshade") {
JKQTMathTextHorizontalAlignment alignment=MTHALeft;
JKQTMathTextVerticalListNode* vlist = parseMultilineLatexString(true, envname, alignment, 1.0, MTSMDefaultSpacing, MTVOFirstLine);
QStringList color;
color<<jkqtp_QColor2String(Qt::lightGray);
nl->addChild(new JKQTMathTextBoxInstructionNode(this, envname, vlist, color));
} else {
error_list.append(tr("error @ ch. %1: unknown environment '%2'").arg(currentTokenID).arg(envname));
}
} else if (currentToken==MTTinstructionEnd) {
QString envname=currentTokenName;
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 if (currentToken==MTTclosebracket) {
if (quitOnClosingBracket) break;
else nl->addChild(new JKQTMathTextTextNode(this, "]", false));
} 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->addChild(new JKQTMathTextModifiedTextPropsInstructionNode(this, "equation", parseLatexString(true)));
}
}
if (getNew) getToken();
}
//std::cout<<" leaving parseLatexString()\n";
lastLineCount=countLine;
return simplifyJKQTMathTextNode(nl);
}
JKQTMathTextVerticalListNode *JKQTMathText::parseMultilineLatexString(bool get, const QString &quitOnEnvironmentEnd, JKQTMathTextHorizontalAlignment _alignment, double _linespacingFactor, JKQTMathTextLineSpacingMode spacingMode_, JKQTMathTextVerticalOrientation _verticalOrientation)
{
JKQTMathTextVerticalListNode* vlist = new JKQTMathTextVerticalListNode(this, _alignment, _linespacingFactor, spacingMode_, _verticalOrientation );
bool first=true;
while (first || currentToken==MTTinstructionNewline) {
vlist->addChild(simplifyAndTrimJKQTMathTextNode(parseLatexString(true, MTBTAny, quitOnEnvironmentEnd)));
first=false;
}
return vlist;
}
JKQTMathTextNode* JKQTMathText::parseInstruction(bool *_foundError, bool* getNew) {
static QHash<QString,double> big_instructions_family;
if (big_instructions_family.size()==0) {
big_instructions_family["big"]=0.85;//1.2;
big_instructions_family["bigl"]=0.85;//1.2;
big_instructions_family["bigm"]=0.85;//1.2;
big_instructions_family["bigr"]=0.85;//1.2;
big_instructions_family["Big"]=1.15;//1.85;
big_instructions_family["Bigl"]=1.15;//1.85;
big_instructions_family["Bigm"]=1.15;//1.85;
big_instructions_family["Bigr"]=1.15;//1.85;
big_instructions_family["bigg"]=1.45;//2.4;
big_instructions_family["biggl"]=1.45;//2.4;
big_instructions_family["biggm"]=1.45;//2.4;
big_instructions_family["biggr"]=1.45;//2.4;
big_instructions_family["Bigg"]=1.75;//3.1;
big_instructions_family["Biggl"]=1.75;//3.1;
big_instructions_family["Biggm"]=1.75;//3.1;
big_instructions_family["Biggr"]=1.75;//3.1;
}
if (currentToken!=MTTinstruction) {
if (_foundError) *_foundError=true;
if (getNew) *getNew=false;
error_list.append(tr("error @ ch. %1: expected instruction token").arg(currentTokenID));
return nullptr;
}
bool foundError=false;
const QString currentInstructionName=currentTokenName;
JKQTMathTextNode* child=nullptr;
if (getNew) *getNew=true;
if (JKQTMathTextWhitespaceNode::supportsInstructionName(currentInstructionName)) {
if (getNew) *getNew=true;
child= new JKQTMathTextWhitespaceNode(currentInstructionName, this);
} else if (JKQTMathTextSymbolNode::hasSymbol(currentInstructionName)) {
child=new JKQTMathTextSymbolNode(this, currentInstructionName);
if (JKQTMathTextSymbolNode::isSubSuperscriptBelowAboveSymbol(currentInstructionName) && parsingMathEnvironment) {
child->setSubSuperscriptAboveBelowNode(true);
}
if (getNew) *getNew=true;
} else if (big_instructions_family.contains(currentInstructionName)) {
// after \big,\bigl... we expect a symbol-instruction or at least one character of text
while (getToken()==MTTwhitespace);// eat whitespace
JKQTMathTextBraceType bracetype=MTBTUnknown;
bool openbrace=true;
if (currentToken==MTTinstruction) {
bracetype=TokenName2JKQTMathTextBraceType(currentTokenName, &openbrace);
} else if (currentToken==MTTtext) {
const QString firstTokenChar(currentTokenName[0]);
bracetype=TokenName2JKQTMathTextBraceType(firstTokenChar, &openbrace);
if (bracetype!=MTBTUnknown) {
giveBackToTokenizer(currentTokenName.size()-1);
} else {
giveBackToTokenizer(currentTokenName.size());
}
} else if (currentToken==MTTopenbracket) {
bracetype=MTBTSquareBracket;
openbrace=true;
} else if (currentToken==MTTclosebracket) {
bracetype=MTBTSquareBracket;
openbrace=false;
} else {
error_list.append(tr("error @ ch. %1: expected symbol-encoding instruction or a character after '\\%2' command, but found token type %3").arg(currentTokenID).arg(currentInstructionName).arg(tokenType2String(currentToken)));
}
if (bracetype!=MTBTUnknown) {
JKQTMathTextEmptyBoxNode* sizeChild=new JKQTMathTextEmptyBoxNode(this, 0, JKQTMathTextEmptyBoxNode::EBUem, big_instructions_family[currentInstructionName], JKQTMathTextEmptyBoxNode::EBUem);
if (openbrace) {
child=new JKQTMathTextBraceNode(this, bracetype, MTBTNone, sizeChild);
} else {
child=new JKQTMathTextBraceNode(this, MTBTNone, bracetype, sizeChild);
}
} else {
error_list.append(tr("error @ ch. %1: expected symbol-encoding instruction or character after '\\%2' command").arg(currentTokenID).arg(currentInstructionName));
}
if (getNew) *getNew=true;
} else if (JKQTMathTextModifiedTextPropsInstructionNode::supportsInstructionName(currentInstructionName)) {
const size_t Nparams=JKQTMathTextModifiedTextPropsInstructionNode::countParametersOfInstruction(currentInstructionName);
bool foundError=false;
const QStringList params=parseStringParams(true, Nparams, &foundError);
if (!foundError) {
if (getToken()==MTTopenbrace) {
const bool oldParseMath=parsingMathEnvironment;
auto __finalpaint=JKQTPFinally(std::bind([&oldParseMath](bool& parsingMathEnvironment) { parsingMathEnvironment=oldParseMath; }, std::ref(parsingMathEnvironment)));
JKQTMathTextModifiedTextPropsInstructionNode::modifyInMathEnvironment(currentInstructionName, parsingMathEnvironment, params);
child=new JKQTMathTextModifiedTextPropsInstructionNode(this, currentInstructionName, parseLatexString(true), params);
} else {
foundError=true;
}
}
if (foundError){
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(Nparams+1));
}
} else if (JKQTMathTextSimpleInstructionNode::supportsInstructionName(currentInstructionName)) {
const size_t Nparams=JKQTMathTextSimpleInstructionNode::countParametersOfInstruction(currentInstructionName);
bool foundError=false;
const QStringList params=parseStringParams(true, Nparams, &foundError);
if (!foundError) {
child=new JKQTMathTextSimpleInstructionNode(this, currentInstructionName, params);
}
if (foundError){
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(Nparams));
}
} else if (JKQTMathTextBoxInstructionNode::supportsInstructionName(currentInstructionName)) {
const size_t Nparams=JKQTMathTextBoxInstructionNode::countParametersOfInstruction(currentInstructionName);
bool foundError=false;
const QStringList params=parseStringParams(true, Nparams, &foundError);
if (!foundError) {
if (getNew) *getNew=true;
if (getToken()==MTTopenbrace) {
const bool oldParseMath=parsingMathEnvironment;
auto __finalpaint=JKQTPFinally(std::bind([&oldParseMath](bool& parsingMathEnvironment) { parsingMathEnvironment=oldParseMath; }, std::ref(parsingMathEnvironment)));
JKQTMathTextBoxInstructionNode::modifyInMathEnvironment(currentInstructionName, parsingMathEnvironment, params);
child=new JKQTMathTextBoxInstructionNode(this, currentInstructionName, parseLatexString(true), params);
} else {
foundError=true;
}
}
if (foundError){
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(Nparams+1));
}
} else if (JKQTMathTextPhantomNode::supportsInstructionName(currentInstructionName)) {
if (getNew) *getNew=true;
if (getToken()==MTTopenbrace) {
child=new JKQTMathTextPhantomNode(this, currentInstructionName, parseLatexString(true));
} else {
error_list.append(tr("error @ ch. %1: expected one argument in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName));
}
} else if (currentInstructionName=="substack" || currentInstructionName=="rsubstack" || currentInstructionName=="lsubstack") {
getToken();
JKQTMathTextHorizontalAlignment alignment=MTHACentered;
if (currentInstructionName=="rsubstack") alignment=MTHARight;
if (currentInstructionName=="lsubstack") alignment=MTHALeft;
if (currentToken==MTTopenbracket) {
alignment=String2JKQTMathTextHorizontalAlignment(parseSingleString(true));
if (currentToken!=MTTclosebracket) {
error_list.append(tr("error @ ch. %1: didn't find closing brace ']' after '\\%2[]{}' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
getToken();
}
if (currentToken==MTTopenbrace) {
child=parseMultilineLatexString(true, "", alignment, 1.0, MTSMMinimalSpacing, MTVOFirstLine);
if (currentToken!=MTTclosebrace) error_list.append(tr("error @ ch. %1: didn't find closing brace '}' after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
} else {
error_list.append(tr("error @ ch. %1: expected one argument in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else if (currentInstructionName=="sqrt") {
getToken();
if (currentToken==MTTopenbrace) {
child=new JKQTMathTextSqrtNode(this, parseLatexString(true));
} else if (currentToken==MTTopenbracket) {
JKQTMathTextNode* n1=parseLatexString(true, MTBTAny, "", true);
JKQTMathTextNode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
else error_list.append(tr("error @ ch. %1: expected one argument in '{' braces after '%2' command with an optional argument in []").arg(currentTokenID).arg(currentInstructionName));
if (n1 && n2) {
child=new JKQTMathTextSqrtNode(this, n2, n1);
} else {
if (n1) delete n1;
if (n2) delete n2;
error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName));
}
} else {
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else if (currentInstructionName=="cbrt") {
if (getToken()==MTTopenbrace) {
child=new JKQTMathTextSqrtNode(this, parseLatexString(true), new JKQTMathTextTextNode(this, "3", false));
} else {
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else if (currentInstructionName=="verb") {
if (getToken()==MTTopenbrace) {
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(currentInstructionName));
child=new JKQTMathTextTextNode(this, text, false);
}
} else {
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else if (JKQTMathTextDecoratedNode::supportsInstructionName(currentInstructionName)) {
if (getToken()==MTTopenbrace) {
child=new JKQTMathTextDecoratedNode(this, JKQTMathTextDecoratedNode::InstructionName2DecorationType(currentInstructionName), parseLatexString(true));
} else {
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else if (JKQTMathTextFracNode::supportsInstructionName(currentInstructionName)) {
if (getToken()==MTTopenbrace) {
JKQTMathTextNode* n1=parseLatexString(true);
JKQTMathTextNode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) child=new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::InstructionName2FracType(currentInstructionName));
else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName));
} else {
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else if (currentInstructionName=="binom") {
if (getToken()==MTTopenbrace) {
JKQTMathTextNode* n1=parseLatexString(true);
JKQTMathTextNode* n2=nullptr;
if (getToken()==MTTopenbrace) n2=parseLatexString(true);
if (n1 && n2) child=new JKQTMathTextBraceNode(this, MTBTParenthesis, MTBTParenthesis, new JKQTMathTextFracNode(this, n1, n2, JKQTMathTextFracNode::MTFMstackrel));
else error_list.append(tr("error @ ch. %1: expected two arguments in '{' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName));
} else {
error_list.append(tr("error @ ch. %1: expected %3 arguments in '{...}' braces after '%2' command").arg(currentTokenID).arg(currentInstructionName).arg(1));
}
} else {
if (getNew) *getNew=true;
foundError=true;
error_list.append(tr("error @ ch. %1: unknown instruction \\%2 or unsupported instruction at this location").arg(currentTokenID).arg(currentInstructionName));
}
if (_foundError) *_foundError=foundError;
return child;
}
QStringList JKQTMathText::parseStringParams(bool get, size_t Nparams, bool *foundError) {
const bool old_parsingMathEnvironment=parsingMathEnvironment;
auto reset_parsingMathEnvironment=JKQTPFinally([&]() { parsingMathEnvironment=old_parsingMathEnvironment; });
if (*foundError) *foundError=false;
if (Nparams<=0) return QStringList();
else {
QStringList params;
for (size_t n=0; n<Nparams; n++) {
if (n>0 || (n==0 && get)) getToken();
if (currentToken==MTTopenbrace) {
bool ok=true;
QString thisparam="";
while (ok) {
getToken();
if (currentToken==MTTtext) {
thisparam+=currentTokenName;
} else if (currentToken==MTTwhitespace) {
thisparam+=" ";
} else if (currentToken==MTTclosebrace) {
params.append(thisparam);
ok=false;
} else {
if (*foundError) *foundError=true;
return params;
}
}
} else {
if (*foundError) *foundError=true;
return params;
}
}
return params;
}
}
QString JKQTMathText::parseSingleString(bool get) {
const bool old_parsingMathEnvironment=parsingMathEnvironment;
auto reset_parsingMathEnvironment=JKQTPFinally([&]() { parsingMathEnvironment=old_parsingMathEnvironment; });
bool ok=true;
QString thisparam="";
while (ok) {
if (get) getToken();
get=true;
if (currentToken==MTTtext) {
thisparam+=currentTokenName;
} else if (currentToken==MTTwhitespace) {
thisparam+=" ";
} else {
ok=false;
}
}
return thisparam;
}
QString JKQTMathText::readUntil(bool get, const QString &endsequence, bool removeFirstlineWhitespace)
{
if (get) currentTokenID++;
QString seq;
while (currentTokenID<parseString.size() && !seq.endsWith(endsequence)) {
seq+=parseString[currentTokenID];
currentTokenID++;
}
currentTokenID--;
if (seq.endsWith(endsequence)) {
seq=seq.left(seq.size()-endsequence.size());
}
if (removeFirstlineWhitespace) {
QStringList sl=seq.split('\n');
if (sl.size()>0) {
bool allWS=true;
for (const QChar& ch: sl.first()) {
if (!ch.isSpace()) {
allWS=false;
break;
}
}
if (allWS) sl.removeFirst();
}
if (sl.size()>0) {
bool allWS=true;
for (const QChar& ch: sl.last()) {
if (!ch.isSpace()) {
allWS=false;
break;
}
}
if (allWS) sl.removeLast();
}
seq=sl.join("\n");
}
return seq;
}
JKQTMathTextNode *JKQTMathText::getParsedNode() const {
return this->parsedNode;
}
bool JKQTMathText::parse(const QString& text, ParseOptions options){
QString ntext;
if (options.testFlag(StartWithMathMode)) ntext=QString("$")+text+QString("$");
if (options.testFlag(AddSpaceBeforeAndAfter)) ntext=QString("\\;")+text+QString("\\;");
else ntext=text;
if (parsedNode && parseString==ntext) return true;
if (parsedNode!=nullptr) delete parsedNode;
parseString=ntext;
currentTokenID=-1;
currentToken=MTTnone;
currentTokenName="";
parsingMathEnvironment=false;
lastLineCount.clear();
error_list.clear();
if (options.testFlag(AllowLinebreaks)) {
parsedNode=parseMultilineLatexString(true, QString(""), MTHALeft, 1.0, MTSMDefaultSpacing, MTVOFirstLine);
} else {
parsedNode=parseLatexString(true);
}
parsedNode=simplifyJKQTMathTextNode(parsedNode);
return (parsedNode!=nullptr);
}
QSizeF JKQTMathText::getSize(QPainter& painter){
if (getNodeTree()!=nullptr) {
const JKQTMathTextNodeSize s=getSizeDetail(painter);
return s.getSize();
}
return QSizeF(0,0);
}
QSize JKQTMathText::getIntSize(QPainter &painter)
{
if (getNodeTree()!=nullptr) {
const JKQTMathTextNodeSize s=getSizeDetail(painter);
return s.getIntSize();
}
return QSize(0,0);
}
double JKQTMathText::getDescent(QPainter& painter) {
const JKQTMathTextNodeSize s=getSizeDetail(painter);
return s.getDescent();
}
double JKQTMathText::getAscent(QPainter& painter) {
const JKQTMathTextNodeSize s=getSizeDetail(painter);
return s.baselineHeight;
}
void JKQTMathText::getSizeDetail(QPainter& painter, double& width, double& ascent, double& descent, double& strikeoutPos) {
JKQTMathTextNodeSize s=getSizeDetail(painter);
width=s.width;
ascent=s.baselineHeight;
descent=s.getDescent();
strikeoutPos=s.strikeoutPos;
}
JKQTMathTextNodeSize JKQTMathText::getSizeDetail(QPainter &painter)
{
JKQTMathTextNodeSize s;
if (getNodeTree()!=nullptr) {
JKQTMathTextEnvironment ev;
ev.color=fontColor;
ev.fontSize=fontSize;
ev.fontSizeUnit=fontSizeUnits;
s=getNodeTree()->getSize(painter, ev);
}
return s;
}
void JKQTMathText::draw(QPainter &painter, QPointF x, bool drawBoxes)
{
draw(painter, x.x(), x.y(), drawBoxes);
}
double JKQTMathText::draw(QPainter& painter, double x, double y, bool drawBoxes){
if (getNodeTree()!=nullptr) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
JKQTMathTextEnvironment ev;
ev.color=fontColor;
ev.fontSize=fontSize;
ev.fontSizeUnit=fontSizeUnits;
getNodeTree()->setDrawBoxes(drawBoxes);
const double xend=getNodeTree()->draw(painter, x, y, ev);
return xend;
}
return x;
}
void JKQTMathText::draw(QPainter& painter, unsigned int flags, QRectF rect, bool drawBoxes) {
if (getNodeTree()!=nullptr) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
JKQTMathTextEnvironment ev;
ev.color=fontColor;
ev.fontSize=fontSize;
ev.fontSizeUnit=fontSizeUnits;
getNodeTree()->setDrawBoxes(drawBoxes);
const JKQTMathTextNodeSize size= getSizeDetail(painter);
// align left top
double x=rect.left();
double y=rect.top()+size.baselineHeight;
// care for horizontal align
if ((flags & Qt::AlignRight) != 0) x=x+rect.width()-size.width;
else if ((flags & Qt::AlignHCenter) != 0) x=x+(rect.width()-size.width)/2.0;
// care for vertical align
if ((flags & Qt::AlignBottom) != 0) y=y+rect.height()-size.overallHeight;
else if ((flags & Qt::AlignVCenter) != 0) y=y+(rect.height()-size.overallHeight)/2.0;
// finally draw
const double xend=getNodeTree()->draw(painter, x, y, ev);
}
}
QPixmap JKQTMathText::drawIntoPixmap(bool drawBoxes, QColor backgroundColor, int sizeincrease, qreal devicePixelRatio)
{
// 1. generate dummy QPixmap that is needed to use a QPainter
// we need the dummy, because we first need to determine the size of the render output
// for which we need a QPainter.
QPixmap pix(1,1);
pix.setDevicePixelRatio(devicePixelRatio);
{
QPainter painter;
// 2. now we determine the size and additional parameters,
// such as the ascent(or "baseline height")
painter.begin(&pix);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
const JKQTMathTextNodeSize size=getSizeDetail(painter);
const QSize pixsize=size.getIntSize()+QSize(2*sizeincrease,2*sizeincrease);
painter.end();
// 3. finally we can generate a QPixmap with the appropriate
// size to contain the full rendering. We fill it with the
// color white and finally paint the math markup/LaTeX string
pix=QPixmap(pixsize);
pix.setDevicePixelRatio(devicePixelRatio);
pix.fill(backgroundColor);
painter.begin(&pix);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
draw(painter, Qt::AlignVCenter|Qt::AlignHCenter, QRect(QPoint(0,0),pixsize), drawBoxes);
painter.end();
}
return pix;
}
QImage JKQTMathText::drawIntoImage(bool drawBoxes, QColor backgroundColor, int sizeincrease, qreal devicePixelRatio, unsigned int resolution_dpi)
{
// 1. generate dummy QPixmap that is needed to use a QPainter
// we need the dummy, because we first need to determine the size of the render output
// for which we need a QPainter.
QImage img(1,1,QImage::Format_ARGB32);
img.setDevicePixelRatio(devicePixelRatio);
img.setDotsPerMeterX(resolution_dpi*(10000/254));
img.setDotsPerMeterY(resolution_dpi*(10000/254));
{
QPainter painter;
// 2. now we determine the size and additional parameters,
// such as the ascent(or "baseline height")
painter.begin(&img);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
const JKQTMathTextNodeSize size=getSizeDetail(painter);
const QSize pixsize=size.getIntSize()+QSize(2*sizeincrease,2*sizeincrease);
painter.end();
// 3. finally we can generate a QPixmap with the appropriate
// size to contain the full rendering. We fill it with the
// color white and finally paint the math markup/LaTeX string
img=QImage(pixsize*devicePixelRatio,QImage::Format_ARGB32);
img.setDevicePixelRatio(devicePixelRatio);
img.setDotsPerMeterX(resolution_dpi*(10000/254));
img.setDotsPerMeterY(resolution_dpi*(10000/254));
img.fill(backgroundColor);
painter.begin(&img);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
draw(painter, Qt::AlignVCenter|Qt::AlignHCenter, QRect(QPoint(0,0),pixsize), drawBoxes);
painter.end();
}
return img;
}
QPicture JKQTMathText::drawIntoPicture(bool drawBoxes)
{
// 1. generate dummy QPixmap that is needed to use a QPainter
// we need the dummy, because we first need to determine the size of the render output
// for which we need a QPainter.
QPicture pic;
{
QPainter painter;
// 2. now we determine the size and additional parameters,
// such as the ascent(or "baseline height")
painter.begin(&pic);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
const JKQTMathTextNodeSize size=getSizeDetail(painter);
painter.end();
// 3. finally we can generate a QPixmap with the appropriate
// size to contain the full rendering. We fill it with the
// color white and finally paint the math markup/LaTeX string
painter.begin(&pic);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
draw(painter, 0, size.baselineHeight, drawBoxes);
painter.end();
}
return pic;
}
JKQTMathTextNode *JKQTMathText::getNodeTree() const {
return parsedNode;
}
QString JKQTMathText::tokenType2String(tokenType type)
{
switch(type) {
case MTTnone: return "MTTnone";
case MTTtext: return "MTTtext";
case MTTinstruction: return "MTTinstruction";
case MTTinstructionNewline: return "MTTinstructionNewline";
case MTTunderscore: return "MTTunderscore";
case MTThat: return "MTThat";
case MTTdollar: return "MTTdollar";
case MTTopenbrace: return "MTTopenbrace";
case MTTclosebrace: return "MTTclosebrace";
case MTTopenbracket: return "MTTopenbracket";
case MTTclosebracket: return "MTTclosebracket";
case MTTwhitespace: return "MTTwhitespace";
case MTTampersand: return "MTTampersand";
case MTThyphen: return "MTThyphen";
case MTTendash: return "MTTendash";
case MTTemdash: return "MTTemdash";
case MTTinstructionVerbatim: return "MTTinstructionVerbatim";
case MTTinstructionVerbatimVisibleSpace: return "MTTinstructionVerbatimVisibleSpace";
case MTTinstructionBegin: return "MTTinstructionBegin";
case MTTinstructionEnd: return "MTTinstructionEnd";
}
return "???";
}