/* This file is part of the KDE project Copyright (C) 2003 Ulrich Kuettler Copyright (C) 2006 Alfredo Beaumont Sainz 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 #include #include #include #include #include #include #include #include #include #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 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( 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