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.
koffice/lib/kotext/KoFontDiaPreview.cpp

443 lines
16 KiB

/* This file is part of the KDE project
Copyright (C) 2001, 2002 Montel Laurent <lmontel@mandrakesoft.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 "KoFontDiaPreview.h"
#include "KoGlobal.h"
#include "KoTextFormat.h"
#include <tdelocale.h>
#include <tqfontmetrics.h>
#include <tqrect.h>
#include <tqpainter.h>
#include <tqfont.h>
#include <tqstringlist.h>
#include <tqstring.h>
#include <tqregexp.h>
#include <math.h>
#include "KoFontDiaPreview.moc"
KoFontDiaPreview::KoFontDiaPreview( TQWidget* parent, const char* name , WFlags fl )
: TQFrame( parent, name, fl )
,m_text( i18n( "The quick brown dog jumps over the lazy cat." ) )
,displayText( i18n( "The quick brown dog jumps over the lazy cat." ) )
,m_font( KoGlobal::defaultFont() )
,m_textColor( TQt::black )
,m_backgroundColor( TQt::white )
,m_shadowDistanceX( 0 )
,m_shadowDistanceY( 0 )
,m_shadowColor( TQt::black )
,m_underlining( 0 )
,m_underliningStyle( 0 )
,m_underliningColor( TQt::black )
,m_wordByWord( false )
,m_strikethrough( 0 )
,m_strikethroughStyle( 0 )
,m_capitalisation( 0 )
,m_subSuper( 0 )
,m_offset( 0 )
,m_relativeSize( 1 )
{
setFrameStyle( TQFrame::WinPanel | TQFrame::Plain );
setBackgroundMode( PaletteBase );
setBackgroundColor( TQt::white );
setMinimumSize( 400, 100 );
}
KoFontDiaPreview::~KoFontDiaPreview()
{
}
void KoFontDiaPreview::setText( const TQString &text )
{
m_text = text;
update();
}
void KoFontDiaPreview::setFont( const TQFont &font )
{
m_font = font;
m_fontSize = m_font.pointSize();
update();
}
void KoFontDiaPreview::setFontColor( const TQColor &textColor )
{
m_textColor = textColor;
update();
}
void KoFontDiaPreview::setBackgroundColor( const TQColor &backgroundColor )
{
m_backgroundColor = backgroundColor;
update();
}
void KoFontDiaPreview::setShadow( double sdx, double sdy, TQColor shadowColor )
{
m_shadowDistanceX = sdx;
m_shadowDistanceY = sdy;
m_shadowColor = shadowColor;
update();
}
void KoFontDiaPreview::setUnderlining( int underlining, int underliningStyle, const TQColor underliningColor, bool wordByWord )
{
m_underlining = underlining;
m_underliningStyle = underliningStyle;
m_underliningColor = underliningColor;
m_wordByWord = wordByWord;
update();
}
void KoFontDiaPreview::setWordByWord( bool wordByWord )
{
m_wordByWord = wordByWord;
update();
}
void KoFontDiaPreview::setStrikethrough( int strikethrough, int strikethroughStyle, bool wordByWord )
{
m_strikethrough = strikethrough;
m_strikethroughStyle = strikethroughStyle;
m_wordByWord = wordByWord;
update();
}
void KoFontDiaPreview::setCapitalisation( int capitalisation )
{
m_capitalisation = capitalisation;
update();
}
void KoFontDiaPreview::setSubSuperscript( int subSuper, int offset, double relativeSize )
{
m_subSuper = subSuper;
m_offset = offset;
m_relativeSize = relativeSize;
update();
}
TQString KoFontDiaPreview::formatCapitalisation( const TQString &string )
{
switch ( m_capitalisation )
{
case KoTextFormat::ATT_NONE :
return string;
case KoTextFormat::ATT_UPPER :
return string.upper();
case KoTextFormat::ATT_LOWER :
return string.lower();
case KoTextFormat::ATT_SMALL_CAPS :
return string.upper();
default:
return string;
}
}
void KoFontDiaPreview::drawContents( TQPainter* p )
{
p->save();
// sort out the font to use
//Capitalisation
double capitalisationCoeff;
TQFontMetrics fmCapitalisation( m_font );
switch ( m_capitalisation )
{
case KoTextFormat::ATT_NONE :
capitalisationCoeff = 1.0;
break;
case KoTextFormat::ATT_UPPER :
capitalisationCoeff = 1.0;
break;
case KoTextFormat::ATT_LOWER :
capitalisationCoeff = 1.0;
break;
case KoTextFormat::ATT_SMALL_CAPS :
capitalisationCoeff = ((double)fmCapitalisation.boundingRect("x").height()/(double)fmCapitalisation.boundingRect("X").height());
break;
default:
capitalisationCoeff = 1.0;
break;
}
//Set the display font. m_font is untouched by the modifications of capitalisation
displayFont = m_font;
displayFont.setPointSizeFloat( m_font.pointSize() * capitalisationCoeff );
// format the string in case Small Caps
displayText = formatCapitalisation( m_text );
// draw the stuff
TQFontMetrics fm( displayFont );
TQRect br = fm.boundingRect( contentsRect().x(), contentsRect().y(), contentsRect().width(), contentsRect().height(), TQt::AlignCenter | TQt::WordBreak, displayText );
if ( br.width() > contentsRect().width() || br.height() > contentsRect().height() ) {
displayText = formatCapitalisation( i18n( "Font too large for the preview pane" ) );
displayFont.setPointSizeFloat( 14 * capitalisationCoeff );
}
TQFontMetrics fm1( displayFont );
br = fm1.boundingRect( contentsRect().x(), contentsRect().y(), contentsRect().width(), contentsRect().height(), TQt::AlignCenter | TQt::WordBreak, displayText );
int xorg = tqRound( ( contentsRect().width() - br.width() ) / 2 ) + contentsRect().x() - fm1.leftBearing( displayText.at( 0 ) );
// sub / superscript modifications
int subSuperOffset = 0;
switch ( m_subSuper ) {
case 0: //normal
displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
subSuperOffset = -( m_offset );
break;
case 1: //subscript
displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
subSuperOffset = fm1.height() / 6;
break;
case 2: //superscript
displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
subSuperOffset = 0 - ( fm1.height() / 2 );
break;
default:
displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
subSuperOffset = 0 - m_offset;
break;
}
TQFontMetrics fm2( displayFont );
br = fm2.boundingRect( contentsRect().x(), contentsRect().y(), contentsRect().width(), contentsRect().height(), TQt::AlignCenter | TQt::WordBreak, displayText );
int yorg = tqRound( ( contentsRect().height() - br.height() ) / 2 ) + fm1.ascent() + subSuperOffset;
int sxorg = xorg + int( m_shadowDistanceX );
int syorg = yorg + int( m_shadowDistanceY );
TQStringList textWords = TQStringList::split( " ", displayText );
int x = xorg;
int y = yorg;
int sx = sxorg;
int sy = syorg;
int bx= TQMIN( x, sx );
int xend = bx;
int yUnderline;
int widthUnderline;
int thicknessUnderline;
int yStrikethrough;
int widthStrikethrough;
int thicknessStrikethrough;
p->setFont(displayFont );
p->setPen( m_textColor );
int count = 1;
for ( TQStringList::iterator it = textWords.begin(); it != textWords.end(); ++it ) {
int boffset = 0;
if ( x + fm2.width( (*it) ) > contentsRect().width() ) {
y += fm1.lineSpacing();
sy += fm1.lineSpacing();
xend = x;
x = xorg;
sx = sxorg;
bx= TQMIN( x, sx );
count = 1;
}
TQString textDraw;
if ( (*it) == textWords.last() ) {
textDraw = (*it);
}
else {
textDraw = (*it) + " ";
}
/*background*/
if ( count == 1 ) boffset = TQABS( int( m_shadowDistanceX ) );
else boffset = 0;
if ( bx < xend && (bx + fm2.width( textDraw ) + boffset ) < xend && ( TQMIN( y, sy ) - fm2.ascent() ) < ( TQMIN( yorg, syorg ) - fm2.ascent() + fm2.height() + TQABS( m_shadowDistanceY ) ) ) {
p->fillRect( bx, TQMIN( yorg, syorg ) - fm2.ascent() + fm2.height() + TQABS( int( m_shadowDistanceY ) ), fm2.width( textDraw ) + boffset , fm2.height() + TQABS( int( m_shadowDistanceY ) ) - ( TQMIN( yorg, syorg ) - TQMIN( y, sy ) + fm2.height() + TQABS( int( m_shadowDistanceY ) ) ), m_backgroundColor );
}
else if ( bx < xend && (bx + fm2.width( textDraw ) + boffset ) >= xend && ( TQMIN( y, sy ) - fm2.ascent() ) < ( TQMIN( yorg, syorg ) - fm2.ascent() + fm2.height() + TQABS( m_shadowDistanceY ) ) ) {
p->fillRect( bx, TQMIN( yorg, syorg ) - fm2.ascent() + fm2.height() + TQABS( int( m_shadowDistanceY ) ), xend - bx , fm2.height() + TQABS( int( m_shadowDistanceY ) ) - ( TQMIN( yorg, syorg ) - TQMIN( y, sy ) + fm2.height() + TQABS( int( m_shadowDistanceY ) ) ), m_backgroundColor );
p->fillRect( xend, TQMIN( y, sy ) - fm2.ascent(), fm2.width( textDraw ) + boffset - xend + bx, fm2.height() + TQABS( int( m_shadowDistanceY ) ), m_backgroundColor );
}
else {
p->fillRect( bx, TQMIN( y, sy ) - fm2.ascent(), fm2.width( textDraw ) + boffset , fm2.height() + TQABS( int( m_shadowDistanceY ) ), m_backgroundColor );
}
if ( count == 1 ) boffset = TQABS( int( m_shadowDistanceX ) );
else boffset = 0;
bx += fm2.width( textDraw ) + boffset;//( count == 1 )?0:0;//TQABS( m_shadowDistanceX ):0;
/*shadow*/
if ( m_shadowDistanceX || m_shadowDistanceY )
{
p->save();
p->setPen( m_shadowColor );
p->drawText( sx, sy, textDraw );
p->restore();
}
/*text*/
p->drawText( x, y, textDraw );
/*underline*/
switch ( m_underlining ) {
case KoTextFormat::U_NONE:
break;
case KoTextFormat::U_SIMPLE:
yUnderline = y + fm2.descent();
( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
thicknessUnderline = 1;
drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
break;
case KoTextFormat::U_DOUBLE:
yUnderline = y + fm2.descent();
( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
thicknessUnderline = 1;
drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
yUnderline = y + tqRound( fm2.descent() / 2 );
drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
break;
case KoTextFormat::U_SIMPLE_BOLD:
yUnderline = y + fm2.descent();
( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
thicknessUnderline = tqRound( displayFont.pointSize() / 10 ) + 1;
drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
break;
case KoTextFormat::U_WAVE:
yUnderline = y + fm2.descent();
( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
thicknessUnderline = 1;
drawUnderlineWave( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
break;
default:
break;
}
/*Strikethrough*/
switch ( m_strikethrough ) {
case KoTextFormat::S_NONE:
break;
case KoTextFormat::S_SIMPLE:
yStrikethrough = y - tqRound( fm2.ascent() / 3 );
( m_wordByWord )? widthStrikethrough = fm2.width( (*it) ): widthStrikethrough = fm2.width( textDraw );
thicknessStrikethrough = 1;
drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
break;
case KoTextFormat::S_DOUBLE:
yStrikethrough = y - tqRound( fm2.ascent() / 4 );
( m_wordByWord )? widthStrikethrough = fm2.width( (*it) ): widthStrikethrough = fm2.width( textDraw );
thicknessStrikethrough = 1;
drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
yStrikethrough = y - 2 * tqRound( fm2.ascent() / 4 );
drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
break;
case KoTextFormat::S_SIMPLE_BOLD:
yStrikethrough = y - tqRound( fm2.ascent() / 3 );
( m_wordByWord )? widthStrikethrough = fm2.width( (*it) ): widthStrikethrough = fm2.width( textDraw );
thicknessStrikethrough = tqRound( displayFont.pointSize() / 10 ) + 1;
drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
break;
default:
break;
}
x += fm2.width( textDraw );
sx += fm2.width( textDraw );
count++;
}
p->restore();
}
void KoFontDiaPreview::drawUnderline( int x, int y, int width, int thickness, TQColor & color, TQPainter *p )
{
p->save();
switch ( m_underliningStyle ) {
case KoTextFormat::U_SOLID:
p->setPen( TQPen( color, thickness, TQt::SolidLine ) );
break;
case KoTextFormat::U_DASH:
p->setPen( TQPen( color, thickness, TQt::DashLine ) );
break;
case KoTextFormat::U_DOT:
p->setPen( TQPen( color, thickness, TQt::DotLine ) );
break;
case KoTextFormat::U_DASH_DOT:
p->setPen( TQPen( color, thickness, TQt::DashDotLine ) );
break;
case KoTextFormat::U_DASH_DOT_DOT:
p->setPen( TQPen( color, thickness, TQt::DashDotDotLine ) );
break;
default:
p->setPen( TQPen( color, thickness, TQt::SolidLine ) );
}
p->drawLine( x, y, x+ width, y );
p->restore();
}
void KoFontDiaPreview::drawUnderlineWave( int x, int y, int width, int thickness, TQColor & color, TQPainter *p )
{
p->save();
int offset = 2 * thickness;
TQPen pen(color, thickness, TQt::SolidLine);
pen.setCapStyle(TQt::RoundCap);
p->setPen(pen);
double anc=acos(1.0-2*(static_cast<double>(offset-(x)%offset)/static_cast<double>(offset)))/3.1415*180;
int pos=1;
//set starting position
if(2*((x/offset)/2)==x/offset)
pos*=-1;
//draw first part of wave
p->drawArc( (x/offset)*offset, y, offset, offset, 0, -tqRound(pos*anc*16) );
//now the main part
int zigzag_x = (x/offset+1)*offset;
for ( ; zigzag_x + offset <= width+x; zigzag_x += offset)
{
p->drawArc( zigzag_x, y, offset, offset, 0, pos*180*16 );
pos*=-1;
}
//and here we finish
anc=acos(1.0-2*(static_cast<double>((x+width)%offset)/static_cast<double>(offset)))/3.1415*180;
p->drawArc( zigzag_x, y, offset, offset, 180*16, -tqRound(pos*anc*16) );
p->restore();
}
void KoFontDiaPreview::drawStrikethrough( int x, int y, int width, int thickness, TQPainter *p )
{
p->save();
switch ( m_strikethroughStyle ) {
case KoTextFormat::S_SOLID:
p->setPen( TQPen( TQt::black, thickness, TQt::SolidLine ) );
break;
case KoTextFormat::S_DASH:
p->setPen( TQPen( TQt::black, thickness, TQt::DashLine ) );
break;
case KoTextFormat::S_DOT:
p->setPen( TQPen( TQt::black, thickness, TQt::DotLine ) );
break;
case KoTextFormat::S_DASH_DOT:
p->setPen( TQPen( TQt::black, thickness, TQt::DashDotLine ) );
break;
case KoTextFormat::S_DASH_DOT_DOT:
p->setPen( TQPen( TQt::black, thickness, TQt::DashDotDotLine ) );
break;
default:
p->setPen( TQPen( TQt::black, thickness, TQt::SolidLine ) );
}
p->drawLine( x, y, x+ width, y );
p->restore();
}