You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
892 lines
29 KiB
892 lines
29 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
|
|
Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <qpainter.h>
|
|
#include <qpen.h>
|
|
#include <qfontdatabase.h>
|
|
#include <qapplication.h>
|
|
|
|
#include <kstaticdeleter.h>
|
|
#include <klocale.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kio/netaccess.h>
|
|
#include <kio/job.h>
|
|
#include <kmessagebox.h>
|
|
|
|
#include "fontstyle.h"
|
|
|
|
|
|
KFORMULA_NAMESPACE_BEGIN
|
|
|
|
#include "unicodetable.cc"
|
|
|
|
bool FontStyle::m_installed = false;
|
|
|
|
bool FontStyle::init( ContextStyle* style, bool install )
|
|
{
|
|
if (!m_installed && install)
|
|
installFonts();
|
|
m_symbolTable.init( style->getMathFont() );
|
|
|
|
return true;
|
|
}
|
|
|
|
// Cache the family list from QFontDatabase after fixing it up (no foundry, lowercase)
|
|
class FontList {
|
|
public:
|
|
FontList() {
|
|
QFontDatabase db;
|
|
const QStringList lst = db.families();
|
|
for ( QStringList::const_iterator it = lst.begin(), end = lst.end() ; it != end ; ++it ) {
|
|
const QString name = *it;
|
|
int i = name.find('[');
|
|
QString family = name;
|
|
// Remove foundry
|
|
if ( i > -1 ) {
|
|
const int li = name.findRev(']');
|
|
if (i < li) {
|
|
if (name[i - 1] == ' ')
|
|
i--;
|
|
family = name.left(i);
|
|
}
|
|
}
|
|
m_fontNames.append( family.lower() );
|
|
}
|
|
}
|
|
bool hasFont( const QString& fontName ) const {
|
|
return m_fontNames.find( fontName ) != m_fontNames.end();
|
|
}
|
|
QStringList m_fontNames;
|
|
};
|
|
static FontList* s_fontList = 0;
|
|
static KStaticDeleter<FontList> s_fontList_sd;
|
|
|
|
void FontStyle::testFont( QStringList& missing, const QString& fontName ) {
|
|
if ( !s_fontList )
|
|
s_fontList_sd.setObject( s_fontList, new FontList() );
|
|
if ( !s_fontList->hasFont( fontName ) ) {
|
|
kdWarning(39001) << "Font '" << fontName << "' not found" << endl;
|
|
missing.append( fontName );
|
|
}
|
|
}
|
|
|
|
|
|
QStringList FontStyle::missingFonts( bool install )
|
|
{
|
|
if (!m_installed && install)
|
|
installFonts();
|
|
|
|
QStringList missing = missingFontsInternal();
|
|
return missing;
|
|
}
|
|
|
|
QStringList FontStyle::missingFontsInternal()
|
|
{
|
|
QStringList missing;
|
|
|
|
testFont( missing, "cmex10" );
|
|
testFont( missing, "arev sans");
|
|
|
|
return missing;
|
|
}
|
|
|
|
void FontStyle::installFonts()
|
|
{
|
|
if (m_installed)
|
|
return;
|
|
QStringList missing = missingFontsInternal();
|
|
if (!missing.isEmpty())
|
|
{
|
|
QStringList urlList;
|
|
for (QStringList::iterator it = missing.begin(); it != missing.end(); ++it)
|
|
{
|
|
if ( *it == "arev sans" ) {
|
|
if (!KIO::NetAccess::exists("fonts:/Personal/Arev.ttf", true, NULL))
|
|
urlList.append(locate("data", "kformula/fonts/Arev.ttf"));
|
|
if (!KIO::NetAccess::exists("fonts:/Personal/ArevIt.ttf", true, NULL))
|
|
urlList.append(locate("data", "kformula/fonts/ArevIt.ttf"));
|
|
if (!KIO::NetAccess::exists("fonts:/Personal/ArevBd.ttf", true, NULL))
|
|
urlList.append(locate("data", "kformula/fonts/ArevBd.ttf"));
|
|
if (!KIO::NetAccess::exists("fonts:/Personal/ArevBI.ttf", true, NULL))
|
|
urlList.append(locate("data", "kformula/fonts/ArevBI.ttf"));
|
|
}
|
|
else {
|
|
if (!KIO::NetAccess::exists("fonts:/Personal/" + *it + ".ttf", true, NULL))
|
|
urlList.append(locate("data", "kformula/fonts/" + *it + ".ttf"));
|
|
}
|
|
}
|
|
KIO::copy(urlList, "fonts:/Personal/", false);
|
|
KMessageBox::information(qApp->mainWidget(),
|
|
i18n("Some fonts have been installed to assure that symbols in formulas are properly visualized. You must restart the application in order so that changes take effect"));
|
|
}
|
|
m_installed = true;
|
|
}
|
|
|
|
Artwork* FontStyle::createArtwork( SymbolType type ) const
|
|
{
|
|
return new Artwork( type );
|
|
}
|
|
|
|
// We claim that all chars come from the same font.
|
|
// It's up to the font tables to ensure this.
|
|
const QChar leftRoundBracket[] = {
|
|
0x30, // uppercorner
|
|
0x40, // lowercorner
|
|
0x42 // line
|
|
};
|
|
const QChar leftSquareBracket[] = {
|
|
0x32, // uppercorner
|
|
0x34, // lowercorner
|
|
0x36 // line
|
|
};
|
|
const QChar leftCurlyBracket[] = {
|
|
0x38, // uppercorner
|
|
0x3A, // lowercorner
|
|
0x3E, // line
|
|
0x3C // middle
|
|
};
|
|
|
|
const QChar leftLineBracket[] = {
|
|
0x36, // line
|
|
0x36, // line
|
|
0x36 // line
|
|
};
|
|
const QChar rightLineBracket[] = {
|
|
0x37, // line
|
|
0x37, // line
|
|
0x37 // line
|
|
};
|
|
|
|
const QChar rightRoundBracket[] = {
|
|
0x31, // uppercorner
|
|
0x41, // lowercorner
|
|
0x43 // line
|
|
};
|
|
const QChar rightSquareBracket[] = {
|
|
0x33, // uppercorner
|
|
0x35, // lowercorner
|
|
0x37 // line
|
|
};
|
|
const QChar rightCurlyBracket[] = {
|
|
0x39, // uppercorner
|
|
0x3B, // lowercorner
|
|
0x3E, // line
|
|
0x3D // middle
|
|
};
|
|
|
|
|
|
static const char cmex_LeftSquareBracket = 163;
|
|
static const char cmex_RightSquareBracket = 164;
|
|
static const char cmex_LeftCurlyBracket = 169;
|
|
static const char cmex_RightCurlyBracket = 170;
|
|
static const char cmex_LeftCornerBracket = 173;
|
|
static const char cmex_RightCornerBracket = 174;
|
|
static const char cmex_LeftRoundBracket = 161;
|
|
static const char cmex_RightRoundBracket = 162;
|
|
static const char cmex_SlashBracket = 177;
|
|
static const char cmex_BackSlashBracket = 178;
|
|
//static const char cmex_LeftLineBracket = 0x4b;
|
|
//static const char cmex_RightLineBracket = 0x4b;
|
|
|
|
// use the big symbols here
|
|
static const char cmex_Int = 90;
|
|
static const char cmex_Sum = 88;
|
|
static const char cmex_Prod = 89;
|
|
|
|
|
|
// cmex is a special font with symbols in four sizes.
|
|
static short cmex_nextchar( short ch )
|
|
{
|
|
switch ( ch ) {
|
|
case 161: return 179;
|
|
case 162: return 180;
|
|
case 163: return 104;
|
|
case 164: return 105;
|
|
case 169: return 110;
|
|
case 170: return 111;
|
|
case 165: return 106;
|
|
case 166: return 107;
|
|
case 167: return 108;
|
|
case 168: return 109;
|
|
case 173: return 68;
|
|
case 174: return 69;
|
|
case 177: return 46;
|
|
case 178: return 47;
|
|
|
|
case 179: return 181;
|
|
case 180: return 182;
|
|
case 104: return 183;
|
|
case 105: return 184;
|
|
case 110: return 189;
|
|
case 111: return 190;
|
|
case 106: return 185;
|
|
case 107: return 186;
|
|
case 108: return 187;
|
|
case 109: return 188;
|
|
case 68: return 191;
|
|
case 69: return 192;
|
|
case 46: return 193;
|
|
case 47: return 194;
|
|
|
|
case 181: return 195;
|
|
case 182: return 33;
|
|
case 183: return 34;
|
|
case 184: return 35;
|
|
case 189: return 40;
|
|
case 190: return 41;
|
|
case 185: return 36;
|
|
case 186: return 37;
|
|
case 187: return 38;
|
|
case 188: return 39;
|
|
case 191: return 42;
|
|
case 192: return 43;
|
|
case 193: return 44;
|
|
case 194: return 45;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool Artwork::calcCMDelimiterSize( const ContextStyle& context,
|
|
uchar c,
|
|
luPt fontSize,
|
|
luPt parentSize )
|
|
{
|
|
QFont f( "cmex10" );
|
|
f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
|
|
QFontMetrics fm( f );
|
|
|
|
for ( char i=1; c != 0; ++i ) {
|
|
LuPixelRect bound = fm.boundingRect( c );
|
|
|
|
luPt height = context.ptToLayoutUnitPt( bound.height() );
|
|
if ( height >= parentSize ) {
|
|
luPt width = context.ptToLayoutUnitPt( fm.width( c ) );
|
|
luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
|
|
|
|
cmChar = c;
|
|
|
|
setHeight( height );
|
|
setWidth( width );
|
|
setBaseline( baseline );
|
|
|
|
return true;
|
|
}
|
|
c = cmex_nextchar( c );
|
|
}
|
|
|
|
// Build it up from pieces.
|
|
return false;
|
|
}
|
|
|
|
|
|
void Artwork::calcLargest( const ContextStyle& context,
|
|
uchar c, luPt fontSize )
|
|
{
|
|
QFont f( "cmex10" );
|
|
f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
|
|
QFontMetrics fm( f );
|
|
|
|
cmChar = c;
|
|
for ( ;; ) {
|
|
c = cmex_nextchar( c );
|
|
if ( c == 0 ) {
|
|
break;
|
|
}
|
|
cmChar = c;
|
|
}
|
|
|
|
LuPixelRect bound = fm.boundingRect( cmChar );
|
|
|
|
luPt height = context.ptToLayoutUnitPt( bound.height() );
|
|
luPt width = context.ptToLayoutUnitPt( fm.width( cmChar ) );
|
|
luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
|
|
|
|
setHeight( height );
|
|
setWidth( width );
|
|
setBaseline( baseline );
|
|
}
|
|
|
|
|
|
void Artwork::drawCMDelimiter( QPainter& painter, const ContextStyle& style,
|
|
luPixel x, luPixel y,
|
|
luPt height )
|
|
{
|
|
QFont f( "cmex10" );
|
|
f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );
|
|
|
|
painter.setFont( f );
|
|
painter.drawText( style.layoutUnitToPixelX( x ),
|
|
style.layoutUnitToPixelY( y + getBaseline() ),
|
|
QString( QChar( cmChar ) ) );
|
|
|
|
// Debug
|
|
#if 0
|
|
QFontMetrics fm( f );
|
|
LuPixelRect bound = fm.boundingRect( cmChar );
|
|
painter.setBrush(Qt::NoBrush);
|
|
painter.setPen(Qt::green);
|
|
painter.drawRect( style.layoutUnitToPixelX( x ),
|
|
style.layoutUnitToPixelY( y ),
|
|
fm.width( cmChar ),
|
|
bound.height() );
|
|
#endif
|
|
}
|
|
|
|
|
|
Artwork::Artwork(SymbolType t)
|
|
: baseline( -1 ), type(t)
|
|
{
|
|
}
|
|
|
|
|
|
void Artwork::calcSizes( const ContextStyle& style,
|
|
ContextStyle::TextStyle tstyle,
|
|
double factor,
|
|
luPt parentSize )
|
|
{
|
|
setBaseline( -1 );
|
|
cmChar = -1;
|
|
luPt mySize = style.getAdjustedSize( tstyle, factor );
|
|
switch (getType()) {
|
|
case LeftSquareBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_LeftSquareBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcRoundBracket( style, leftSquareBracket, parentSize, mySize );
|
|
break;
|
|
case RightSquareBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_RightSquareBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcRoundBracket( style, rightSquareBracket, parentSize, mySize );
|
|
break;
|
|
case LeftLineBracket:
|
|
calcRoundBracket( style, leftLineBracket, parentSize, mySize );
|
|
setWidth( getWidth()/2 );
|
|
break;
|
|
case RightLineBracket:
|
|
calcRoundBracket( style, rightLineBracket, parentSize, mySize );
|
|
setWidth( getWidth()/2 );
|
|
break;
|
|
case SlashBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_SlashBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcLargest( style, cmex_SlashBracket, mySize );
|
|
break;
|
|
case BackSlashBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_BackSlashBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcLargest( style, cmex_BackSlashBracket, mySize );
|
|
break;
|
|
case LeftCornerBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_LeftCornerBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcLargest( style, cmex_LeftCornerBracket, mySize );
|
|
break;
|
|
case RightCornerBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_RightCornerBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcLargest( style, cmex_RightCornerBracket, mySize );
|
|
break;
|
|
case LeftRoundBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_LeftRoundBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcRoundBracket( style, leftRoundBracket, parentSize, mySize );
|
|
break;
|
|
case RightRoundBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_RightRoundBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcRoundBracket( style, rightRoundBracket, parentSize, mySize );
|
|
break;
|
|
case EmptyBracket:
|
|
setHeight(parentSize);
|
|
//setWidth(style.getEmptyRectWidth());
|
|
setWidth(0);
|
|
break;
|
|
case LeftCurlyBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_LeftCurlyBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcCurlyBracket( style, leftCurlyBracket, parentSize, mySize );
|
|
break;
|
|
case RightCurlyBracket:
|
|
if ( calcCMDelimiterSize( style, cmex_RightCurlyBracket,
|
|
mySize, parentSize ) ) {
|
|
return;
|
|
}
|
|
calcCurlyBracket( style, rightCurlyBracket, parentSize, mySize );
|
|
break;
|
|
case Integral:
|
|
calcCharSize( style, style.getBracketFont(), mySize, cmex_Int );
|
|
break;
|
|
case Sum:
|
|
calcCharSize( style, style.getBracketFont(), mySize, cmex_Sum );
|
|
break;
|
|
case Product:
|
|
calcCharSize( style, style.getBracketFont(), mySize, cmex_Prod );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Artwork::calcSizes( const ContextStyle& style,
|
|
ContextStyle::TextStyle tstyle,
|
|
double factor )
|
|
{
|
|
luPt mySize = style.getAdjustedSize( tstyle, factor );
|
|
switch (type) {
|
|
case LeftSquareBracket:
|
|
calcCharSize(style, mySize, leftSquareBracketChar);
|
|
break;
|
|
case RightSquareBracket:
|
|
calcCharSize(style, mySize, rightSquareBracketChar);
|
|
break;
|
|
case LeftLineBracket:
|
|
case RightLineBracket:
|
|
calcCharSize(style, mySize, verticalLineChar);
|
|
break;
|
|
case SlashBracket:
|
|
calcCharSize(style, mySize, slashChar);
|
|
break;
|
|
case BackSlashBracket:
|
|
calcCharSize(style, mySize, backSlashChar);
|
|
break;
|
|
case LeftCornerBracket:
|
|
calcCharSize(style, mySize, leftAngleBracketChar);
|
|
break;
|
|
case RightCornerBracket:
|
|
calcCharSize(style, mySize, rightAngleBracketChar);
|
|
break;
|
|
case LeftRoundBracket:
|
|
calcCharSize(style, mySize, leftParenthesisChar);
|
|
break;
|
|
case RightRoundBracket:
|
|
calcCharSize(style, mySize, rightParenthesisChar);
|
|
break;
|
|
case EmptyBracket:
|
|
//calcCharSize(style, mySize, spaceChar);
|
|
setHeight(0);
|
|
//setWidth(style.getEmptyRectWidth());
|
|
setWidth(0);
|
|
break;
|
|
case LeftCurlyBracket:
|
|
calcCharSize(style, mySize, leftCurlyBracketChar);
|
|
break;
|
|
case RightCurlyBracket:
|
|
calcCharSize(style, mySize, rightCurlyBracketChar);
|
|
break;
|
|
case Integral:
|
|
case Sum:
|
|
case Product:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void Artwork::draw(QPainter& painter, const LuPixelRect& /*r*/,
|
|
const ContextStyle& context, ContextStyle::TextStyle tstyle,
|
|
StyleAttributes& style, const LuPixelPoint& parentOrigin)
|
|
{
|
|
luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
|
|
luPixel myX = parentOrigin.x() + getX();
|
|
luPixel myY = parentOrigin.y() + getY();
|
|
/*
|
|
if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
|
|
return;
|
|
*/
|
|
|
|
painter.setPen(context.getDefaultColor());
|
|
|
|
switch (type) {
|
|
case LeftSquareBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, leftSquareBracketChar);
|
|
break;
|
|
case RightSquareBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, rightSquareBracketChar);
|
|
break;
|
|
case LeftCurlyBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, leftCurlyBracketChar);
|
|
break;
|
|
case RightCurlyBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, rightCurlyBracketChar);
|
|
break;
|
|
case LeftLineBracket:
|
|
case RightLineBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, verticalLineChar);
|
|
break;
|
|
case SlashBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, slashChar);
|
|
break;
|
|
case BackSlashBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, backSlashChar);
|
|
break;
|
|
case LeftCornerBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
|
|
break;
|
|
case RightCornerBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
|
|
break;
|
|
case LeftRoundBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, leftParenthesisChar);
|
|
break;
|
|
case RightRoundBracket:
|
|
drawCharacter(painter, context, myX, myY, mySize, rightParenthesisChar);
|
|
break;
|
|
case EmptyBracket:
|
|
break;
|
|
case Integral:
|
|
case Sum:
|
|
case Product:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Artwork::draw(QPainter& painter, const LuPixelRect& ,
|
|
const ContextStyle& context, ContextStyle::TextStyle tstyle,
|
|
StyleAttributes& style, luPt , const LuPixelPoint& origin)
|
|
{
|
|
luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
|
|
luPixel myX = origin.x() + getX();
|
|
luPixel myY = origin.y() + getY();
|
|
/*
|
|
if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
|
|
return;
|
|
*/
|
|
|
|
painter.setPen(context.getDefaultColor());
|
|
|
|
switch (getType()) {
|
|
case LeftSquareBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else {
|
|
drawBigRoundBracket( painter, context, leftSquareBracket, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case RightSquareBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else {
|
|
drawBigRoundBracket( painter, context, rightSquareBracket, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case LeftCurlyBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else {
|
|
drawBigCurlyBracket( painter, context, leftCurlyBracket, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case RightCurlyBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else {
|
|
drawBigCurlyBracket( painter, context, rightCurlyBracket, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case LeftLineBracket: {
|
|
luPixel halfWidth = getWidth()/2;
|
|
drawBigRoundBracket( painter, context, leftLineBracket,
|
|
myX-halfWidth, myY, mySize );
|
|
}
|
|
break;
|
|
case RightLineBracket: {
|
|
luPixel halfWidth = getWidth()/2;
|
|
drawBigRoundBracket( painter, context, rightLineBracket,
|
|
myX-halfWidth, myY, mySize );
|
|
}
|
|
break;
|
|
case SlashBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case BackSlashBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case LeftCornerBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
|
|
break;
|
|
case RightCornerBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
|
|
break;
|
|
case LeftRoundBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else {
|
|
drawBigRoundBracket( painter, context, leftRoundBracket, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case RightRoundBracket:
|
|
if ( cmChar != -1 ) {
|
|
drawCMDelimiter( painter, context, myX, myY, mySize );
|
|
}
|
|
else {
|
|
drawBigRoundBracket( painter, context, rightRoundBracket, myX, myY, mySize );
|
|
}
|
|
break;
|
|
case EmptyBracket:
|
|
break;
|
|
case Integral:
|
|
drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Int);
|
|
break;
|
|
case Sum:
|
|
drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Sum);
|
|
break;
|
|
case Product:
|
|
drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Prod);
|
|
break;
|
|
}
|
|
|
|
// debug
|
|
// painter.setBrush(Qt::NoBrush);
|
|
// painter.setPen(Qt::green);
|
|
// painter.drawRect( context.layoutUnitToPixelX( myX ),
|
|
// context.layoutUnitToPixelY( myY ),
|
|
// context.layoutUnitToPixelX( getWidth() ),
|
|
// context.layoutUnitToPixelY( getHeight() ) );
|
|
}
|
|
|
|
void Artwork::calcCharSize( const ContextStyle& style, luPt height, QChar ch )
|
|
{
|
|
calcCharSize( style, style.getMathFont(), height, ch );
|
|
}
|
|
|
|
|
|
void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
|
|
luPixel x, luPixel y,
|
|
luPt height, QChar ch )
|
|
{
|
|
drawCharacter( painter, style, style.getMathFont(), x, y, height, ch );
|
|
}
|
|
|
|
|
|
void Artwork::calcCharSize( const ContextStyle& style, QFont f,
|
|
luPt height, QChar c )
|
|
{
|
|
f.setPointSizeFloat( style.layoutUnitPtToPt( height ) );
|
|
//f.setPointSize( height );
|
|
QFontMetrics fm(f);
|
|
setWidth( style.ptToLayoutUnitPt( fm.width( c ) ) );
|
|
LuPixelRect bound = fm.boundingRect( c );
|
|
setHeight( style.ptToLayoutUnitPt( bound.height() ) );
|
|
setBaseline( style.ptToLayoutUnitPt( -bound.top() ) );
|
|
}
|
|
|
|
|
|
void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
|
|
QFont f,
|
|
luPixel x, luPixel y, luPt height, uchar c )
|
|
{
|
|
f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );
|
|
|
|
painter.setFont( f );
|
|
painter.drawText( style.layoutUnitToPixelX( x ),
|
|
style.layoutUnitToPixelY( y+getBaseline() ),
|
|
QString( QChar( c ) ) );
|
|
}
|
|
|
|
|
|
void Artwork::calcRoundBracket( const ContextStyle& style, const QChar chars[],
|
|
luPt height, luPt charHeight )
|
|
{
|
|
uchar uppercorner = chars[0];
|
|
uchar lowercorner = chars[1];
|
|
//uchar line = style.symbolTable().character( chars[2] );
|
|
|
|
QFont f = style.getBracketFont();
|
|
f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
|
|
QFontMetrics fm( f );
|
|
LuPtRect upperBound = fm.boundingRect( uppercorner );
|
|
LuPtRect lowerBound = fm.boundingRect( lowercorner );
|
|
//LuPtRect lineBound = fm.boundingRect( line );
|
|
|
|
setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
|
|
luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+lowerBound.height() );
|
|
//luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
|
|
|
|
//setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
|
|
setHeight( QMAX( edgeHeight, height ) );
|
|
}
|
|
|
|
void Artwork::drawBigRoundBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
|
|
luPixel x, luPixel y, luPt charHeight )
|
|
{
|
|
uchar uppercorner = chars[0];
|
|
uchar lowercorner = chars[1];
|
|
uchar line = chars[2];
|
|
|
|
QFont f = style.getBracketFont();
|
|
f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
|
|
p.setFont(f);
|
|
|
|
QFontMetrics fm(f);
|
|
QRect upperBound = fm.boundingRect(uppercorner);
|
|
QRect lowerBound = fm.boundingRect(lowercorner);
|
|
QRect lineBound = fm.boundingRect(line);
|
|
|
|
pixel ptX = style.layoutUnitToPixelX( x );
|
|
pixel ptY = style.layoutUnitToPixelY( y );
|
|
pixel height = style.layoutUnitToPixelY( getHeight() );
|
|
|
|
// p.setPen( Qt::red );
|
|
// //p.drawRect( ptX, ptY, upperBound.width(), upperBound.height() + lowerBound.height() );
|
|
// p.drawRect( ptX, ptY, style.layoutUnitToPixelX( getWidth() ),
|
|
// style.layoutUnitToPixelY( getHeight() ) );
|
|
|
|
// p.setPen( Qt::black );
|
|
p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
|
|
p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
|
|
QString( QChar( lowercorner ) ) );
|
|
|
|
// for printing
|
|
//pt safety = lineBound.height() / 10.0;
|
|
pixel safety = 0;
|
|
|
|
pixel gap = height - upperBound.height() - lowerBound.height();
|
|
pixel lineHeight = lineBound.height() - safety;
|
|
int lineCount = qRound( static_cast<double>( gap ) / lineHeight );
|
|
pixel start = upperBound.height()-lineBound.top() - safety;
|
|
|
|
for (int i = 0; i < lineCount; i++) {
|
|
p.drawText( ptX, ptY+start+i*lineHeight, QString(QChar(line)));
|
|
}
|
|
pixel remaining = gap - lineCount*lineHeight;
|
|
pixel dist = ( lineHeight - remaining ) / 2;
|
|
p.drawText( ptX, ptY+height-upperBound.height()+dist-lineBound.height()-lineBound.top(),
|
|
QString( QChar( line ) ) );
|
|
}
|
|
|
|
void Artwork::calcCurlyBracket( const ContextStyle& style, const QChar chars[],
|
|
luPt height, luPt charHeight )
|
|
{
|
|
uchar uppercorner = chars[0];
|
|
uchar lowercorner = chars[1];
|
|
//uchar line = style.symbolTable().character( chars[2] );
|
|
uchar middle = chars[3];
|
|
|
|
QFont f = style.getBracketFont();
|
|
f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
|
|
QFontMetrics fm( f );
|
|
LuPtRect upperBound = fm.boundingRect( uppercorner );
|
|
LuPtRect lowerBound = fm.boundingRect( lowercorner );
|
|
//LuPtRect lineBound = fm.boundingRect( line );
|
|
LuPtRect middleBound = fm.boundingRect( middle );
|
|
|
|
setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
|
|
luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+
|
|
lowerBound.height()+
|
|
middleBound.height() );
|
|
//luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
|
|
|
|
//setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
|
|
setHeight( QMAX( edgeHeight, height ) );
|
|
}
|
|
|
|
void Artwork::drawBigCurlyBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
|
|
luPixel x, luPixel y, luPt charHeight )
|
|
{
|
|
//QFont f = style.getSymbolFont();
|
|
QFont f = style.getBracketFont();
|
|
f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
|
|
p.setFont(f);
|
|
|
|
uchar uppercorner = chars[0];
|
|
uchar lowercorner = chars[1];
|
|
uchar line = chars[2];
|
|
uchar middle = chars[3];
|
|
|
|
QFontMetrics fm(p.fontMetrics());
|
|
QRect upperBound = fm.boundingRect(uppercorner);
|
|
QRect lowerBound = fm.boundingRect(lowercorner);
|
|
QRect middleBound = fm.boundingRect(middle);
|
|
QRect lineBound = fm.boundingRect(line);
|
|
|
|
pixel ptX = style.layoutUnitToPixelX( x );
|
|
pixel ptY = style.layoutUnitToPixelY( y );
|
|
pixel height = style.layoutUnitToPixelY( getHeight() );
|
|
|
|
//p.setPen(Qt::gray);
|
|
//p.drawRect(x, y, upperBound.width() + offset, height);
|
|
|
|
p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
|
|
p.drawText( ptX, ptY+(height-middleBound.height())/2-middleBound.top(),
|
|
QString( QChar( middle ) ) );
|
|
p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
|
|
QString( QChar( lowercorner ) ) );
|
|
|
|
// for printing
|
|
// If the world was perfect and the urw-symbol font correct
|
|
// this could be 0.
|
|
//lu safety = lineBound.height() / 10;
|
|
pixel safety = 0;
|
|
|
|
pixel lineHeight = lineBound.height() - safety;
|
|
pixel gap = height/2 - upperBound.height() - middleBound.height() / 2;
|
|
|
|
if (gap > 0) {
|
|
QString ch = QString(QChar(line));
|
|
int lineCount = qRound( gap / lineHeight ) + 1;
|
|
|
|
pixel start = (height - middleBound.height()) / 2 + safety;
|
|
for (int i = 0; i < lineCount; i++) {
|
|
p.drawText( ptX, ptY-lineBound.top()+QMAX( start-(i+1)*lineHeight,
|
|
upperBound.width() ),
|
|
ch );
|
|
}
|
|
|
|
start = (height + middleBound.height()) / 2 - safety;
|
|
for (int i = 0; i < lineCount; i++) {
|
|
p.drawText( ptX, ptY-lineBound.top()+QMIN( start+i*lineHeight,
|
|
height-upperBound.width()-lineBound.height() ),
|
|
ch );
|
|
}
|
|
}
|
|
}
|
|
|
|
KFORMULA_NAMESPACE_END
|