mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-11-15 18:15:52 +08:00
440 lines
13 KiB
C++
440 lines
13 KiB
C++
/*
|
|
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
|
|
|
|
|
|
|
|
This software is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
|
the Free Software Foundation, either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License (LGPL) for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
|
|
#include "jkqtmathtext/nodes/jkqtmathtextwhitespacenode.h"
|
|
#include "jkqtmathtext/jkqtmathtexttools.h"
|
|
#include "jkqtmathtext/nodes/jkqtmathtextnode.h"
|
|
#include "jkqtmathtext/jkqtmathtext.h"
|
|
#include "jkqtcommon/jkqtpcodestructuring.h"
|
|
#include "jkqtcommon/jkqtpstringtools.h"
|
|
#include <cmath>
|
|
#include <QFontMetricsF>
|
|
#include <QDebug>
|
|
#include <QFontDatabase>
|
|
#include <QFontInfo>
|
|
#include <QApplication>
|
|
#include <QFont>
|
|
|
|
|
|
|
|
|
|
JKQTMathTextWhitespaceNode::JKQTMathTextWhitespaceNode(Types type, JKQTMathText *_parent):
|
|
JKQTMathTextWhitespaceNode(type, 1, _parent)
|
|
{
|
|
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::JKQTMathTextWhitespaceNode(JKQTMathText *_parent):
|
|
JKQTMathTextWhitespaceNode(WSTNormal, 1, _parent)
|
|
{
|
|
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::JKQTMathTextWhitespaceNode(const QString &_type, JKQTMathText *parent):
|
|
JKQTMathTextWhitespaceNode(parent)
|
|
{
|
|
fillSupportedInstructions();
|
|
whitespace=supportedInstructions[_type];
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::JKQTMathTextWhitespaceNode(const QString &_type, size_t count, JKQTMathText *parent):
|
|
JKQTMathTextWhitespaceNode(parent)
|
|
{
|
|
fillSupportedInstructions();
|
|
whitespace=supportedInstructions[_type];
|
|
whitespace.count=whitespace.count*count;
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::JKQTMathTextWhitespaceNode(Types type, size_t count, JKQTMathText *parent):
|
|
JKQTMathTextNode(parent),
|
|
whitespace(type, count)
|
|
{
|
|
fillSupportedInstructions();
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::~JKQTMathTextWhitespaceNode() {
|
|
|
|
}
|
|
|
|
QString JKQTMathTextWhitespaceNode::getTypeName() const
|
|
{
|
|
return QLatin1String("JKQTMathTextWhitespaceNode(")+Type2String(whitespace.type)+", count="+QString::number(whitespace.count)+")";
|
|
}
|
|
|
|
bool JKQTMathTextWhitespaceNode::toHtml(QString &html, JKQTMathTextEnvironment /*currentEv*/, JKQTMathTextEnvironment /*defaultEv*/) const {
|
|
for (size_t i=0; i<whitespace.count; i++) {
|
|
html=html+Type2HTML(whitespace.type);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::WhitespaceProps::WhitespaceProps(JKQTMathTextWhitespaceNode::Types _type, size_t _count):
|
|
type(_type), count(_count)
|
|
{
|
|
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::WhitespaceProps::WhitespaceProps(const WhitespaceProps &other):
|
|
type(other.type), count(other.count)
|
|
{
|
|
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::WhitespaceProps& JKQTMathTextWhitespaceNode::WhitespaceProps::operator=(const WhitespaceProps &other)
|
|
{
|
|
type=other.type;
|
|
count=other.count;
|
|
return *this;
|
|
}
|
|
|
|
JKQTMathTextWhitespaceNode::Types JKQTMathTextWhitespaceNode::getWhitespaceType() const
|
|
{
|
|
return whitespace.type;
|
|
}
|
|
|
|
size_t JKQTMathTextWhitespaceNode::getWhitespaceCount() const
|
|
{
|
|
return whitespace.count;
|
|
}
|
|
|
|
double JKQTMathTextWhitespaceNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
|
|
{
|
|
const JKQTMathTextNodeSize s=getSize(painter, currentEv);
|
|
doDrawBoxes(painter, x,y,s);
|
|
return x+s.width;
|
|
}
|
|
|
|
JKQTMathTextNodeSize JKQTMathTextWhitespaceNode::getSizeInternal(QPainter &painter, JKQTMathTextEnvironment currentEv) const
|
|
{
|
|
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();
|
|
return s;
|
|
}
|
|
|
|
QHash<QString, JKQTMathTextWhitespaceNode::WhitespaceProps> JKQTMathTextWhitespaceNode::supportedInstructions;
|
|
|
|
void JKQTMathTextWhitespaceNode::fillSupportedInstructions()
|
|
{
|
|
static std::mutex sMutex;
|
|
std::lock_guard<std::mutex> lock(sMutex);
|
|
if (supportedInstructions.size()==0) {
|
|
supportedInstructions[" "]=WhitespaceProps(WSTthicker, 1);
|
|
supportedInstructions["nbsp"]=WhitespaceProps(WSTNonbreaking, 1);
|
|
supportedInstructions["enspace"]=WhitespaceProps(WST1en, 1);
|
|
supportedInstructions["enskip"]=WhitespaceProps(WST1en, 1);
|
|
supportedInstructions["quad"]=WhitespaceProps(WSTQuad, 1);
|
|
supportedInstructions["emspace"]=WhitespaceProps(WSTQuad, 1);
|
|
supportedInstructions["qquad"]=WhitespaceProps(WSTQuad, 2);
|
|
supportedInstructions[","]=WhitespaceProps(WSTthin, 1);
|
|
supportedInstructions["thinspace"]=WhitespaceProps(WSTthin, 1);
|
|
supportedInstructions[":"]=WhitespaceProps(WSTmedium, 1);
|
|
supportedInstructions["medspace"]=WhitespaceProps(WSTmedium, 1);
|
|
supportedInstructions[";"]=WhitespaceProps(WSTthick, 1);
|
|
supportedInstructions["thickspace"]=WhitespaceProps(WSTthick, 1);
|
|
supportedInstructions["!"]=WhitespaceProps(WSTnegthin, 1);
|
|
supportedInstructions["negthinspace"]=WhitespaceProps(WSTnegthin, 1);
|
|
supportedInstructions["negmedspace"]=WhitespaceProps(WSTnegmedium, 1);
|
|
supportedInstructions["negthickspace"]=WhitespaceProps(WSTnegthick, 1);
|
|
}
|
|
|
|
}
|
|
|
|
QString JKQTMathTextWhitespaceNode::Type2String(Types type)
|
|
{
|
|
switch (type) {
|
|
case WSTNormal: return "WSTNormal";
|
|
case WSTNonbreaking: return "WSTNonbreaking";
|
|
case WST1en: return "WST1en";
|
|
case WST1em: return "WST1em";
|
|
case WSThair: return "WSThair";
|
|
case WSTthin: return "WSTthin";
|
|
case WSTnegthin: return "WSTnegthin";
|
|
case WSTmedium: return "WSTmedium";
|
|
case WSTnegmedium: return "WSTnegmedium";
|
|
case WSTthick: return "WSTthick";
|
|
case WSTnegthick: return "WSTnegthick";
|
|
case WSTthicker: return "WSTthicker";
|
|
}
|
|
return "???";
|
|
}
|
|
|
|
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 double en=em/2.0;
|
|
switch (type) {
|
|
case WSTNormal: return sp;
|
|
case WSTNonbreaking: return sp;
|
|
case WST1en: return en;
|
|
case WST1em: return em;
|
|
case WSThair: return em/12.0;
|
|
case WSTthin: return em/6.0;
|
|
case WSTnegthin: return -em/6.0;
|
|
case WSTmedium: return em*2.0/9.0;
|
|
case WSTnegmedium: return -em*2.0/9.0;
|
|
case WSTthick: return em*5.0/18.0;
|
|
case WSTnegthick: return -em*5.0/18.0;
|
|
case WSTthicker: return em/3.0;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
bool JKQTMathTextWhitespaceNode::supportsInstructionName(const QString &instruction)
|
|
{
|
|
fillSupportedInstructions();
|
|
return supportedInstructions.contains(instruction);
|
|
}
|
|
|
|
|
|
QString JKQTMathTextWhitespaceNode::Type2HTML(Types type)
|
|
{
|
|
switch (type) {
|
|
case WSTNonbreaking: return " ";
|
|
case WST1en: return " ";
|
|
case WST1em: return " ";
|
|
case WSThair: return "&hairsp";
|
|
case WSTthin: return " ";
|
|
case WSTnegthin: return "";
|
|
case WSTmedium: return " ";
|
|
case WSTnegmedium: return "";
|
|
case WSTthick: return " ";
|
|
case WSTnegthick: return "";
|
|
case WSTthicker: return "  ";
|
|
case WSTNormal:
|
|
default:
|
|
return " ";
|
|
}
|
|
return " ";
|
|
}
|
|
|
|
|
|
QString JKQTMathTextEmptyBoxNode::Units2String(Units type)
|
|
{
|
|
switch(type) {
|
|
case EBUem: return "em";
|
|
case EBUex: return "ex";
|
|
}
|
|
return "?";
|
|
}
|
|
|
|
JKQTMathTextEmptyBoxNode::Units JKQTMathTextEmptyBoxNode::String2Units(QString type)
|
|
{
|
|
type=type.toLower().trimmed();
|
|
if (type=="ex") return EBUex;
|
|
if (type=="em") return EBUem;
|
|
return EBUem;
|
|
}
|
|
|
|
double JKQTMathTextEmptyBoxNode::Units2PixelWidth(double value, Units unit, JKQTMathTextEnvironment currentEv, QPaintDevice *pd) const
|
|
{
|
|
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
|
|
//qDebug()<<"em="<<em<<"pix";
|
|
return value*em;
|
|
} else if (unit==EBUex) {
|
|
const double ex=JKQTMathTextGetTightBoundingRect(f, "x", pd).height();
|
|
//qDebug()<<"ex="<<ex<<"pix";
|
|
return value*ex;
|
|
} else {
|
|
//qDebug()<<"JKQTMathTextEmptyBoxNode::Units2PixelWidth(): UNKOWN UNIT";
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
JKQTMathTextEmptyBoxNode::JKQTMathTextEmptyBoxNode(JKQTMathText *parent, double width_, Units widthUnit_, double height_, Units heightUnit_):
|
|
JKQTMathTextNode(parent),
|
|
width(width_), widthUnit(widthUnit_),
|
|
height(height_),heightUnit(heightUnit_)
|
|
{
|
|
|
|
}
|
|
|
|
JKQTMathTextEmptyBoxNode::~JKQTMathTextEmptyBoxNode()
|
|
{
|
|
|
|
}
|
|
|
|
QString JKQTMathTextEmptyBoxNode::getTypeName() const
|
|
{
|
|
return QString("JKQTMathTextEmptyBoxNode(%1%2 x %3%4)").arg(getWidth()).arg(JKQTMathTextEmptyBoxNode::Units2String(getWidthUnit())).arg(getHeight()).arg(JKQTMathTextEmptyBoxNode::Units2String(getHeightUnit()));
|
|
}
|
|
|
|
bool JKQTMathTextEmptyBoxNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
JKQTMathTextEmptyBoxNode::Units JKQTMathTextEmptyBoxNode::getWidthUnit() const
|
|
{
|
|
return widthUnit;
|
|
}
|
|
|
|
double JKQTMathTextEmptyBoxNode::getWidth() const
|
|
{
|
|
return width;
|
|
}
|
|
|
|
JKQTMathTextEmptyBoxNode::Units JKQTMathTextEmptyBoxNode::getHeightUnit() const
|
|
{
|
|
return heightUnit;
|
|
}
|
|
|
|
double JKQTMathTextEmptyBoxNode::getHeight() const
|
|
{
|
|
return height;
|
|
}
|
|
|
|
double JKQTMathTextEmptyBoxNode::draw(QPainter &painter, double x, double y, JKQTMathTextEnvironment currentEv) const
|
|
{
|
|
const auto s=getSize(painter, currentEv);
|
|
doDrawBoxes(painter, x,y,s);
|
|
return x+s.width;
|
|
}
|
|
|
|
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) {
|
|
s.baselineHeight=s.overallHeight;
|
|
} else {
|
|
s.baselineHeight=0;
|
|
}
|
|
s.strikeoutPos=fm.strikeOutPos();
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QString JKQTMathTextPhantomNode::Mode2Instruction(Mode mode)
|
|
{
|
|
switch(mode) {
|
|
case FMwidthAndHeight: return "phantom";
|
|
case FMwidth: return "hphantom";
|
|
case FMheight: return "vphantom";
|
|
}
|
|
|
|
return "phantom";
|
|
}
|
|
|
|
JKQTMathTextPhantomNode::JKQTMathTextPhantomNode(JKQTMathText *parent, const QString &mode, JKQTMathTextNode *child):
|
|
JKQTMathTextInstruction1Node(parent, mode, child)
|
|
{
|
|
fillInstructions();
|
|
}
|
|
|
|
JKQTMathTextPhantomNode::JKQTMathTextPhantomNode(JKQTMathText* _parent, Mode mode, JKQTMathTextNode* child):
|
|
JKQTMathTextInstruction1Node(_parent, Mode2Instruction(mode), child)
|
|
{
|
|
fillInstructions();
|
|
}
|
|
|
|
JKQTMathTextPhantomNode::~JKQTMathTextPhantomNode() {
|
|
}
|
|
|
|
|
|
QString JKQTMathTextPhantomNode::getTypeName() const
|
|
{
|
|
return QLatin1String("JKQTMathTextPhantomNode(")+instructionName+")";
|
|
}
|
|
|
|
JKQTMathTextNodeSize JKQTMathTextPhantomNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv) const {
|
|
fillInstructions();
|
|
JKQTMathTextNodeSize s=getChild()->getSize(painter, currentEv);
|
|
|
|
switch(instructions[getInstructionName()]) {
|
|
case FMwidth:
|
|
s.overallHeight=0;
|
|
s.baselineHeight=0;
|
|
s.strikeoutPos=0;
|
|
break;
|
|
case FMwidthAndHeight:
|
|
break;
|
|
case FMheight:
|
|
s.width=0;
|
|
break;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
double JKQTMathTextPhantomNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv) const {
|
|
const JKQTMathTextNodeSize s=getSize(painter, currentEv);
|
|
doDrawBoxes(painter, x, y, s);
|
|
return x+s.width;
|
|
}
|
|
|
|
bool JKQTMathTextPhantomNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) const {
|
|
JKQTMathTextEnvironment ev=currentEv;
|
|
fillInstructions();
|
|
return " ";
|
|
}
|
|
|
|
bool JKQTMathTextPhantomNode::supportsInstructionName(const QString &instructionName)
|
|
{
|
|
fillInstructions();
|
|
return instructions.contains(instructionName);
|
|
}
|
|
|
|
QHash<QString, JKQTMathTextPhantomNode::Mode> JKQTMathTextPhantomNode::instructions;
|
|
|
|
void JKQTMathTextPhantomNode::fillInstructions()
|
|
{
|
|
static std::mutex sMutex;
|
|
std::lock_guard<std::mutex> lock(sMutex);
|
|
if (instructions.size()>0) return;
|
|
instructions["phantom"] = FMwidthAndHeight;
|
|
instructions["hphantom"] = FMwidth;
|
|
instructions["vphantom"] = FMheight;
|
|
}
|
|
|