NEW/REWORKED: extended the set of functions like JKQTMathTextGetTightBoundingRect(): These use an internal, thread-safe cache and capsule calls to QFontMetricsF-instances. This significantly improves speed in (parallelized) plotting.

This commit is contained in:
jkriege2 2024-01-08 17:16:31 +01:00
parent 3fee9609fb
commit 09e07cb12a
27 changed files with 761 additions and 361 deletions

View File

@ -97,10 +97,10 @@ This test results in the following numbers (on my AMD Ryzen5 8/16-core laptop):
<b>VERSION:</b> 5.0.0
<b>BUILD MODE:</b> Release
<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 1896.0ms<br/>single runtimes = (236.9 +/- 379.1) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/>
<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 3399.6ms<br/>single runtimes = (141.6 +/- 366.9) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/><br/>
<u><b>PARALLEL RESULTS:</b></u><br/>
runtime, overall = 624.7ms<br/>single runtimes = (564.3 +/- 107.7) ms<br/>speedup = 7.23x<br/>threads / available = 8 / 16<br/><br/><b>speedup vs. serial = 3.0x</b>
runtime, overall = 526.7ms<br/>single runtimes = (166.4 +/- 9.9) ms<br/>speedup = 7.58x<br/>threads / available = 8 / 16<br/>batch runs = 3<br/><br/><b>speedup vs. serial = 6.5x</b>
[comment]:RESULTS_END
@ -108,8 +108,9 @@ runtime, overall = 624.7ms<br/>single runtimes = (564.3 +/- 107.7) ms<br/>speedu
From this data you can observe:
- The plotting parallelizes nicely, i.e. the speedup ist >7x on a 8-core-machine. This is the speedup calculated as sum of runtimes of each thread, divided by the runtime of all threads in parallel.
- BUT: the speedup of serialized plotting vs. parallel plotting is way smaller: It is only 2-3x. Also the runtime in each thread is about 3x longer than in the serialized example. This can be explained by the (significant) overhead due to shared caches (and therefore synchronization) between the plotters. This may be reworked in future!
- BUT: the speedup of serialized plotting vs. parallel plotting is a biz smaller: It is only 6-7x. Also the runtime in each thread is a bit longer than in the serialized example. This can be explained by the overhead due to shared caches (and therefore synchronization) between the plotters (e.g. using JKQTMathTextGetBoundingRect() within JKQTMathText).
- The variance in runtimes in the (initial) serial test-run is larger than in the parallel run. This is due to filling of the internal caches during the first plotting!
- NOTE: The parallel vs. serial speedup significantly depends on the complexity of the text rendering (i.e. usage of JKQTMathText). Therefore rendinering more complex textxs with more and more complex LaTeX markup, will result in smalle speedups!
.
Finally the application displays the plots:

View File

@ -21,6 +21,7 @@
#define NUM_PLOTS 8
#define NUM_GRAPHS 6
#define NUM_DATAPOINTS 1000
#define NUM_REPEATS 3
int main(int argc, char* argv[])
@ -33,11 +34,21 @@ int main(int argc, char* argv[])
mainWin->setCentralWidget(main=new QWidget(mainWin));
QString markdownFile="";
QString labelTemplate="Plot %1: $f(x)=\\cos\\left(x+\\sfrac{%1\\pi}{8}\\right)$";
QByteArray mdMATCH="RESULTS";
for (int i=1; i<argc; i++) {
if (QString(argv[i]).startsWith("--mdfile=")) {
markdownFile=QString::fromLatin1(argv[i]).right(QString::fromLatin1(argv[i]).size()-9);
if (markdownFile.startsWith('"')) markdownFile.remove('"');
}
if (QString(argv[i]).startsWith("--complexlabel")) {
labelTemplate="Plot %1: $f(x)=\\cos\\left(x+\\sfrac{%1\\pi}{8}\\right)$";
mdMATCH="COMPLEXRESULTS";
}
if (QString(argv[i]).startsWith("--simplelabel")) {
labelTemplate="Plot %1: $f(x)=\\cos(x+%1\\pi/8)$";
mdMATCH="COMPLEXRESULTS";
}
}
@ -72,40 +83,45 @@ int main(int argc, char* argv[])
lay_serial->addWidget(pic_serial.last(), 1);
lay_parallel->addWidget(pic_parallel.last(), 1);
}
QElapsedTimer timer;
QList<double> runtimesSerial;
timer.start();
for (int i=0; i<NUM_PLOTS; i++) {
double dur=0;
filenamesSerial<<PlottingThread::plotAndSave("serial", i, NUM_GRAPHS, NUM_DATAPOINTS, &dur);
runtimesSerial<<dur/1e6;
}
const double durSerialNano=timer.nsecsElapsed();
qDebug()<<"durSerial = "<<durSerialNano/1e6<<"ms";
QList<double> runtimesParallel;
QList<QSharedPointer<PlottingThread>> threads;
for (int i=0; i<NUM_PLOTS; i++) {
qDebug()<<" creating thread "<<i;
threads.append(QSharedPointer<PlottingThread>::create("parallel",i, NUM_GRAPHS, NUM_DATAPOINTS, nullptr));
}
timer.start();
for (int i=0; i<NUM_PLOTS; i++) {
qDebug()<<" staring thread "<<i;
threads[i]->start();
}
for (int i=0; i<NUM_PLOTS; i++) {
qDebug()<<" waiting for thread "<<i;
if (threads[i]->wait()) {
filenamesParallel<<threads[i]->getFilename();
runtimesParallel<<threads[i]->getRuntimeNanosends()/1e6;
}
}
const double durParallelNano=timer.nsecsElapsed();
qDebug()<<"durParallel = "<<durParallelNano/1e6<<"ms";
QList<double> runtimesSerial;
double durSerialNano=0;
double durParallelNano=0;
for (int run=0; run<NUM_REPEATS; run++) {
filenamesParallel.clear();
QElapsedTimer timer;
timer.start();
for (int i=0; i<NUM_PLOTS; i++) {
double dur=0;
filenamesSerial<<PlottingThread::plotAndSave("serial", i, NUM_GRAPHS, NUM_DATAPOINTS, labelTemplate, &dur);
runtimesSerial<<dur/1e6;
}
durSerialNano+=timer.nsecsElapsed();
qDebug()<<"durSerial = "<<durSerialNano/1e6<<"ms";
QList<QSharedPointer<PlottingThread>> threads;
for (int i=0; i<NUM_PLOTS; i++) {
qDebug()<<" creating thread "<<i;
threads.append(QSharedPointer<PlottingThread>::create("parallel",i, NUM_GRAPHS, NUM_DATAPOINTS, labelTemplate, nullptr));
}
timer.start();
for (int i=0; i<NUM_PLOTS; i++) {
qDebug()<<" staring thread "<<i;
threads[i]->start();
}
for (int i=0; i<NUM_PLOTS; i++) {
qDebug()<<" waiting for thread "<<i;
if (threads[i]->wait()) {
filenamesParallel<<threads[i]->getFilename();
runtimesParallel<<threads[i]->getRuntimeNanosends()/1e6;
}
}
durParallelNano+=timer.nsecsElapsed();
qDebug()<<"durParallel["<<run+1<<"] = "<<durParallelNano/1e6<<"ms";
threads.clear();
}
threads.clear();
for (int ii=0; ii<NUM_SHOWN_PLOTS; ii++) {
int i=ii;
@ -114,8 +130,8 @@ int main(int argc, char* argv[])
pic_parallel[ii]->setPixmap(QPixmap(filenamesParallel[i], "PNG"));
}
QString ser_result, par_result;
labSerialResult->setText(ser_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/><br/> ").arg(durSerialNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatSum(runtimesSerial.begin(), runtimesSerial.end())/(durSerialNano/1e6),0,'f',2).arg(1).arg(std::thread::hardware_concurrency()));
labParallelResult->setText(par_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/><br/><b>speedup vs. serial = %7x</b>").arg(durParallelNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatSum(runtimesParallel.begin(), runtimesParallel.end())/(durParallelNano/1e6),0,'f',2).arg(NUM_PLOTS).arg(std::thread::hardware_concurrency()).arg(durSerialNano/durParallelNano,0,'f',1));
labSerialResult->setText(ser_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/><br/><br/> ").arg(durSerialNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesSerial.begin(), runtimesSerial.end()),0,'f',1).arg(jkqtpstatSum(runtimesSerial.begin(), runtimesSerial.end())/(durSerialNano/1e6),0,'f',2).arg(1).arg(std::thread::hardware_concurrency()));
labParallelResult->setText(par_result=QString("runtime, overall = %1ms<br/>single runtimes = (%2 +/- %3) ms<br/>speedup = %4x<br/>threads / available = %5 / %6<br/>batch runs = %8<br/><br/><b>speedup vs. serial = %7x</b>").arg(durParallelNano/1e6,0,'f',1).arg(jkqtpstatAverage(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatStdDev(runtimesParallel.begin(), runtimesParallel.end()),0,'f',1).arg(jkqtpstatSum(runtimesParallel.begin(), runtimesParallel.end())/(durParallelNano/1e6),0,'f',2).arg(NUM_PLOTS).arg(std::thread::hardware_concurrency()).arg(durSerialNano/durParallelNano,0,'f',1).arg(NUM_REPEATS));
mainWin->show();
if (!markdownFile.isEmpty()) {
@ -126,11 +142,11 @@ int main(int argc, char* argv[])
md=f.readAll();
qDebug()<<" read "<<md.size()<<" bytes";
f.close();
const auto istart=md.indexOf("[comment]:RESULTS");
const auto iend=md.indexOf("[comment]:RESULTS_END");
const auto istart=md.indexOf("[comment]:"+mdMATCH);
const auto iend=md.indexOf("[comment]:"+mdMATCH+"_END");
qDebug()<<" istart="<<istart<<", iend="<<iend;
if (istart>=0 && iend>istart) {
const QByteArray newResults="[comment]:RESULTS\n\n<b>VERSION:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_VERSION)
const QByteArray newResults="[comment]:"+mdMATCH+"\n\n<b>VERSION:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_VERSION)
+"\n<b>BUILD MODE:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_BUILDTYPE)
+"\n\n<u><b>SERIAL RESULTS:</b></u><br/>"+ser_result.toUtf8()
+"\n\n<u><b>PARALLEL RESULTS:</b></u><br/>\n"+par_result.toUtf8()+"\n\n";

View File

@ -14,17 +14,18 @@
class PlottingThread: public QThread {
Q_OBJECT
public:
inline PlottingThread(const QString& filenamepart, int plotindex, int NUM_GRAPHS, int NUM_DATAPOINTS, QObject* parent):
inline PlottingThread(const QString& filenamepart, int plotindex, int NUM_GRAPHS, int NUM_DATAPOINTS, const QString& labeltemplate, QObject* parent):
QThread(parent),
m_plotindex(plotindex),
m_runtimeNanoseconds(0),
m_filenamepart(filenamepart),
m_filename(),
m_NUM_GRAPHS(NUM_GRAPHS),
m_NUM_DATAPOINTS(NUM_DATAPOINTS)
m_NUM_DATAPOINTS(NUM_DATAPOINTS),
m_labeltemplate(labeltemplate)
{}
inline static QString plotAndSave(const QString& filenamepart, int plotIndex, int NUM_GRAPHS, int NUM_DATAPOINTS, double* runtimeNanoseconds=nullptr) {
inline static QString plotAndSave(const QString& filenamepart, int plotIndex, int NUM_GRAPHS, int NUM_DATAPOINTS, const QString& labeltemplate, double* runtimeNanoseconds=nullptr) {
QElapsedTimer timer;
timer.start();
const QString filename=QDir(QDir::tempPath()).absoluteFilePath(QString("testimg_%1_%2.png").arg(filenamepart).arg(plotIndex));
@ -36,15 +37,15 @@ public:
JKQTPXYLineGraph* g;
plot.addGraph(g=new JKQTPXYLineGraph(&plot));
g->setXColumn(colX);
g->setYColumn(plot.getDatastore()->addColumnCalculatedFromColumn(colX, [&](double x) { return cos(x+double(i)/8.0*JKQTPSTATISTICS_PI)+rng.generateDouble()*0.2-0.1;}));
g->setTitle(QString("Plot %1: $f(x)=\\cos\\leftx+\\frac{%1\\pi}{8}\\right)").arg(i+1));
g->setYColumn(plot.getDatastore()->addColumnCalculatedFromColumn(colX, [&](double x) { return cos(x+double(i+plotIndex)/8.0*JKQTPSTATISTICS_PI)+rng.generateDouble()*0.2-0.1;}));
g->setTitle(labeltemplate.arg(i+plotIndex+1));
g->setDrawLine(true);
g->setSymbolType(JKQTPNoSymbol);
}
plot.setPlotLabel(QString("Test Plot %1").arg(plotIndex+1));
plot.getXAxis()->setAxisLabel("x-axis");
plot.getYAxis()->setAxisLabel("y-axis");
plot.setPlotLabel(QString("Test Plot %1 (%2)").arg(plotIndex+1).arg(filenamepart));
plot.getXAxis()->setAxisLabel("x-axis $x$");
plot.getYAxis()->setAxisLabel("y-axis $f(x)$");
plot.zoomToFit();
plot.saveAsPixelImage(filename, false, "PNG");
@ -59,15 +60,16 @@ public:
}
protected:
inline virtual void run() {
m_filename=plotAndSave(m_filenamepart, m_plotindex, m_NUM_GRAPHS, m_NUM_DATAPOINTS, &m_runtimeNanoseconds);
m_filename=plotAndSave(m_filenamepart, m_plotindex, m_NUM_GRAPHS, m_NUM_DATAPOINTS, m_labeltemplate, &m_runtimeNanoseconds);
}
int m_plotindex;
double m_runtimeNanoseconds;
QString m_filename;
QString m_filenamepart;
const QString m_filenamepart;
const int m_NUM_GRAPHS;
const int m_NUM_DATAPOINTS;
const QString m_labeltemplate;
};
#endif // MULTITHREADED_THREAD_H

View File

@ -70,7 +70,15 @@ class JKQTMathTextVerticalListNode; // forward
(which is modelled after LaTeX, but with tweaks especially for use in the context of GUI code)
- \ref jkqtmathtext_supportedlatex for a description of the supported LaTeX subset
.
\section JKQTMathTextUsageThreadSafety Thread-Safety/Re-Entrancy Guarantees
All functions in this class are reentrant. Therefore different instances off JKQTMathtext can be used in parallel in different threads.
DO NOT however use the same instance from multiple threads, as the functions are not thread-safe!
Also note that there are certain caches that reuse information (e.g. about fonts) from previous runs, which allow different instances
(also over different threads) to profit from each other. On the other hand, this strategy requires a bit of overhead due to synchronization,
but usually the speedup outweighs the overhead significantly!
\section JKQTMathTextUsage Usage

View File

@ -22,6 +22,7 @@
#include "jkqtmathtext/jkqtmathtexttools.h"
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpcachingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -29,6 +30,7 @@
#include <QFontInfo>
#include <QApplication>
#include <QFont>
#include <QReadWriteLock>
#include <mutex>
@ -877,81 +879,239 @@ QPainterPath JKQTMathTextMakeHBracePath(double x, double ybrace, double width, d
}
JKQTMathTextTBRData::JKQTMathTextTBRData(const QFont &f, const QString &text, QPaintDevice *pd):
fm(f, pd)
{
this->text=text;
this->tbr=this->fm.tightBoundingRect(text);
this->f=f;
//this->pd=pd;
if (pd) {
ldpiX=pd->logicalDpiX();
ldpiY=pd->logicalDpiY();
pdpiX=pd->physicalDpiX();
pdpiY=pd->physicalDpiY();
} else {
ldpiX=0;
ldpiY=0;
pdpiX=0;
pdpiY=0;
}
}
bool JKQTMathTextTBRData::operator==(const JKQTMathTextTBRData &other) const
{
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f;
}
namespace {
JKQTMathTextTBRDataH::JKQTMathTextTBRDataH(const QFont &f, const QString &text, QPaintDevice *pd)
{
this->text=text;
this->f=f;
if (pd) {
ldpiX=pd->logicalDpiX();
ldpiY=pd->logicalDpiY();
pdpiX=pd->physicalDpiX();
pdpiY=pd->physicalDpiY();
} else {
ldpiX=0;
ldpiY=0;
pdpiX=0;
pdpiY=0;
}
}
bool JKQTMathTextTBRDataH::operator==(const JKQTMathTextTBRDataH &other) const
{
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && text==other.text && f==other.f;
}
QRectF JKQTMathTextGetTightBoundingRect(const QFont &fm, const QString &text, QPaintDevice *pd)
{
thread_local QList<JKQTMathTextTBRData> JKQTMathText_tbrs=QList<JKQTMathTextTBRData>();
thread_local QHash<JKQTMathTextTBRDataH, QRectF> JKQTMathText_tbrh=QHash<JKQTMathTextTBRDataH, QRectF>();
JKQTMathTextTBRDataH dh(fm, text, pd);
if (pd) {
if (JKQTMathText_tbrh.contains(dh)) return JKQTMathText_tbrh[dh];
/*for (int i=0; i<tbrs.size(); i++) {
if (tbrs[i].f==fm && tbrs[i].text==text && (tbrs[i].ldpiX==pd->logicalDpiX() && tbrs[i].ldpiY==pd->logicalDpiY() && tbrs[i].pdpiX==pd->physicalDpiX() && tbrs[i].pdpiY==pd->physicalDpiY())) {
//qDebug()<<" ### "<<fm<<pd<<tbrs[i].text<<tbrs[i].tbr;
return tbrs[i].tbr;
struct JKQTMathTextCacheKeyBase {
inline explicit JKQTMathTextCacheKeyBase(const QFont& f_, QPaintDevice *pd):
f(f_)
{
if (pd) {
ldpiX=pd->logicalDpiX();
ldpiY=pd->logicalDpiY();
pdpiX=pd->physicalDpiX();
pdpiY=pd->physicalDpiY();
} else {
ldpiX=0;
ldpiY=0;
pdpiX=0;
pdpiY=0;
}
}*/
} else {
//qDebug()<<"warning no pd";
}
QFont f;
int ldpiX, ldpiY, pdpiX, pdpiY;
inline bool operator==(const JKQTMathTextCacheKeyBase& other) const{
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && pdpiX==other.pdpiX && pdpiY==other.pdpiY && f==other.f;
};
};
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
inline size_t qHash(const JKQTMathTextCacheKeyBase& data, size_t seed=0) {
#else
inline uint qHash(const JKQTMathTextCacheKeyBase& data) {
const size_t seed=0;
#endif
return qHash(data.f)+::qHash(data.ldpiX,seed)+::qHash(data.ldpiY)+::qHash(data.pdpiX)+::qHash(data.pdpiY);
}
JKQTMathTextTBRData d(fm, text, pd);
JKQTMathText_tbrs.append(d);
JKQTMathText_tbrh[dh]=d.tbr;
//qDebug()<<"TBRs lits: "<<tbrs.size();
//qDebug()<<"+++ "<<fm<<pd<<d.text<<d.tbr;
return d.tbr;
struct JKQTMathTextCacheKeyBaseExt: public JKQTMathTextCacheKeyBase {
inline explicit JKQTMathTextCacheKeyBaseExt(const QFont& f_, QPaintDevice *pd_):
JKQTMathTextCacheKeyBase(f_,pd_), pd(pd_)
{}
QPaintDevice *pd;
};
template <class TText=QString>
struct JKQTMathTextTBRDataH: public JKQTMathTextCacheKeyBase {
inline explicit JKQTMathTextTBRDataH(const QFont& f_, const TText& text_, QPaintDevice *pd):
JKQTMathTextCacheKeyBase(f_, pd), text(text_)
{
}
TText text;
inline bool operator==(const JKQTMathTextTBRDataH& other) const{
return JKQTMathTextCacheKeyBase::operator==(other) && text==other.text;
};
};
template <class TText=QString>
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
inline size_t qHash(const JKQTMathTextTBRDataH<TText>& data, size_t /*seed=0*/) {
#else
inline uint qHash(const JKQTMathTextTBRDataH<TText>& data) {
#endif
return qHash(data.f)+qHash(data.text)+::qHash(data.ldpiX)+::qHash(data.ldpiY)+::qHash(data.pdpiX)+::qHash(data.pdpiY);
}
template <class TText=QString>
struct JKQTMathTextTBRDataHExt: public JKQTMathTextTBRDataH<TText> {
inline explicit JKQTMathTextTBRDataHExt(const QFont& f_, const TText& text_, QPaintDevice *pd_):
JKQTMathTextTBRDataH<TText>(f_,text_,pd_), pd(pd_)
{}
QPaintDevice *pd;
};
}
QRectF JKQTMathTextGetTightBoundingRect(const QFont &f, const QString &text, QPaintDevice *pd)
{
//thread_local JKQTPDataCache<QRectF,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
[](const JKQTMathTextTBRDataHExt<QString>& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.tightBoundingRect(key.text);
});
return cache.get_inline(f, text, pd);
}
QRectF JKQTMathTextGetBoundingRect(const QFont &f, const QString &text, QPaintDevice *pd)
{
//thread_local JKQTPDataCache<QRectF,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
[](const JKQTMathTextTBRDataHExt<QString>& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.boundingRect(key.text);
});
return cache.get_inline(f, text, pd);
}
qreal JKQTMathTextGetHorAdvance(const QFont &f, const QString &text, QPaintDevice *pd)
{
//thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
[](const JKQTMathTextTBRDataHExt<QString>& key) {
const QFontMetricsF fm(key.f, key.pd);
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
return fm.horizontalAdvance(key.text);
#else
return fm.width(key.text);
#endif
});
return cache.get_inline(f, text, pd);
}
qreal JKQTMathTextGetRightBearing(const QFont &f, const QChar &text, QPaintDevice *pd)
{
//thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,true,JKQTMathTextTBRDataHExt<QChar>> cache(
[](const JKQTMathTextTBRDataHExt<QChar>& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.rightBearing(key.text);
});
return cache.get_inline(f, text, pd);
}
qreal JKQTMathTextGetLeftBearing(const QFont &f, const QChar &text, QPaintDevice *pd)
{
//thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,true,JKQTMathTextTBRDataHExt<QChar>> cache(
[](const JKQTMathTextTBRDataHExt<QChar>& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.leftBearing(key.text);
});
return cache.get_inline(f, text, pd);
}
qreal JKQTMathTextGetFontAscent(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.ascent();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontDescent(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.descent();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontHeight(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.height();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontLineWidth(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.lineWidth();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontLeading(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.leading();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontLineSpacing(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.lineSpacing();
});
return cache.get_inline(f, pd);
}
qreal JKQTMathTextGetFontStrikoutPos(const QFont &f, QPaintDevice *pd)
{
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
[](const JKQTMathTextCacheKeyBaseExt& key) {
const QFontMetricsF fm(key.f, key.pd);
return fm.strikeOutPos();
});
return cache.get_inline(f, pd);
}
QFont JKQTMathTextGetNonItalic(const QFont &font)
@ -1048,12 +1208,12 @@ JKQTMathTextBlackboradDrawingMode String2JKQTMathTextBlackboradDrawingMode(QStri
void JKQTMathTextDrawStringSimBlackboard(QPainter &painter, const QFont &f, const QColor& color, double x, double y, const QString &txt)
{
const QFontMetricsF fm(f, painter.device());
const QPen p(color, fm.lineWidth()/4.0, Qt::SolidLine);
const qreal lw=JKQTMathTextGetFontLineWidth(f, painter.device());
const QPen p(color, lw/4.0, Qt::SolidLine);
painter.setPen(p);
QPainterPath path;
path.addText(QPointF(x, y), f, txt);
path.addText(QPointF(x+fm.lineWidth()/2.0, y), f, txt);
path.addText(QPointF(x+lw/2.0, y), f, txt);
painter.drawPath(path);
}
@ -1074,3 +1234,4 @@ JKQTMathTextLineSpacingMode String2JKQTMathTextLineSpacingMode(QString tokenName
if (tokenName=="minimal" || tokenName=="min" || tokenName=="minimum") return MTSMMinimalSpacing;
return MTSMDefaultSpacing;
}

View File

@ -42,7 +42,8 @@
#include <QHash>
#include <QPainterPath>
#include <QtMath>
#include <QFontMetrics>
#include <QFontMetricsF>
class JKQTMathText; // forward
@ -471,41 +472,173 @@ JKQTMATHTEXT_LIB_EXPORT QPainterPath JKQTMathTextMakeDArrow(double x, double y,
*/
JKQTMATHTEXT_LIB_EXPORT void JKQTMathTextDrawStringSimBlackboard(QPainter& painter, const QFont& f, const QColor &color, double x, double y, const QString& txt);
struct JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTBRData {
explicit JKQTMathTextTBRData(const QFont& f, const QString& text, QPaintDevice *pd);
QFontMetricsF fm;
QString text;
QRectF tbr;
QFont f;
int ldpiX, ldpiY, pdpiX, pdpiY;
//QPaintDevice *pd;
bool operator==(const JKQTMathTextTBRData& other) const;
};
struct JKQTMATHTEXT_LIB_EXPORT JKQTMathTextTBRDataH {
explicit JKQTMathTextTBRDataH(const QFont& f, const QString& text, QPaintDevice *pd);
QString text;
QFont f;
int ldpiX, ldpiY, pdpiX, pdpiY;
bool operator==(const JKQTMathTextTBRDataH& other) const;
};
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
inline size_t qHash(const JKQTMathTextTBRDataH& data, size_t /*seed=0*/) {
#else
inline uint qHash(const JKQTMathTextTBRDataH& data) {
#endif
return qHash(data.f.family())+qHash(data.text);
}
/** \brief calculates the tight bounding rectangle around \a text, uses internal hashing to not redo a calculation that has already been performed
/** \brief calculates the tight bounding rectangle around \a text
* (from <a href="https://doc.qt.io/qt/qfontmetricsf.html#tightBoundingRect">QFontMetricsF::tightBoundingRect()</a>),
* uses internal (thread-local) hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the text of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT QRectF JKQTMathTextGetTightBoundingRect(const QFont &fm, const QString& text, QPaintDevice *pd);
/** \brief calculates the bounding rectangle around \a text
* (from (using <a href="https://doc.qt.io/qt/qfontmetricsf.html#boundingRect">QFontMetricsF::boundingRect()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the text of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT QRectF JKQTMathTextGetBoundingRect(const QFont &fm, const QString& text, QPaintDevice *pd);
/** \brief calculates the horizontal advance of \a text
* (from <a href="https://doc.qt.io/qt/qfontmetricsf.html#horizontalAdvance">QFontMetricsF::horizontalAdvance()</a>
* or \c QFontMetricsF::width() if it is not yet available in your Qt version),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the text of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetHorAdvance(const QFont &fm, const QString& text, QPaintDevice *pd);
/** \brief calculates the left bearing of \a text
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#leftBearing">QFontMetricsF::leftBearing()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the character of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetLeftBearing(const QFont &fm, const QChar& text, QPaintDevice *pd);
/** \brief calculates the right bearing of \a text
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#rightBearing">QFontMetricsF::rightBearing()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font the text should be set in
* \param text the character of which the properties are calculated
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetRightBearing(const QFont &fm, const QChar& text, QPaintDevice *pd);
/** \brief calculates the strikeout-pos of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#strikeoutPos">QFontMetricsF::strikeoutPos()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontStrikoutPos(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the line width of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#lineWidth">QFontMetricsF::lineWidth()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontLineWidth(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the ascent of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#ascent">QFontMetricsF::ascent()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontAscent(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the descent of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#descent">QFontMetricsF::descent()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontDescent(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the height of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#height">QFontMetricsF::height()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontHeight(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the leading of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#leading">QFontMetricsF::leading()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontLeading(const QFont &fm, QPaintDevice *pd);
/** \brief calculates the line spacing of \a font
* (from <a href="https://doc.qt.io/qt-6/qfontmetricsf.html#lineSpacing">QFontMetricsF::lineSpacing()</a>),
* uses internal hashing to not redo a calculation that has already been performed
* \ingroup jkqtmathtext_tools
*
* \param fm font for which to calculate
* \param pd (or \c nullptr) the currently used <a href="https://doc.qt.io/qt-6/qpaintdevice.html">QPaintDevice</a>
* (e.g. from <a href="https://doc.qt.io/qt/qpainter.html#device">QPainter::device()</a> )
*
* \note This function is thread-safe and uses the same cache for all threads (so they profit from eachother)
*/
JKQTMATHTEXT_LIB_EXPORT qreal JKQTMathTextGetFontLineSpacing(const QFont &fm, QPaintDevice *pd);
/** \brief returns a copy of \a f, but with the italic-property set to \c false
* \ingroup jkqtmathtext_tools
*/

View File

@ -24,8 +24,8 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
#include <QFontDatabase>
#include <QFontInfo>
@ -60,9 +60,9 @@ JKQTMathTextNodeSize JKQTMathTextBoxInstructionNode::getSizeInternal(QPainter& p
inst.modifier(ev, getParameters());
const QPen p=inst.pen(ev, getParameters(), parentMathText);
const QBrush b=inst.brush(ev, getParameters(), parentMathText);
const QFontMetricsF fmNonItalic(JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText)), painter.device());
const QFont fNonItalic=JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText));
const double lw=p.widthF();
const double padding=inst.paddingFactor*fmNonItalic.tightBoundingRect("x").width();
const double padding=inst.paddingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
JKQTMathTextNodeSize s;
@ -74,6 +74,9 @@ JKQTMathTextNodeSize JKQTMathTextBoxInstructionNode::getSizeInternal(QPainter& p
}
double JKQTMathTextBoxInstructionNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextBoxInstructionNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv;
@ -81,10 +84,10 @@ double JKQTMathTextBoxInstructionNode::draw(QPainter& painter, double x, double
inst.modifier(ev, getParameters());
const QPen p=inst.pen(ev, getParameters(), parentMathText);
const QBrush b=inst.brush(ev, getParameters(), parentMathText);
const QFontMetricsF fmNonItalic(JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText)), painter.device());
const QFont fNonItalic=JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText));
const double lw=p.widthF();
const double padding=inst.paddingFactor*fmNonItalic.tightBoundingRect("x").width();
const double rr=inst.roundingFactor*fmNonItalic.tightBoundingRect("x").width();
const double padding=inst.paddingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
const double rr=inst.roundingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
{
@ -116,10 +119,10 @@ bool JKQTMathTextBoxInstructionNode::toHtml(QString &html, JKQTMathTextEnvironme
inst.modifier(ev, getParameters());
const QPen p=inst.pen(ev, getParameters(), parentMathText);
const QBrush b=inst.brush(ev, getParameters(), parentMathText);
const QFontMetricsF fmNonItalic(JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText)));
const QFont fNonItalic=JKQTMathTextGetNonItalic(currentEv.getFont(parentMathText));
//const double lw=p.widthF();
const double padding=inst.paddingFactor*fmNonItalic.tightBoundingRect("x").width();
//const double rr=inst.roundingFactor*fmNonItalic.tightBoundingRect("x").width();
const double padding=inst.paddingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", nullptr).width();
//const double rr=inst.roundingFactor*JKQTMathTextGetBoundingRect(fNonItalic, "x", painter.device()).width();
QString s=QString("padding: %1px").arg(padding);
if (p!=Qt::NoPen) {
if (s.size()>0 && s.right(2)!="; ") s=s+"; ";
@ -310,7 +313,7 @@ JKQTMathTextBoxInstructionNode::InstructionProperties::ModifyEnvironmentFunctor
[](JKQTMathTextEnvironment& /*ev*/, const QStringList& /*parameters*/){};
JKQTMathTextBoxInstructionNode::InstructionProperties::GetBoxPenFunctor JKQTMathTextBoxInstructionNode::InstructionProperties::DefaultPen=
[](JKQTMathTextEnvironment& ev, const QStringList& /*parameters*/, JKQTMathText* parent){ return QPen(ev.color, QFontMetricsF(ev.getFont(parent)).lineWidth(), Qt::SolidLine); };
[](JKQTMathTextEnvironment& ev, const QStringList& /*parameters*/, JKQTMathText* parent){ return QPen(ev.color, JKQTMathTextGetFontLineWidth(ev.getFont(parent),nullptr), Qt::SolidLine); };
JKQTMathTextBoxInstructionNode::InstructionProperties::GetBoxPenFunctor JKQTMathTextBoxInstructionNode::InstructionProperties::NoPen=
[](JKQTMathTextEnvironment& /*ev*/, const QStringList& /*parameters*/, JKQTMathText* /*parent*/){ return Qt::NoPen; };

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -55,8 +56,8 @@ JKQTMathTextBraceNode::NodeSize JKQTMathTextBraceNode::getSizeInternalAndBrace(Q
{
NodeSize s;
const NodeSize childSize=getChild()->getSize(painter, currentEv);
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
const double minChildHeight=fm.tightBoundingRect("l").height();
const QFont f=currentEv.getFont(parentMathText);
const double minChildHeight=JKQTMathTextGetTightBoundingRect(f, "l", painter.device()).height();
double cAscentAboveStrike=0;
double cDescentBelowStrike=0;
@ -84,13 +85,16 @@ JKQTMathTextBraceNode::NodeSize JKQTMathTextBraceNode::getSizeInternalAndBrace(Q
}
double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextBraceNode[]::draw()"));
#endif
//std::cout<<"drawing brace-node: '"<<openbrace.toStdString()<<"' ... '"<<closebrace.toStdString()<<"'\n";
const NodeSize nodesize=getSizeInternalAndBrace(painter, currentEv);
doDrawBoxes(painter, x, y, nodesize);
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
const QFont f=currentEv.getFont(parentMathText);
const double lw=fm.lineWidth();
const double lw=JKQTMathTextGetFontLineWidth(f, painter.device());
double xnew=x;
@ -360,7 +364,6 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa
}
}
//qDebug()<<" ==> "<<bc<<fm.boundingRect(bc).width();
return xnew;
}
@ -466,20 +469,20 @@ JKQTMathTextBraceNode::NodeSize::NodeSize(const NodeSize &other):
void JKQTMathTextBraceNode::calcBraceSizes(NodeSize& out, QPainter &painter, const JKQTMathTextEnvironment &ev, const JKQTMathTextNodeSize &childSize) const
{
const QFontMetricsF fm(ev.getFont(parentMathText), painter.device());
const QSizeF openBraceS=calcBraceSize(fm, openbrace, childSize);
const QSizeF closeBraceS=calcBraceSize(fm, closebrace, childSize);
const QFont f=ev.getFont(parentMathText);
const QSizeF openBraceS=calcBraceSize(f, painter.device(), openbrace, childSize);
const QSizeF closeBraceS=calcBraceSize(f, painter.device(), closebrace, childSize);
out.openBraceWidth=openBraceS.width();
out.openBraceHeight=openBraceS.width();
out.closeBraceWidth=closeBraceS.width();
out.closeBraceHeight=closeBraceS.width();
}
QSizeF JKQTMathTextBraceNode::calcBraceSize(const QFontMetricsF &fm, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const
QSizeF JKQTMathTextBraceNode::calcBraceSize(const QFont &f, QPaintDevice *pd, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const
{
double braceWidth=0.0;
double braceHeight=0.0;
const double lw=fm.lineWidth();
const double lw=JKQTMathTextGetFontLineWidth(f, pd);
const double dblline_distance=2.0*lw;
braceHeight=childSize.overallHeight*parentMathText->getBraceFactor();
braceWidth=lw*5.0;
@ -489,7 +492,7 @@ QSizeF JKQTMathTextBraceNode::calcBraceSize(const QFontMetricsF &fm, JKQTMathTex
if (bracetype==MTBTSingleLine) braceWidth=3.0*lw;
if (bracetype==MTBTSquareBracket || bracetype==MTBTCeilBracket || bracetype==MTBTFloorBracket) braceWidth=7.0*lw;
const double overSizeFactor=braceHeight/fm.height();
const double overSizeFactor=braceHeight/JKQTMathTextGetFontHeight(f, pd);
if (overSizeFactor>1.2) braceWidth=braceWidth*sqrt(overSizeFactor);
return QSizeF(braceWidth, braceHeight);

View File

@ -101,7 +101,7 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextBraceNode: public JKQTMathTextSingleCh
*
* \return width and hieght of the brace
*/
QSizeF calcBraceSize(const QFontMetricsF& fm, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const;
QSizeF calcBraceSize(const QFont& fm, QPaintDevice* pd, JKQTMathTextBraceType bracetype, const JKQTMathTextNodeSize &childSize) const;
};
#endif // JKQTMATHTEXTBRACENODE_H

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -133,15 +134,15 @@ JKQTMathTextNodeSize JKQTMathTextDecoratedNode::getSizeInternal(QPainter& painte
JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
const double cDescent=cs.getDescent();
const QFont font=ev.getFont(parentMathText);
const QFontMetricsF fm(font, painter.device());
const double decoSeparation=parentMathText->getDecorationSeparationFactor()*fm.ascent();
const double deco_height=parentMathText->getDecorationHeightFactor()*fm.ascent();
const double fascent=JKQTMathTextGetFontAscent(font, painter.device());
const double decoSeparation=parentMathText->getDecorationSeparationFactor()*fascent;
const double deco_height=parentMathText->getDecorationHeightFactor()*fascent;
const double deco_ypos=cs.baselineHeight+decoSeparation;
const double decoAboveAscent_ypos=fm.ascent()+decoSeparation;
const double decoAboveAscent_ypos=fascent+decoSeparation;
const double decobelow_ypos=cDescent+decoSeparation;
const double italic_xcorrection=getNonItalicXCorretion(painter, cs.width, ev, getChild());
const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?fm.boundingRect("~").width():fm.boundingRect("^").width())-italic_xcorrection;
const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, fm.lineWidth());
const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?JKQTMathTextGetBoundingRect(font,"~",painter.device()).width():JKQTMathTextGetBoundingRect(font,"^",painter.device()).width())-italic_xcorrection;
const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, JKQTMathTextGetFontLineWidth(font, painter.device()));
@ -227,20 +228,24 @@ const QHash<QString, JKQTMathTextDecoratedNode::DecorationType>& JKQTMathTextDec
}
double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextDecoratedNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv;
auto cs=getChild()->getSize(painter, ev);
const double cDescent=cs.overallHeight-cs.baselineHeight;
const QFont font=ev.getFont(parentMathText);
const QFontMetricsF fm(font, painter.device());
const double width_X=fm.boundingRect("X").width();
const double width_x=fm.boundingRect("x").width();
const double width_dot=fm.boundingRect(".").width()/2.0;
const double decoSeparation=parentMathText->getDecorationSeparationFactor()*fm.ascent();
const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, fm.lineWidth());
const double width_X=JKQTMathTextGetBoundingRect(font,"X",painter.device()).width();
const double width_x=JKQTMathTextGetBoundingRect(font,"x",painter.device()).width();
const double width_dot=JKQTMathTextGetBoundingRect(font,".",painter.device()).width()/2.0;
const double ascent=JKQTMathTextGetFontLineWidth(font, painter.device());
const double decoSeparation=parentMathText->getDecorationSeparationFactor()*ascent;
const double linewidth=qMax(parentMathText->ABS_MIN_LINEWIDTH, JKQTMathTextGetFontLineWidth(font, painter.device()));
const double linewidthArrow=linewidth*0.65;
const double deco_height=parentMathText->getDecorationHeightFactor()*fm.ascent();
const double decoAboveAscent_ypos=y-fm.ascent()-decoSeparation;
const double deco_height=parentMathText->getDecorationHeightFactor()*ascent;
const double decoAboveAscent_ypos=y-ascent-decoSeparation;
const double strike_ypos=y-cs.baselineHeight/2.0;
const double decobelow_ypos=y+cDescent+decoSeparation;
const double italic_xcorrection=getNonItalicXCorretion(painter, cs.width, ev, getChild());
@ -249,7 +254,7 @@ double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JK
const double deco_vecwidth=width_x*0.25;
const double deco_vecheight=deco_height*0.5;
const double deco_accentwidth=deco_height/4.0;
const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?fm.boundingRect("j").width():fm.boundingRect("^").width())-italic_xcorrection;
const double deco_miniwidth=((decoration==MTDtilde||decoration==MTDbreve)?JKQTMathTextGetBoundingRect(font,"~",painter.device()).width():JKQTMathTextGetBoundingRect(font,"^",painter.device()).width())-italic_xcorrection;
const double decotop_xcenter=x+italic_xcorrection+(cs.width-italic_xcorrection)/2.0;
const double decotop_xstart=decotop_xcenter-deco_width/2.0+linewidth/2.0;
const double decotop_xend=decotop_xcenter+deco_width/2.0-linewidth/2.0;
@ -280,7 +285,7 @@ double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JK
auto fDrawFontAccent=[&](QChar aDirect=QChar(), QChar aFallback=QChar()) -> bool {
if (!aDirect.isNull() && fm.inFont(aDirect)) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
const QRectF tbra=fm.tightBoundingRect(aDirect);
const QRectF tbra=JKQTMathTextGetBoundingRect(font, aDirect, painter.device());
painter.translate(decotop_xcenter-tbra.width()/2.0, (deco_ytopcenter+deco_ytoptop)/2.0);
//painter.setPen("red");
//painter.drawEllipse(0-2,0-2,4,4);
@ -298,7 +303,7 @@ double JKQTMathTextDecoratedNode::draw(QPainter& painter, double x, double y, JK
}
if (!aFallback.isNull() && fm.inFont(aFallback)) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
const QRectF tbra=fm.tightBoundingRect(aFallback);
const QRectF tbra=JKQTMathTextGetBoundingRect(font, aFallback, painter.device());
painter.translate(decotop_xcenter-tbra.width()/2.0, (deco_ytopcenter+deco_ytoptop)/2.0);
//painter.setPen("yellow");
//painter.drawEllipse(0-2,0-2,4,4);

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -128,15 +129,14 @@ JKQTMathTextNodeSize JKQTMathTextFracNode::getSizeInternal(QPainter& painter, JK
if (fracmode==MTFMsfrac) fracmode=MTFMstfrac;
}
const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
JKQTMathTextEnvironment ev1=currentEv;
JKQTMathTextEnvironment ev2=currentEv;
const double xheight=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height();
const double line_ascent=xheight/2.0;
//const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();//fm.ascent();
//const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();
const double xwidth=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).width();
const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();//fm.ascent();
const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();
const double braceheight=xheight*parentMathText->getUnderbraceBraceSizeXFactor();
const double braceseparation=xheight*parentMathText->getUnderbraceSeparationXFactor();
@ -152,11 +152,11 @@ JKQTMathTextNodeSize JKQTMathTextFracNode::getSizeInternal(QPainter& painter, JK
ev2.fontSize=ev2.fontSize*getFracScalingFactor()*0.7;
}
const QFontMetricsF fmev1(ev1.getFont(parentMathText), painter.device());
const QRectF AeTBR1=fmev1.tightBoundingRect("A");
const QFont fev1=ev1.getFont(parentMathText);
const QRectF AeTBR1=JKQTMathTextGetBoundingRect(fev1, "A", painter.device());
const double asc1=AeTBR1.height();
const QFontMetricsF fmev2(ev2.getFont(parentMathText), painter.device());
const QRectF AeTBR2=fmev2.tightBoundingRect("A");
const QFont fev2=ev2.getFont(parentMathText);
const QRectF AeTBR2=JKQTMathTextGetBoundingRect(fev2, "A", painter.device());
const double asc2=AeTBR2.height();
JKQTMathTextNodeSize size1=child1->getSize(painter, ev1);
@ -243,6 +243,9 @@ double JKQTMathTextFracNode::getFracScalingFactor() const
}
double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextFracNode[]::draw()"));
#endif
FracType fracmode=this->mode;
if (currentEv.isMathTextStyle()) {
if (fracmode==MTFMfrac) fracmode=MTFMtfrac;
@ -251,14 +254,13 @@ double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMat
doDrawBoxes(painter, x, y, currentEv);
const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
JKQTMathTextEnvironment ev1=currentEv;
JKQTMathTextEnvironment ev2=currentEv;
const double xheight=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height();
const double xwidth=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).width();
const double linewideth=fm.lineWidth();
const QRectF tbr_x=JKQTMathTextGetTightBoundingRect(f, "x", painter.device());
const double xheight=tbr_x.height();
const double xwidth=tbr_x.width();
const double linewideth=JKQTMathTextGetFontLineWidth(f, painter.device());
const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();//fm.ascent();
const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();//fm.ascent();
const double braceheight=xheight*parentMathText->getUnderbraceBraceSizeXFactor();
@ -277,13 +279,14 @@ double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMat
}
const QFontMetricsF fmev1(ev1.getFont(parentMathText), painter.device());
const QRectF AeTBR1=fmev1.tightBoundingRect("A");
const QFont fev1=ev1.getFont(parentMathText);
const QRectF AeTBR1=JKQTMathTextGetBoundingRect(fev1, "A", painter.device());
const double asc1=AeTBR1.height();
const QFontMetricsF fmev2(ev2.getFont(parentMathText), painter.device());
const QRectF AeTBR2=fmev2.tightBoundingRect("A");
const QFont fev2=ev2.getFont(parentMathText);
const QRectF AeTBR2=JKQTMathTextGetBoundingRect(fev2, "A", painter.device());
const double asc2=AeTBR2.height();
JKQTMathTextNodeSize size1=child1->getSize(painter, ev1);
JKQTMathTextNodeSize size2=child2->getSize(painter, ev2);
if (asc1>size1.baselineHeight) {

View File

@ -27,6 +27,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -63,12 +64,12 @@ JKQTMathTextNodeSize JKQTMathTextHorizontalListNode::getSizeInternal(QPainter& p
//bool wasBrace=false;
for (int i=0; i<nodes.size(); i++) {
const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
const double subsupershift=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height()*parentMathText->getOperatorsubsuperDistanceFactor();
const double subsuperextrawidth=fm.boundingRect('x').width()*parentMathText->getOperatorsubsuperExtraSpaceFactor();
const double subsuperSpecialModeAscent=fm.ascent()*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double subsuperSpecialModeDecent=fm.descent()*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double spaceWidth=fm.boundingRect(' ').width();
const auto tbr_x=JKQTMathTextGetTightBoundingRect(f, "x", painter.device());
const double subsupershift=tbr_x.height()*parentMathText->getOperatorsubsuperDistanceFactor();
const double subsuperextrawidth=tbr_x.width()*parentMathText->getOperatorsubsuperExtraSpaceFactor();
const double subsuperSpecialModeAscent=JKQTMathTextGetFontAscent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double subsuperSpecialModeDecent=JKQTMathTextGetFontDescent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double spaceWidth=JKQTMathTextGetBoundingRect(f, " ", painter.device()).width();
JKQTMathTextSymbolNode::NodeSize prevNodeSize;
JKQTMathTextNodeSize* prevNodeSizePtrForSubscript=nullptr;
@ -85,7 +86,7 @@ JKQTMathTextNodeSize JKQTMathTextHorizontalListNode::getSizeInternal(QPainter& p
if (shouldUseSpecialSubscriptMode) prevNodeSizePtrForSubscript=&prevNodeSize;
if (shouldUseSpecialSuperscriptMode) prevNodeSizePtrForSuperscript=&prevNodeSize;
}
const double subscript_xcorrection=prevNodeSize.baselineXCorrection+fm.lineWidth()*0.5;
const double subscript_xcorrection=prevNodeSize.baselineXCorrection+JKQTMathTextGetFontLineWidth(f, painter.device())*0.5;
JKQTMathTextSuperscriptNode* nodeI_SuperScript=dynamic_cast<JKQTMathTextSuperscriptNode*>(nodes[i]);
JKQTMathTextSubscriptNode* nodeI_SubScript=dynamic_cast<JKQTMathTextSubscriptNode*>(nodes[i]);
@ -327,6 +328,9 @@ JKQTMathTextNodeSize JKQTMathTextHorizontalListNode::getSizeInternal(QPainter& p
}
double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment ev) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextHorizontalListNode[]::draw()"));
#endif
JKQTMathTextEnvironment currentEv=ev;
doDrawBoxes(painter, x, y, currentEv);
double ynew=y;
@ -335,11 +339,11 @@ double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double
for (int i=0; i<nodes.size(); i++) {
bool doDraw=true;
const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
const double subsupershift=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height()*parentMathText->getOperatorsubsuperDistanceFactor();
const double subsuperextrawidth=fm.boundingRect('x').width()*parentMathText->getOperatorsubsuperExtraSpaceFactor();
const double subsuperSpecialModeAscent=fm.ascent()*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double subsuperSpecialModeDecent=fm.descent()*parentMathText->getSubsuperModeSelectionBySizeFactor();
const auto tbr_x=JKQTMathTextGetTightBoundingRect(f, "x", painter.device());
const double subsupershift=tbr_x.height()*parentMathText->getOperatorsubsuperDistanceFactor();
const double subsuperextrawidth=tbr_x.width()*parentMathText->getOperatorsubsuperExtraSpaceFactor();
const double subsuperSpecialModeAscent=JKQTMathTextGetFontAscent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
const double subsuperSpecialModeDecent=JKQTMathTextGetFontDescent(f, painter.device())*parentMathText->getSubsuperModeSelectionBySizeFactor();
JKQTMathTextSymbolNode::NodeSize prevNodeSize;
JKQTMathTextNodeSize* prevNodeSizePtrForSubscript=nullptr;
@ -359,7 +363,7 @@ double JKQTMathTextHorizontalListNode::draw(QPainter& painter, double x, double
if (shouldUseSpecialSubscriptMode) prevNodeSizePtrForSubscript=&prevNodeSize;
if (shouldUseSpecialSuperscriptMode) prevNodeSizePtrForSuperscript=&prevNodeSize;
}
const double subscript_xcorrection=prevNodeSize.baselineXCorrection+fm.lineWidth()*0.5;
const double subscript_xcorrection=prevNodeSize.baselineXCorrection+JKQTMathTextGetFontLineWidth(f, painter.device())*0.5;
JKQTMathTextSuperscriptNode* nodeI_SuperScript=dynamic_cast<JKQTMathTextSuperscriptNode*>(nodes[i]);
JKQTMathTextSubscriptNode* nodeI_SubScript=dynamic_cast<JKQTMathTextSubscriptNode*>(nodes[i]);

View File

@ -82,9 +82,8 @@ double JKQTMathTextSimpleInstructionNode::draw(QPainter &painter, double x, doub
doDrawBoxes(painter, x, y, currentEv);
QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault);
const QFontMetricsF fm(f, painter.device());
const QString txt=executeInstruction();
const QRectF bb=fm.boundingRect(txt);
const QRectF bb=JKQTMathTextGetBoundingRect(f, txt, painter.device());
painter.setPen(currentEv.color);
painter.setFont(f);
painter.drawText(x,y,txt);
@ -123,14 +122,13 @@ JKQTMathTextNodeSize JKQTMathTextSimpleInstructionNode::getSizeInternal(QPainter
{
QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault);
const QFontMetricsF fm(f, painter.device());
const QString txt=executeInstruction();
const QRectF bb=fm.boundingRect(txt);
const QRectF bb=JKQTMathTextGetBoundingRect(f, txt, painter.device());
JKQTMathTextNodeSize s;
s.width=bb.width();
s.baselineHeight=-bb.y();
s.overallHeight=bb.height();
s.strikeoutPos=fm.strikeOutPos();
s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
return s;
}

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -318,10 +319,10 @@ JKQTMathTextMatrixNode::LayoutInfo JKQTMathTextMatrixNode::calcLayout(QPainter &
JKQTMathTextEnvironment ev1=currentEv;
const QFontMetricsF fm(ev1.getFont(parentMathText), painter.device());
const double strikepos=fm.strikeOutPos();
const double xwidth=fm.boundingRect("x").width();
const double lw=fm.lineWidth()*1.5;
const QFont font=ev1.getFont(parentMathText);
const double strikepos=JKQTMathTextGetFontStrikoutPos(font, painter.device());
const double xwidth=JKQTMathTextGetBoundingRect(font,"f",painter.device()).width();
const double lw=JKQTMathTextGetFontLineWidth(font, painter.device())*1.5;
const double XPadding=parentMathText->getMatrixXPaddingFactor()*xwidth;
const double YPadding=parentMathText->getMatrixYPaddingFactor()*xwidth;
const double XSeparation=parentMathText->getMatrixXSeparationFactor()*xwidth;
@ -372,21 +373,25 @@ JKQTMathTextNodeSize JKQTMathTextMatrixNode::getSizeInternal(QPainter& painter,
}
double JKQTMathTextMatrixNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextMatrixNode[]::draw()"));
#endif
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
const QFont font=currentEv.getFont(parentMathText);
JKQTMathTextEnvironment ev1=currentEv;
const LayoutInfo l=calcLayout(painter, currentEv);
doDrawBoxes(painter, x, y, l);
const double xwidth=fm.boundingRect("x").width();
const double xwidth=JKQTMathTextGetBoundingRect(font,"f",painter.device()).width();
const double fontlw=JKQTMathTextGetFontLineWidth(font, painter.device());
const double XSeparation=parentMathText->getMatrixXSeparationFactor()*xwidth;
const double YSeparation=parentMathText->getMatrixYSeparationFactor()*xwidth;
const double yTop=y-l.baselineHeight+l.topPadding;
const double xLeft=x+l.leftPadding;
const double linewidth=parentMathText->getMatrixLinewidthThinFactor()*fm.lineWidth();
const double linewidthThick=parentMathText->getMatrixLinewidthHeavyFactor()*fm.lineWidth();
const double lineSeparation=parentMathText->getMatrixLineSeparationFactor()*fm.lineWidth();
const double linewidth=parentMathText->getMatrixLinewidthThinFactor()*fontlw;
const double linewidthThick=parentMathText->getMatrixLinewidthHeavyFactor()*fontlw;
const double lineSeparation=parentMathText->getMatrixLineSeparationFactor()*fontlw;
double leftlineX=xLeft-l.leftPadding/2.0;
double rightlineX=x+l.width-l.rightPadding/2.0;
double toplineY=yTop-l.topPadding/2.0;

View File

@ -23,6 +23,7 @@
#include "jkqtmathtext/jkqtmathtexttools.h"
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -58,6 +59,9 @@ JKQTMathTextNodeSize JKQTMathTextModifiedTextPropsInstructionNode::getSizeIntern
}
double JKQTMathTextModifiedTextPropsInstructionNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextModifiedTextPropsInstructionNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv;

View File

@ -22,6 +22,7 @@
#include "jkqtmathtext/nodes/jkqtmathtextnoopnode.h"
#include "jkqtmathtext/nodes/jkqtmathtextnode.h"
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
@ -67,6 +68,9 @@ QString JKQTMathTextBlockNode::getTypeName() const
double JKQTMathTextBlockNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextBlockNode[]::draw()"));
#endif
return child->draw(painter, x, y, currentEv);
}

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -52,16 +53,16 @@ JKQTMathTextSqrtNode::~JKQTMathTextSqrtNode() {
JKQTMathTextNodeSize JKQTMathTextSqrtNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv) const {
JKQTMathTextNodeSize s;
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
const QFont f=currentEv.getFont(parentMathText);
JKQTMathTextEnvironment evSmall=currentEv;
evSmall.fontSize=currentEv.fontSize*parentMathText->getSqrtSmallFontFactor();
evSmall.italic=false;
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, currentEv);
const double descent=cs.getDescent();
const double sqrtwidth=fm.boundingRect("X").width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), fm.ascent());
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), fm.descent());
const double sqrtwidth=JKQTMathTextGetBoundingRect(f, "X", painter.device()).width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontAscent(f, painter.device()));
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontDescent(f, painter.device()));
s.overallHeight=newAscent+newDescent;
s.baselineHeight=newAscent;
@ -76,20 +77,22 @@ JKQTMathTextNodeSize JKQTMathTextSqrtNode::getSizeInternal(QPainter& painter, JK
}
double JKQTMathTextSqrtNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSqrtNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv);
const QFont f=currentEv.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
JKQTMathTextEnvironment evSmall=currentEv;
evSmall.fontSize=currentEv.fontSize*parentMathText->getSqrtSmallFontFactor();
evSmall.italic=false;
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, currentEv);
const double descent=cs.overallHeight-cs.baselineHeight;
const double sqrtwidth=fm.boundingRect("X").width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), fm.ascent());
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), fm.descent());
const double linewidth=fm.lineWidth();
const double sqrtwidth=JKQTMathTextGetBoundingRect(f, "X", painter.device()).width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(cs.baselineHeight*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontAscent(f, painter.device()));
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), JKQTMathTextGetFontDescent(f, painter.device()));
const double linewidth=JKQTMathTextGetFontLineWidth(f, painter.device());
const double tinyhookSize=sqrtwidth*0.1;
const double smalltextIndent=0.6*sqrtwidth;

View File

@ -24,6 +24,10 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -50,7 +54,6 @@ JKQTMathTextNodeSize JKQTMathTextSuperscriptNode::getSizeWithSpecialPlacement(QP
JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
const QFont fnt=currentEv.getFont(parentMathText);
const QFontMetricsF fm(fnt, painter.device());
//const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device());
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
const double childDescent=cs.getDescent();
@ -67,7 +70,7 @@ JKQTMathTextNodeSize JKQTMathTextSuperscriptNode::getSizeWithSpecialPlacement(QP
s.baselineHeight=s.overallHeight=cs.overallHeight+shiftToChildBottom;
s.width=cs.width;
if (prevNodeSizeForSpecialPlacement!=nullptr) s.strikeoutPos=prevNodeSizeForSpecialPlacement->strikeoutPos;
else s.strikeoutPos=fm.strikeOutPos();
else s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(fnt, painter.device());
return s;
}
@ -77,13 +80,15 @@ JKQTMathTextNodeSize JKQTMathTextSuperscriptNode::getSizeInternal(QPainter &pain
}
double JKQTMathTextSuperscriptNode::drawWithSpecialPlacement(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSizeForSpecialPlacement) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSuperscriptNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
const QFont fnt=currentEv.getFont(parentMathText);
const QFontMetricsF fm(fnt, painter.device());
const QRectF tbr=JKQTMathTextGetTightBoundingRect(fnt, "x", painter.device());
const double xh=tbr.height();
//qDebug()<<"x="<<x<<" prevNodeSizeForSpecialPlacement="<<prevNodeSizeForSpecialPlacement<<" font="<<currentEv.getFont(parentMathText);
@ -98,11 +103,14 @@ double JKQTMathTextSuperscriptNode::drawWithSpecialPlacement(QPainter& painter,
double xx=x;
return getChild()->draw(painter, xx, y-(shiftToChildBottom+childDescent), ev);//+0.5*fm.boundingRect("A").width();
return getChild()->draw(painter, xx, y-(shiftToChildBottom+childDescent), ev);
}
double JKQTMathTextSuperscriptNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSuperscriptNode[]::draw()"));
#endif
return drawWithSpecialPlacement(painter, x, y, currentEv, nullptr);
}
@ -141,7 +149,6 @@ JKQTMathTextNodeSize JKQTMathTextSubscriptNode::getSizeWithSpecialPlacement(QPai
JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
const QFont f(ev.getFont(parentMathText));
const QFontMetricsF fm(f, painter.device());
//const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device());
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
@ -159,7 +166,7 @@ JKQTMathTextNodeSize JKQTMathTextSubscriptNode::getSizeWithSpecialPlacement(QPai
s.baselineHeight=cs.baselineHeight-shift_to_childBaseline;
s.overallHeight=cs.overallHeight;
if (prevNodeSizeForSpecialPlacement!=nullptr) s.strikeoutPos=prevNodeSizeForSpecialPlacement->strikeoutPos;
else s.strikeoutPos=fm.strikeOutPos();
else s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
s.width=cs.width;
return s;
}
@ -170,11 +177,13 @@ JKQTMathTextNodeSize JKQTMathTextSubscriptNode::getSizeInternal(QPainter &painte
}
double JKQTMathTextSubscriptNode::drawWithSpecialPlacement(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* prevNodeSizeForSpecialPlacement) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSubscriptNode[]::draw()"));
#endif
doDrawBoxes(painter, x, y, currentEv);
JKQTMathTextEnvironment ev=currentEv;
ev.fontSize=ev.fontSize*parentMathText->getSubsuperSizeFactor();
QFont f=ev.getFont(parentMathText);
const QFontMetricsF fm(f, painter.device());
//const QRectF tbr_of_letterM=JKQTMathTextGetTightBoundingRect(currentEv.getFont(parentMathText), "M", painter.device());
const JKQTMathTextNodeSize cs=getChild()->getSize(painter, ev);
@ -191,11 +200,14 @@ double JKQTMathTextSubscriptNode::drawWithSpecialPlacement(QPainter& painter, do
//qDebug()<<"baselineHeight="<<baselineHeight<<", overallHeight="<<overallHeight<<", strikeoutPos="<<strikeoutPos;
//qDebug()<<"shift="<<shift<<", yshift="<<yshift;
double xx=x;
return getChild()->draw(painter, xx, y+shift_to_childBaseline, ev);//+0.5*fm.boundingRect("A").width();
return getChild()->draw(painter, xx, y+shift_to_childBaseline, ev);
}
double JKQTMathTextSubscriptNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSubscriptNode[]::draw()"));
#endif
return drawWithSpecialPlacement(painter, x, y, currentEv, nullptr);
}

View File

@ -24,6 +24,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -54,14 +55,17 @@ JKQTMathTextNodeSize JKQTMathTextSymbolNode::getSizeInternal(QPainter& painter,
return getSymbolSize(painter, currentEv);
}
QRectF JKQTMathTextSymbolNode::getBoundingRect(const QFontMetricsF &fm, const QString &text, GlobalSymbolFlags globalFlags)
QRectF JKQTMathTextSymbolNode::getBoundingRect(const QFont &f, const QString &text, GlobalSymbolFlags globalFlags, QPaintDevice *pd)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::getBoundingRect()"));
#endif
if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) {
const QStringList str=text.simplified().trimmed().split(' ');
const QRectF brSp=fm.boundingRect("i");
const QRectF brSp=JKQTMathTextGetBoundingRect(f,"i",pd);
QRectF br;
for (int i=0; i<str.size(); i++) {
const QRectF lbr=fm.boundingRect(str[i]);
const QRectF lbr=JKQTMathTextGetBoundingRect(f,str[i],pd);
if (i==0) br=lbr;
else {
br.setWidth(br.width()+brSp.width()/2.0+lbr.width());
@ -75,18 +79,21 @@ QRectF JKQTMathTextSymbolNode::getBoundingRect(const QFontMetricsF &fm, const QS
}
return br;
} else {
return fm.boundingRect(text);
return JKQTMathTextGetBoundingRect(f,text,pd);
}
}
QRectF JKQTMathTextSymbolNode::getTightBoundingRect(const QFontMetricsF &fm, const QString &text, GlobalSymbolFlags globalFlags)
QRectF JKQTMathTextSymbolNode::getTightBoundingRect(const QFont &f, const QString &text, GlobalSymbolFlags globalFlags, QPaintDevice* pd)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::getTightBoundingRect()"));
#endif
if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) {
const QStringList str=text.simplified().trimmed().split(' ');
const QRectF brSp=fm.boundingRect("i");
const QRectF brSp=JKQTMathTextGetBoundingRect(f,"i",pd);
QRectF br;
for (int i=0; i<str.size(); i++) {
const QRectF lbr=fm.tightBoundingRect(str[i]);
const QRectF lbr=JKQTMathTextGetTightBoundingRect(f,str[i],pd);
if (i==0) br=lbr;
else {
br.setWidth(br.width()+brSp.width()/2.0+lbr.width());
@ -100,23 +107,25 @@ QRectF JKQTMathTextSymbolNode::getTightBoundingRect(const QFontMetricsF &fm, con
}
return br;
} else {
return fm.tightBoundingRect(text);
return JKQTMathTextGetTightBoundingRect(f,text,pd);
}
}
void JKQTMathTextSymbolNode::drawText(QPainter &p, const QString &text, GlobalSymbolFlags globalFlags, SymbolFlags symflags)
{
const QFontMetricsF fm(p.font(), p.device());
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::drawText()"));
#endif
if (has(globalFlags, MakeWhitespaceHalf) && text.contains(' ')) {
const QStringList str=text.simplified().trimmed().split(' ');
const QRectF brSp=fm.boundingRect("i");
const QRectF brSp=JKQTMathTextGetBoundingRect(p.font(), "i", p.device());
double x=0;
for (int i=0; i<str.size(); i++) {
p.drawText(QPointF(x,0), str[i]);
x=x+fm.boundingRect(str[i]).width()+brSp.width()/2.0;
x=x+JKQTMathTextGetBoundingRect(p.font(), str[i], p.device()).width()+brSp.width()/2.0;
}
} else {
const QRectF tbr=fm.tightBoundingRect(text);
const QRectF tbr=JKQTMathTextGetBoundingRect(p.font(), text, p.device());
p.save(); auto __finalpaint=JKQTPFinally([&p]() {p.restore();});
p.translate(tbr.center());
if (has(symflags, RotateSymbol90)) {
@ -138,6 +147,9 @@ void JKQTMathTextSymbolNode::drawText(QPainter &p, const QString &text, GlobalSy
double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::draw()"));
#endif
const NodeSize s=getSymbolSize(painter, currentEv);
doDrawBoxes(painter, x, y, s);
@ -146,20 +158,18 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
const auto drawProps=fullProps.getDrawingData(currentEv, parentMathText, painter);
const QFont f=drawProps.first;
const QFont fnonItalic=JKQTMathTextGetNonItalic(drawProps.first);
const QFontMetricsF fm(f, painter.device());
const QFontMetricsF fmNonItalic(fnonItalic, painter.device());
const JKQTMathTextSymbolNode::SymbolProps symprops=drawProps.second;
const SymbolFlags symflags=symprops.flags;
const QString sym=symprops.symbol;
const QRectF tbr=getTightBoundingRect(fm, sym, globalFlags);
const QRectF tbrNonItalic=getTightBoundingRect(fmNonItalic, sym, globalFlags);
const QRectF tbr=getTightBoundingRect(f, sym, globalFlags, painter.device());
const QRectF tbrNonItalic=getTightBoundingRect(fnonItalic, sym, globalFlags, painter.device());
//const QRectF br=getBoundingRect(fm, sym, globalFlags);
const QRectF tbrNoSymbol=JKQTMathTextGetTightBoundingRect(f, "X", painter.device());
const double yShift=symprops.yShiftFactor*tbr.height();
const double xShift=(s.width-tbr.width())/2.0;
const QPointF x0(x+xShift-tbr.x(), y+yShift);
double italic_xcorrection=fabs(tbr.width()-tbrNonItalic.width());
if (fabs(italic_xcorrection)<1e-6) italic_xcorrection=double(fm.boundingRect(' ').width())*0.4;
if (fabs(italic_xcorrection)<1e-6) italic_xcorrection=double(JKQTMathTextGetBoundingRect(f, " ", painter.device()).width())*0.4;
//std::cout<<"SYMB::draw(): symbolName="<<symbolName.toStdString()<<" font="<<f.family().toStdString()<<" sym="<<sym.toStdString()<<"(0x"<<std::hex<<((sym.size()==0)?uint64_t(0):uint64_t(sym[0].unicode()))<<") yShiftFactor="<<symprops.yShiftFactor<<"\n";
@ -173,7 +183,7 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
if (has(symflags, DrawLeftHBar) || has (symflags, DrawRightHBar)) {
//qDebug()<<" -> DrawLeftHBar or DrawRightHBar";
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(QPen(currentEv.color, fm.lineWidth()));
painter.setPen(QPen(currentEv.color, JKQTMathTextGetFontLineWidth(f, painter.device())));
const double xh=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).height();
const double ybar=-xh*1.1;
const double deltaybar=xh*0.2;
@ -184,7 +194,7 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
if (has(symflags, DrawVertLine)) {
//qDebug()<<" -> DrawVertLine";
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(QPen(currentEv.color, fm.lineWidth()));
painter.setPen(QPen(currentEv.color, JKQTMathTextGetFontLineWidth(f, painter.device())));
const double ybar=tbr.top();
const double xbarstart=italic_xcorrection+tbrNonItalic.width()/2.0;
const double xbarend=tbrNonItalic.width()/2.0;
@ -192,22 +202,16 @@ double JKQTMathTextSymbolNode::draw(QPainter& painter, double x, double y, JKQTM
}
if (has(symflags, DrawSlash)) {
//qDebug()<<" -> DrawSlash";
painter.drawText(QPointF((s.width-fm.boundingRect('/').width())/2.0,0),"/");
painter.drawText(QPointF((s.width-JKQTMathTextGetBoundingRect(f, "/", painter.device()).width())/2.0,0),"/");
}
if (has(symflags, DrawBackSlash)) {
//qDebug()<<" -> DrawBackSlash";
painter.drawText(QPointF((s.width-fm.boundingRect('\\').width())/2.0,0),"\\");
painter.drawText(QPointF((s.width-JKQTMathTextGetBoundingRect(f, "\\", painter.device()).width())/2.0,0),"\\");
}
/*painter.save();
painter.setPen(QPen(QColor("red"), 0.5, Qt::DotLine));
painter.drawEllipse(0,0,5,5);
painter.drawRect(tbr);
painter.setPen(QPen(QColor("blue"), 0.5, Qt::DashLine));
painter.drawRect(br);
painter.restore();*/
} else { // draw a box to indicate an unavailable symbol
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(QPen(currentEv.color, fm.lineWidth()));
painter.setPen(QPen(currentEv.color, JKQTMathTextGetFontLineWidth(f, painter.device())));
painter.drawRect(QRectF(x0.x(), x0.y()-tbrNoSymbol.height(), tbrNoSymbol.width(), tbrNoSymbol.height()));
}
@ -232,18 +236,20 @@ QString JKQTMathTextSymbolNode::getSymbolName() const {
JKQTMathTextSymbolNode::NodeSize JKQTMathTextSymbolNode::getSymbolSize(QPainter &painter, JKQTMathTextEnvironment currentEv) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextSymbolNode[]::getSymbolSize()"));
#endif
NodeSize s;
const auto fullProps=symbols().value(symbolName, SymbolFullProps());
const GlobalSymbolFlags globalFlags=fullProps.globalFlags;
const auto drawProps=fullProps.getDrawingData(currentEv, parentMathText, painter);
const QFont f=drawProps.first;
const QFontMetricsF fm(f, painter.device());
const JKQTMathTextSymbolNode::SymbolProps symprops=drawProps.second;
const SymbolFlags symflags=symprops.flags;
const QString sym=symprops.symbol;
const QRectF tbr=getTightBoundingRect(fm, sym, globalFlags);
const QRectF br=getBoundingRect(fm, sym, globalFlags);
const QRectF tbr=getTightBoundingRect(f, sym, globalFlags, painter.device());
const QRectF br=getBoundingRect(f, sym, globalFlags, painter.device());
const QRectF tbrNoSymbol=JKQTMathTextGetTightBoundingRect(f, "X", painter.device());
const QRectF mintbr=JKQTMathTextGetTightBoundingRect(f, "(", painter.device());
const QRectF dottbr=JKQTMathTextGetTightBoundingRect(f, ".", painter.device());
@ -272,13 +278,13 @@ JKQTMathTextSymbolNode::NodeSize JKQTMathTextSymbolNode::getSymbolSize(QPainter
const double oldDescent=s.overallHeight-s.baselineHeight;
if (has(symflags, HeightIsAscent)) {
s.baselineHeight=fm.ascent();
s.baselineHeight=JKQTMathTextGetFontAscent(f, painter.device());
s.overallHeight=s.baselineHeight+oldDescent;
}
if (has(symflags, RotateSymbol90)) {
s.width=qMax(s.overallHeight, s.width);
}
s.strikeoutPos=fm.strikeOutPos();
s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
if (has(globalFlags, IntLikeSymbolCorrection)) {
if (has(globalFlags, SubSuperscriptBelowAboveSymbol)) {
@ -288,7 +294,7 @@ JKQTMathTextSymbolNode::NodeSize JKQTMathTextSymbolNode::getSymbolSize(QPainter
s.topXCorrection=dottbr.width();
}
if (has(globalFlags, SubscriptCorrection) && sym.size()>0) {
s.baselineXCorrection=fm.rightBearing(sym[sym.size()-1]);
s.baselineXCorrection=JKQTMathTextGetRightBearing(f,sym[sym.size()-1],painter.device());
}
return s;
@ -384,7 +390,7 @@ const QHash<QString, JKQTMathTextSymbolNode::SymbolFullProps> &JKQTMathTextSymbo
* STANDARD Symbols available in all standard fonts
**************************************************************************************/
symbols["#"]=SimpleTextSymbol("#", "&num;");
symbols["%"]=SimpleTextSymbol("%", "&NestedGreaterGreater;");
symbols["%"]=SimpleTextSymbol("%", "&percent;");
symbols["&"]=SimpleTextSymbol("&", "&amp;");
symbols["("]=SimpleUprightTextSymbol("(");
symbols[")"]=SimpleUprightTextSymbol(")");

View File

@ -156,9 +156,9 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextSymbolNode: public JKQTMathTextNode {
friend inline bool has(GlobalSymbolFlags a, GlobalSymbolFlags b) { return (a&b)==b; }
/** \brief calculates the bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */
static QRectF getBoundingRect(const QFontMetricsF& fm, const QString& text, GlobalSymbolFlags globalFlags);
static QRectF getBoundingRect(const QFont &fm, const QString& text, GlobalSymbolFlags globalFlags, QPaintDevice *pd);
/** \brief calculates the tight bounding rect of \a text using \a fm and taking the flags from \a globalFlags into account */
static QRectF getTightBoundingRect(const QFontMetricsF& fm, const QString& text, GlobalSymbolFlags globalFlags);
static QRectF getTightBoundingRect(const QFont& fm, const QString& text, GlobalSymbolFlags globalFlags, QPaintDevice *pd);
/** \brief draw \a text at (0,0) using QPainter \a p and taking the flags from \a globalFlags into account */
static void drawText(QPainter &p, const QString &text, GlobalSymbolFlags globalFlags, SymbolFlags symflags);

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -141,15 +142,7 @@ JKQTMathTextTextNode::LayoutInfo JKQTMathTextTextNode::calcLayout(QPainter &pain
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());
const QFontMetricsF fm(f, painter.device());
const QFontMetricsF fmFallbackSym(fFallbackSym, painter.device());
const QFontMetricsF fmRoman(fRoman, painter.device());
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
const double sp=fm.horizontalAdvance(' ');
#else
const double sp=fm.width(' ');
#endif
const double sp=JKQTMathTextGetHorAdvance(f, " ", painter.device());
l.width=0;
double ascent=0;
double descent=0;
@ -160,23 +153,23 @@ JKQTMathTextTextNode::LayoutInfo JKQTMathTextTextNode::calcLayout(QPainter &pain
switch(l.fontMode[i]) {
case FMasDefined:
case FMasDefinedOutline:
br=fm.boundingRect(l.textpart[i]);
br=JKQTMathTextGetBoundingRect(f, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(f, l.textpart[i], painter.device());
if (f.italic() && l.textpart[i].size()>0) l.baselineXCorrection=fm.rightBearing(l.textpart[i].operator[](l.textpart[i].size()-1));
if (f.italic() && l.textpart[i].size()>0) l.baselineXCorrection=JKQTMathTextGetRightBearing(f,l.textpart[i].operator[](l.textpart[i].size()-1),painter.device());
break;
case FMasDefinedForceUpright:
br=fmUpright.boundingRect(l.textpart[i]);
br=JKQTMathTextGetBoundingRect(fUpright, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(fUpright, l.textpart[i], painter.device());
break;
case FMroman:
br=fmRoman.boundingRect(l.textpart[i]);
br=JKQTMathTextGetBoundingRect(fRoman, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(fRoman, l.textpart[i], painter.device());
if (fRoman.italic() && l.textpart[i].size()>0) l.baselineXCorrection=fmRoman.rightBearing(l.textpart[i].operator[](l.textpart[i].size()-1));
if (fRoman.italic() && l.textpart[i].size()>0) l.baselineXCorrection=JKQTMathTextGetRightBearing(fRoman,l.textpart[i].operator[](l.textpart[i].size()-1),painter.device());
break;
case FMfallbackSymbol:
br=fmFallbackSym.boundingRect(l.textpart[i]);
br=JKQTMathTextGetBoundingRect(fFallbackSym, l.textpart[i], painter.device());
tbr=JKQTMathTextGetTightBoundingRect(fFallbackSym, l.textpart[i], painter.device());
if (fFallbackSym.italic() && l.textpart[i].size()>0) l.baselineXCorrection=fmFallbackSym.rightBearing(l.textpart[i].operator[](l.textpart[i].size()-1));
if (fFallbackSym.italic() && l.textpart[i].size()>0) l.baselineXCorrection=JKQTMathTextGetRightBearing(fFallbackSym,l.textpart[i].operator[](l.textpart[i].size()-1),painter.device());
break;
}
l.textpartXPos.append(l.width);
@ -193,7 +186,7 @@ JKQTMathTextTextNode::LayoutInfo JKQTMathTextTextNode::calcLayout(QPainter &pain
}
l.overallHeight=(ascent+descent); //fm.height();
l.baselineHeight=ascent;
l.strikeoutPos=fm.strikeOutPos();
l.strikeoutPos=JKQTMathTextGetFontStrikoutPos(f, painter.device());
return l;
}
@ -285,6 +278,9 @@ void JKQTMathTextTextNode::splitTextForLayout(QPainter &painter, JKQTMathTextEnv
}
double JKQTMathTextTextNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextTextNode[]::draw()"));
#endif
const LayoutInfo l=calcLayout(painter, currentEv);
doDrawBoxes(painter, x, y, l);

View File

@ -25,6 +25,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -81,6 +82,9 @@ size_t JKQTMathTextVerbatimNode::getTabSize() const
double JKQTMathTextVerbatimNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextVerbatimNode[]::draw()"));
#endif
transformEnvironment(currentEv);
const LayoutInfo l=calcLayout(painter, currentEv);
doDrawBoxes(painter, x, y, l);
@ -134,10 +138,10 @@ JKQTMathTextVerbatimNode::LayoutInfo JKQTMathTextVerbatimNode::calcLayout(QPaint
QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault);
f.setFixedPitch(true);
const QFontMetricsF fm(f, painter.device());
const double linespacing=fm.lineSpacing()*lineSpacingFactor;
const double fleading=fm.leading();
const double synLeading=fm.lineWidth();
const qreal fascent=JKQTMathTextGetFontAscent(f, painter.device());
const double linespacing=JKQTMathTextGetFontLineSpacing(f, painter.device())*lineSpacingFactor;
const double fleading=JKQTMathTextGetFontLeading(f, painter.device());
const double synLeading=JKQTMathTextGetFontLineWidth(f, painter.device());
const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor;
if (text.size()<=0) {
@ -154,18 +158,18 @@ JKQTMathTextVerbatimNode::LayoutInfo JKQTMathTextVerbatimNode::calcLayout(QPaint
for (int i=0; i<l.lines.size(); i++) {
if (i==0) {
heightSum=fm.ascent();
heightSum=fascent;
} else if (i>0) {
const double deltaLine=qMax(linespacing, descents.last()+lineLeading+fm.ascent());
const double deltaLine=qMax(linespacing, descents.last()+lineLeading+fascent);
heightSum=heightSum+deltaLine;
y=y+deltaLine;
}
widths<<fm.boundingRect(l.lines[i]).width();
widths<<JKQTMathTextGetBoundingRect(f,l.lines[i],painter.device()).width();
l.width=qMax(l.width, widths.last());
heights<<fm.height();
ascents<<fm.ascent();
descents<<fm.descent();
strikeouts<<fm.strikeOutPos();
heights<<JKQTMathTextGetFontHeight(f, painter.device());
ascents<<fascent;
descents<<JKQTMathTextGetFontDescent(f, painter.device());
strikeouts<<JKQTMathTextGetFontStrikoutPos(f, painter.device());
ysFromFirstLine<<y;
}
heightSum+=descents.last();

View File

@ -27,6 +27,7 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -76,10 +77,10 @@ JKQTMathTextVerticalListNode::LayoutInfo JKQTMathTextVerticalListNode::calcLayou
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<nodes.size(); i++) {
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
const double linespacing=fm.lineSpacing()*lineSpacingFactor;
const double fleading=fm.leading();
const double synLeading=fm.lineWidth();
const QFont f=currentEv.getFont(parentMathText);
const double linespacing=JKQTMathTextGetFontLineSpacing(f, painter.device())*lineSpacingFactor;
const double fleading=JKQTMathTextGetFontLeading(f, painter.device());
const double synLeading=JKQTMathTextGetFontLineWidth(f, painter.device());
const double lineLeading=((fabs(fleading)>1e-6)?fleading:synLeading)*lineSpacingFactor;
const JKQTMathTextNodeSize loc=nodes[i]->getSize(painter, currentEv);
@ -145,6 +146,9 @@ JKQTMathTextVerticalListNode::LayoutInfo JKQTMathTextVerticalListNode::calcLayou
}
double JKQTMathTextVerticalListNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment ev) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextVerticalListNode[]::draw()"));
#endif
JKQTMathTextEnvironment currentEv=ev;
doDrawBoxes(painter, x, y, currentEv);
const LayoutInfo l=calcLayout(painter, currentEv);

View File

@ -25,6 +25,9 @@
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtcommon/jkqtpcodestructuring.h"
#include "jkqtcommon/jkqtpstringtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include "jkqtcommon/jkqtpdebuggingtools.h"
#include <cmath>
#include <QFontMetricsF>
#include <QDebug>
@ -114,6 +117,9 @@ size_t JKQTMathTextWhitespaceNode::getWhitespaceCount() const
double JKQTMathTextWhitespaceNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextWhitespaceNode[]::draw()"));
#endif
const JKQTMathTextNodeSize s=getSize(painter, currentEv);
doDrawBoxes(painter, x,y,s);
return x+s.width;
@ -123,11 +129,10 @@ JKQTMathTextNodeSize JKQTMathTextWhitespaceNode::getSizeInternal(QPainter &paint
{
JKQTMathTextNodeSize s;
const double singelWidthPIX=Type2PixelWidth(whitespace.type, currentEv, painter.device());
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
s.width=singelWidthPIX*static_cast<double>(whitespace.count);
s.baselineHeight=0;
s.overallHeight=0;
s.strikeoutPos=fm.strikeOutPos();
s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(currentEv.getFont(parentMathText), painter.device());
return s;
}
@ -179,14 +184,9 @@ QString JKQTMathTextWhitespaceNode::Type2String(Types type)
double JKQTMathTextWhitespaceNode::Type2PixelWidth(Types type, JKQTMathTextEnvironment currentEv, QPaintDevice* pd) const
{
const QFontMetricsF fm(currentEv.getFont(parentMathText), pd);
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
const double em=fm.horizontalAdvance(QChar(0x2003));//currentEv.fontSize;
const double sp=fm.horizontalAdvance(' ');//currentEv.fontSize;
#else
const double em=fm.width(QChar(0x2003));//currentEv.fontSize;
const double sp=fm.width(' ');//currentEv.fontSize;
#endif
const QFont f=currentEv.getFont(parentMathText);
const double sp=JKQTMathTextGetHorAdvance(f, " ", pd);
const double em=JKQTMathTextGetHorAdvance(f, QChar(0x2003), pd);
const double en=em/2.0;
switch (type) {
case WSTNormal: return sp;
@ -255,13 +255,8 @@ double JKQTMathTextEmptyBoxNode::Units2PixelWidth(double value, Units unit, JKQT
{
QFont f=currentEv.getFont(parentMathText);
f.setStyleStrategy(QFont::PreferDefault);
const QFontMetricsF fm(f, pd);
if (unit==EBUem) {
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
const double em=fm.horizontalAdvance(QChar(0x2003));//currentEv.fontSize;
#else
const double em=fm.width(QChar(0x2003));//currentEv.fontSize;
#endif
const double em=JKQTMathTextGetHorAdvance(f, QChar(0x2003), pd);
//qDebug()<<"em="<<em<<"pix";
return value*em;
} else if (unit==EBUex) {
@ -319,6 +314,9 @@ double JKQTMathTextEmptyBoxNode::getHeight() const
double JKQTMathTextEmptyBoxNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextEmptyBoxNode[]::draw()"));
#endif
const auto s=getSize(painter, currentEv);
doDrawBoxes(painter, x,y,s);
return x+s.width;
@ -327,7 +325,6 @@ double JKQTMathTextEmptyBoxNode::draw(QPainter &painter, double x, double y, JKQ
JKQTMathTextNodeSize JKQTMathTextEmptyBoxNode::getSizeInternal(QPainter &painter, JKQTMathTextEnvironment currentEv) const
{
JKQTMathTextNodeSize s;
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
s.width=Units2PixelWidth(width, widthUnit, currentEv, painter.device());
s.overallHeight=Units2PixelWidth(height, heightUnit, currentEv, painter.device());
if (height>0) {
@ -335,7 +332,7 @@ JKQTMathTextNodeSize JKQTMathTextEmptyBoxNode::getSizeInternal(QPainter &painter
} else {
s.baselineHeight=0;
}
s.strikeoutPos=fm.strikeOutPos();
s.strikeoutPos=JKQTMathTextGetFontStrikoutPos(currentEv.getFont(parentMathText), painter.device());
return s;
}
@ -400,6 +397,9 @@ JKQTMathTextNodeSize JKQTMathTextPhantomNode::getSizeInternal(QPainter& painter,
}
double JKQTMathTextPhantomNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTMathTextPhantomNode[]::draw()"));
#endif
const JKQTMathTextNodeSize s=getSize(painter, currentEv);
doDrawBoxes(painter, x, y, s);
return x+s.width;

View File

@ -63,13 +63,15 @@ void JKQTPBaseKey::saveSettings(QSettings& settings, const QString& group) const
void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, const KeySizeDescription& layout)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::drawKey()").arg(objectName()));
#endif
if (!keyStyle().visible) return;
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
const QFontMetricsF kfm(kf, painter.device());
const qreal Xwid=kfm.boundingRect('X').width();
const qreal FHeight=kfm.height();
const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const qreal FHeight=JKQTMathTextGetFontHeight(kf, painter.device());
// determine layouting info and size
QPointF internalOffset(0,0);
@ -130,6 +132,7 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
// draw key table/contents
x0=x0+internalOffset;
QPointF xi=x0;
int ic=0;
for (const auto& c: layout.d->columns) {
xi.setY(x0.y());
int ir=0;
@ -137,12 +140,22 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
const QRectF sampleRect(xi, QSizeF(keyStyle().sampleLineLength*Xwid, keyStyle().sampleHeight*FHeight));
const double rowHeight=layout.d->calcRowHeight(ir, sampleRect.height());
const QRectF textRect(xi+QPointF((keyStyle().sampleLineLength+keyStyle().xSeparation)*Xwid, 0), QSize(r.size.width(), rowHeight));
drawEntrySample(r.id, painter, sampleRect),
getParentMathText()->setFontColor(keyStyle().textColor);
getParentMathText()->setFontPointSize(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
getParentMathText()->setFontSpecial(keyStyle().fontName);
getParentMathText()->parse(r.text);
getParentMathText()->draw(painter, Qt::AlignLeft|Qt::AlignVCenter, textRect, getParent()->isDebugShowTextBoxesEnabled());
drawEntrySample(r.id, painter, sampleRect);
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaatmt(QString("JKQTPBaseKey[%1]::drawKey()::drawEntryText(r=%2,c=%3)::parse").arg(objectName()).arg(ir).arg(ic));
#endif
getParentMathText()->setFontColor(keyStyle().textColor);
getParentMathText()->setFontPointSize(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
getParentMathText()->setFontSpecial(keyStyle().fontName);
getParentMathText()->parse(r.text);
}
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaatmt(QString("JKQTPBaseKey[%1]::drawKey()::drawEntryText(r=%2,c=%3)::parse").arg(objectName()).arg(ir).arg(ic));
#endif
getParentMathText()->draw(painter, Qt::AlignLeft|Qt::AlignVCenter, textRect, getParent()->isDebugShowTextBoxesEnabled());
}
if (drawDebugRects) {
painter.save(); auto __finalpaintinner=JKQTPFinally([&painter]() {painter.restore();});
@ -160,6 +173,7 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
ir++;
}
xi.setX(xi.x()+c.calcColumnWidth(keyStyle().sampleLineLength*Xwid, keyStyle().xSeparation*Xwid)+keyStyle().columnSeparation*Xwid);
ic++;
}
}
@ -167,13 +181,15 @@ void JKQTPBaseKey::drawKey(JKQTPEnhancedPainter &painter, const QRectF &rect, co
JKQTPBaseKey::KeySizeDescription JKQTPBaseKey::getSize(JKQTPEnhancedPainter &painter)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::getSize()").arg(objectName()));
#endif
KeySizeDescription size;
if (!keyStyle().visible) return size;
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
const QFontMetricsF kfm(kf, painter.device());
const qreal Xwid=kfm.boundingRect('X').width();
const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
// calculate layout of the "table" of samples and labels
const KeyLayoutDescription layout=getKeyLayout(painter);
@ -190,9 +206,8 @@ void JKQTPBaseKey::calcLayoutSize(JKQTPEnhancedPainter &painter, KeySizeDescript
{
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
const QFontMetricsF kfm(kf, painter.device());
const qreal Xwid=kfm.boundingRect('X').width();
const qreal FHeight=kfm.height();
const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const qreal FHeight=JKQTMathTextGetFontHeight(kf, painter.device());
layout.requiredSize=extendLayoutSize(QSizeF(layout.d->calcOverallWidth(keyStyle().sampleLineLength*Xwid, keyStyle().xSeparation*Xwid, keyStyle().columnSeparation*Xwid),
layout.d->calcOverallHeight(keyStyle().ySeparation*FHeight, keyStyle().sampleHeight*FHeight)), painter);
@ -207,6 +222,9 @@ void JKQTPBaseKey::calcLayoutSize(JKQTPEnhancedPainter &painter, KeySizeDescript
void JKQTPBaseKey::modifySize(JKQTPEnhancedPainter &painter, KeySizeDescription &currentKeyLayout, QSizeF preliminaryPlotSize)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::modifySize()").arg(objectName()));
#endif
const auto lay=getLayout();
if (lay==JKQTPKeyLayoutMultiColumn || lay==JKQTPKeyLayoutMultiRow) {
std::function<bool(QSizeF, QSizeF)> fCompare=[](const QSizeF& requiredSize, const QSizeF& preliminaryPlotSize) {
@ -264,11 +282,13 @@ void JKQTPBaseKey::setCurrentKeyStyle(const JKQTPKeyStyle &style)
JKQTPBaseKey::KeyLayoutDescription JKQTPBaseKey::getKeyLayout(JKQTPEnhancedPainter &painter)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::getKeyLayout()").arg(objectName()));
#endif
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
QFontMetricsF kfm(kf, painter.device());
//const qreal Xwid=kfm.boundingRect('X').width();
const qreal Fheight=kfm.height();
//const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const qreal Fheight=JKQTMathTextGetFontHeight(kf, painter.device());
//const double frameWidth=qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, getParent()->pt2px(painter, keyStyle().frameWidth*getParent()->getLineWidthMultiplier()));
@ -303,10 +323,12 @@ JKQTPBaseKey::KeyLayoutDescription JKQTPBaseKey::getKeyLayout(JKQTPEnhancedPaint
QSizeF JKQTPBaseKey::extendLayoutSize(QSizeF rawLayoutSize, JKQTPEnhancedPainter& painter, QPointF *offset) const
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::extendLayoutSize()").arg(objectName()));
#endif
QFont kf(JKQTMathTextFontSpecifier::fromFontSpec(keyStyle().fontName).fontName(), keyStyle().fontSize);
kf.setPointSizeF(keyStyle().fontSize*getParent()->getFontSizeMultiplier());
QFontMetricsF kfm(kf, painter.device());
const qreal Xwid=kfm.boundingRect('X').width();
const qreal Xwid=JKQTMathTextGetBoundingRect(kf,"X",painter.device()).width();
const double frameWidth=qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH, getParent()->pt2px(painter, keyStyle().frameWidth*getParent()->getLineWidthMultiplier()));
if (rawLayoutSize.width()>0) rawLayoutSize.setWidth(rawLayoutSize.width()+2.0*keyStyle().xMargin*Xwid+2.0*frameWidth);
@ -531,6 +553,9 @@ QColor JKQTPMainKey::getEntryColor(int item) const
void JKQTPMainKey::drawEntrySample(int item, JKQTPEnhancedPainter &painter, const QRectF &rect)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPBaseKey[%1]::drawEntrySammple(%2)").arg(objectName()).arg(item));
#endif
auto g=getPlotElement(item);
if (g) g->drawKeyMarker(painter, rect);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 34 KiB