lib

KoFontDiaPreview.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001, 2002 Montel Laurent <lmontel@mandrakesoft.com>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "KoFontDiaPreview.h"
21#include "KoGlobal.h"
22#include "KoTextFormat.h"
23
24#include <tdelocale.h>
25
26#include <tqfontmetrics.h>
27#include <tqrect.h>
28#include <tqpainter.h>
29#include <tqfont.h>
30#include <tqstringlist.h>
31#include <tqstring.h>
32#include <tqregexp.h>
33
34#include <math.h>
35
36#include "KoFontDiaPreview.moc"
37
38KoFontDiaPreview::KoFontDiaPreview( TQWidget* parent, const char* name , WFlags fl )
39 : TQFrame( parent, name, fl )
40 ,m_text( i18n( "The quick brown dog jumps over the lazy cat." ) )
41 ,displayText( i18n( "The quick brown dog jumps over the lazy cat." ) )
42 ,m_font( KoGlobal::defaultFont() )
43 ,m_textColor( TQt::black )
44 ,m_backgroundColor( TQt::white )
45 ,m_shadowDistanceX( 0 )
46 ,m_shadowDistanceY( 0 )
47 ,m_shadowColor( TQt::black )
48 ,m_underlining( 0 )
49 ,m_underliningStyle( 0 )
50 ,m_underliningColor( TQt::black )
51 ,m_wordByWord( false )
52 ,m_strikethrough( 0 )
53 ,m_strikethroughStyle( 0 )
54 ,m_capitalisation( 0 )
55 ,m_subSuper( 0 )
56 ,m_offset( 0 )
57 ,m_relativeSize( 1 )
58
59{
60 setFrameStyle( TQFrame::WinPanel | TQFrame::Plain );
61 setBackgroundMode( PaletteBase );
62 setBackgroundColor( TQt::white );
63 setMinimumSize( 400, 100 );
64}
65
66KoFontDiaPreview::~KoFontDiaPreview()
67{
68}
69
70void KoFontDiaPreview::setText( const TQString &text )
71{
72 m_text = text;
73 update();
74}
75
76void KoFontDiaPreview::setFont( const TQFont &font )
77{
78 m_font = font;
79 m_fontSize = m_font.pointSize();
80 update();
81}
82
83void KoFontDiaPreview::setFontColor( const TQColor &textColor )
84{
85 m_textColor = textColor;
86 update();
87}
88
89void KoFontDiaPreview::setBackgroundColor( const TQColor &backgroundColor )
90{
91 m_backgroundColor = backgroundColor;
92 update();
93}
94
95void KoFontDiaPreview::setShadow( double sdx, double sdy, TQColor shadowColor )
96{
97 m_shadowDistanceX = sdx;
98 m_shadowDistanceY = sdy;
99 m_shadowColor = shadowColor;
100 update();
101}
102
103void KoFontDiaPreview::setUnderlining( int underlining, int underliningStyle, const TQColor underliningColor, bool wordByWord )
104{
105 m_underlining = underlining;
106 m_underliningStyle = underliningStyle;
107 m_underliningColor = underliningColor;
108 m_wordByWord = wordByWord;
109 update();
110}
111
112void KoFontDiaPreview::setWordByWord( bool wordByWord )
113{
114 m_wordByWord = wordByWord;
115 update();
116}
117
118void KoFontDiaPreview::setStrikethrough( int strikethrough, int strikethroughStyle, bool wordByWord )
119{
120 m_strikethrough = strikethrough;
121 m_strikethroughStyle = strikethroughStyle;
122 m_wordByWord = wordByWord;
123 update();
124}
125
126void KoFontDiaPreview::setCapitalisation( int capitalisation )
127{
128 m_capitalisation = capitalisation;
129 update();
130}
131
132void KoFontDiaPreview::setSubSuperscript( int subSuper, int offset, double relativeSize )
133{
134 m_subSuper = subSuper;
135 m_offset = offset;
136 m_relativeSize = relativeSize;
137 update();
138}
139
140TQString KoFontDiaPreview::formatCapitalisation( const TQString &string )
141{
142 switch ( m_capitalisation )
143 {
144 case KoTextFormat::ATT_NONE :
145 return string;
146 case KoTextFormat::ATT_UPPER :
147 return string.upper();
148 case KoTextFormat::ATT_LOWER :
149 return string.lower();
150 case KoTextFormat::ATT_SMALL_CAPS :
151 return string.upper();
152 default:
153 return string;
154 }
155}
156
157void KoFontDiaPreview::drawContents( TQPainter* p )
158{
159 p->save();
160
161 // sort out the font to use
162
163 //Capitalisation
164 double capitalisationCoeff;
165 TQFontMetrics fmCapitalisation( m_font );
166
167 switch ( m_capitalisation )
168 {
169 case KoTextFormat::ATT_NONE :
170 capitalisationCoeff = 1.0;
171 break;
172 case KoTextFormat::ATT_UPPER :
173 capitalisationCoeff = 1.0;
174 break;
175 case KoTextFormat::ATT_LOWER :
176 capitalisationCoeff = 1.0;
177 break;
178 case KoTextFormat::ATT_SMALL_CAPS :
179 capitalisationCoeff = ((double)fmCapitalisation.boundingRect("x").height()/(double)fmCapitalisation.boundingRect("X").height());
180 break;
181 default:
182 capitalisationCoeff = 1.0;
183 break;
184 }
185 //Set the display font. m_font is untouched by the modifications of capitalisation
186 displayFont = m_font;
187 displayFont.setPointSizeFloat( m_font.pointSize() * capitalisationCoeff );
188
189// format the string in case Small Caps
190 displayText = formatCapitalisation( m_text );
191
192// draw the stuff
193 TQFontMetrics fm( displayFont );
194 TQRect br = fm.boundingRect( contentsRect().x(), contentsRect().y(), contentsRect().width(), contentsRect().height(), TQt::AlignCenter | TQt::WordBreak, displayText );
195
196 if ( br.width() > contentsRect().width() || br.height() > contentsRect().height() ) {
197 displayText = formatCapitalisation( i18n( "Font too large for the preview pane" ) );
198 displayFont.setPointSizeFloat( 14 * capitalisationCoeff );
199 }
200
201 TQFontMetrics fm1( displayFont );
202 br = fm1.boundingRect( contentsRect().x(), contentsRect().y(), contentsRect().width(), contentsRect().height(), TQt::AlignCenter | TQt::WordBreak, displayText );
203
204 int xorg = tqRound( ( contentsRect().width() - br.width() ) / 2 ) + contentsRect().x() - fm1.leftBearing( displayText.at( 0 ) );
205
206 // sub / superscript modifications
207 int subSuperOffset = 0;
208 switch ( m_subSuper ) {
209 case 0: //normal
210 displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
211 subSuperOffset = -( m_offset );
212 break;
213 case 1: //subscript
214 displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
215 subSuperOffset = fm1.height() / 6;
216 break;
217 case 2: //superscript
218 displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
219 subSuperOffset = 0 - ( fm1.height() / 2 );
220 break;
221 default:
222 displayFont.setPointSizeFloat( displayFont.pointSize() * m_relativeSize );
223 subSuperOffset = 0 - m_offset;
224 break;
225 }
226
227 TQFontMetrics fm2( displayFont );
228 br = fm2.boundingRect( contentsRect().x(), contentsRect().y(), contentsRect().width(), contentsRect().height(), TQt::AlignCenter | TQt::WordBreak, displayText );
229 int yorg = tqRound( ( contentsRect().height() - br.height() ) / 2 ) + fm1.ascent() + subSuperOffset;
230 int sxorg = xorg + int( m_shadowDistanceX );
231 int syorg = yorg + int( m_shadowDistanceY );
232 TQStringList textWords = TQStringList::split( " ", displayText );
233 int x = xorg;
234 int y = yorg;
235 int sx = sxorg;
236 int sy = syorg;
237 int bx= TQMIN( x, sx );
238 int xend = bx;
239 int yUnderline;
240 int widthUnderline;
241 int thicknessUnderline;
242 int yStrikethrough;
243 int widthStrikethrough;
244 int thicknessStrikethrough;
245
246 p->setFont(displayFont );
247 p->setPen( m_textColor );
248 int count = 1;
249
250 for ( TQStringList::iterator it = textWords.begin(); it != textWords.end(); ++it ) {
251 int boffset = 0;
252 if ( x + fm2.width( (*it) ) > contentsRect().width() ) {
253 y += fm1.lineSpacing();
254 sy += fm1.lineSpacing();
255 xend = x;
256 x = xorg;
257 sx = sxorg;
258 bx= TQMIN( x, sx );
259 count = 1;
260 }
261 TQString textDraw;
262 if ( (*it) == textWords.last() ) {
263 textDraw = (*it);
264 }
265 else {
266 textDraw = (*it) + " ";
267 }
268/*background*/
269 if ( count == 1 ) boffset = TQABS( int( m_shadowDistanceX ) );
270 else boffset = 0;
271
272 if ( bx < xend && (bx + fm2.width( textDraw ) + boffset ) < xend && ( TQMIN( y, sy ) - fm2.ascent() ) < ( TQMIN( yorg, syorg ) - fm2.ascent() + fm2.height() + TQABS( m_shadowDistanceY ) ) ) {
273 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 );
274 }
275 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 ) ) ) {
276 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 );
277 p->fillRect( xend, TQMIN( y, sy ) - fm2.ascent(), fm2.width( textDraw ) + boffset - xend + bx, fm2.height() + TQABS( int( m_shadowDistanceY ) ), m_backgroundColor );
278 }
279 else {
280 p->fillRect( bx, TQMIN( y, sy ) - fm2.ascent(), fm2.width( textDraw ) + boffset , fm2.height() + TQABS( int( m_shadowDistanceY ) ), m_backgroundColor );
281 }
282
283 if ( count == 1 ) boffset = TQABS( int( m_shadowDistanceX ) );
284 else boffset = 0;
285 bx += fm2.width( textDraw ) + boffset;//( count == 1 )?0:0;//TQABS( m_shadowDistanceX ):0;
286/*shadow*/
287 if ( m_shadowDistanceX || m_shadowDistanceY )
288 {
289 p->save();
290 p->setPen( m_shadowColor );
291 p->drawText( sx, sy, textDraw );
292 p->restore();
293 }
294/*text*/
295 p->drawText( x, y, textDraw );
296/*underline*/
297 switch ( m_underlining ) {
298 case KoTextFormat::U_NONE:
299 break;
300 case KoTextFormat::U_SIMPLE:
301 yUnderline = y + fm2.descent();
302 ( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
303 thicknessUnderline = 1;
304 drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
305 break;
306 case KoTextFormat::U_DOUBLE:
307 yUnderline = y + fm2.descent();
308 ( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
309 thicknessUnderline = 1;
310 drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
311 yUnderline = y + tqRound( fm2.descent() / 2 );
312 drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
313 break;
314 case KoTextFormat::U_SIMPLE_BOLD:
315 yUnderline = y + fm2.descent();
316 ( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
317 thicknessUnderline = tqRound( displayFont.pointSize() / 10 ) + 1;
318 drawUnderline( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
319 break;
320 case KoTextFormat::U_WAVE:
321 yUnderline = y + fm2.descent();
322 ( m_wordByWord )? widthUnderline = fm2.width( (*it) ): widthUnderline = fm2.width( textDraw );
323 thicknessUnderline = 1;
324 drawUnderlineWave( x, yUnderline, widthUnderline, thicknessUnderline, m_underliningColor, p );
325 break;
326 default:
327 break;
328 }
329/*Strikethrough*/
330 switch ( m_strikethrough ) {
331 case KoTextFormat::S_NONE:
332 break;
333 case KoTextFormat::S_SIMPLE:
334 yStrikethrough = y - tqRound( fm2.ascent() / 3 );
335 ( m_wordByWord )? widthStrikethrough = fm2.width( (*it) ): widthStrikethrough = fm2.width( textDraw );
336 thicknessStrikethrough = 1;
337 drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
338 break;
339 case KoTextFormat::S_DOUBLE:
340 yStrikethrough = y - tqRound( fm2.ascent() / 4 );
341 ( m_wordByWord )? widthStrikethrough = fm2.width( (*it) ): widthStrikethrough = fm2.width( textDraw );
342 thicknessStrikethrough = 1;
343 drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
344 yStrikethrough = y - 2 * tqRound( fm2.ascent() / 4 );
345 drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
346 break;
347 case KoTextFormat::S_SIMPLE_BOLD:
348 yStrikethrough = y - tqRound( fm2.ascent() / 3 );
349 ( m_wordByWord )? widthStrikethrough = fm2.width( (*it) ): widthStrikethrough = fm2.width( textDraw );
350 thicknessStrikethrough = tqRound( displayFont.pointSize() / 10 ) + 1;
351 drawStrikethrough( x, yStrikethrough, widthStrikethrough, thicknessStrikethrough, p );
352 break;
353 default:
354 break;
355 }
356 x += fm2.width( textDraw );
357 sx += fm2.width( textDraw );
358 count++;
359 }
360
361 p->restore();
362}
363
364void KoFontDiaPreview::drawUnderline( int x, int y, int width, int thickness, TQColor & color, TQPainter *p )
365{
366 p->save();
367 switch ( m_underliningStyle ) {
368 case KoTextFormat::U_SOLID:
369 p->setPen( TQPen( color, thickness, TQt::SolidLine ) );
370 break;
371 case KoTextFormat::U_DASH:
372 p->setPen( TQPen( color, thickness, TQt::DashLine ) );
373 break;
374 case KoTextFormat::U_DOT:
375 p->setPen( TQPen( color, thickness, TQt::DotLine ) );
376 break;
377 case KoTextFormat::U_DASH_DOT:
378 p->setPen( TQPen( color, thickness, TQt::DashDotLine ) );
379 break;
380 case KoTextFormat::U_DASH_DOT_DOT:
381 p->setPen( TQPen( color, thickness, TQt::DashDotDotLine ) );
382 break;
383 default:
384 p->setPen( TQPen( color, thickness, TQt::SolidLine ) );
385 }
386 p->drawLine( x, y, x+ width, y );
387 p->restore();
388}
389
390void KoFontDiaPreview::drawUnderlineWave( int x, int y, int width, int thickness, TQColor & color, TQPainter *p )
391{
392 p->save();
393 int offset = 2 * thickness;
394 TQPen pen(color, thickness, TQt::SolidLine);
395 pen.setCapStyle(TQt::RoundCap);
396 p->setPen(pen);
397 double anc=acos(1.0-2*(static_cast<double>(offset-(x)%offset)/static_cast<double>(offset)))/3.1415*180;
398 int pos=1;
399 //set starting position
400 if(2*((x/offset)/2)==x/offset)
401 pos*=-1;
402 //draw first part of wave
403 p->drawArc( (x/offset)*offset, y, offset, offset, 0, -tqRound(pos*anc*16) );
404 //now the main part
405 int zigzag_x = (x/offset+1)*offset;
406 for ( ; zigzag_x + offset <= width+x; zigzag_x += offset)
407 {
408 p->drawArc( zigzag_x, y, offset, offset, 0, pos*180*16 );
409 pos*=-1;
410 }
411 //and here we finish
412 anc=acos(1.0-2*(static_cast<double>((x+width)%offset)/static_cast<double>(offset)))/3.1415*180;
413 p->drawArc( zigzag_x, y, offset, offset, 180*16, -tqRound(pos*anc*16) );
414 p->restore();
415}
416
417void KoFontDiaPreview::drawStrikethrough( int x, int y, int width, int thickness, TQPainter *p )
418{
419 p->save();
420 switch ( m_strikethroughStyle ) {
421 case KoTextFormat::S_SOLID:
422 p->setPen( TQPen( TQt::black, thickness, TQt::SolidLine ) );
423 break;
424 case KoTextFormat::S_DASH:
425 p->setPen( TQPen( TQt::black, thickness, TQt::DashLine ) );
426 break;
427 case KoTextFormat::S_DOT:
428 p->setPen( TQPen( TQt::black, thickness, TQt::DotLine ) );
429 break;
430 case KoTextFormat::S_DASH_DOT:
431 p->setPen( TQPen( TQt::black, thickness, TQt::DashDotLine ) );
432 break;
433 case KoTextFormat::S_DASH_DOT_DOT:
434 p->setPen( TQPen( TQt::black, thickness, TQt::DashDotDotLine ) );
435 break;
436 default:
437 p->setPen( TQPen( TQt::black, thickness, TQt::SolidLine ) );
438 }
439 p->drawLine( x, y, x+ width, y );
440 p->restore();
441}
442
KoFontDiaPreview(TQWidget *parent=0, const char *name=0, WFlags fl=0)
Constructor.