00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
#include "kwordwrap.h"
00020
#include <kdebug.h>
00021
#include <kstringhandler.h>
00022
#include <qpainter.h>
00023
00024
class KWordWrapPrivate {
00025
public:
00026
QRect m_constrainingRect;
00027 };
00028
00029 KWordWrap::KWordWrap(
const QRect & r) {
00030 d =
new KWordWrapPrivate;
00031 d->m_constrainingRect = r;
00032 }
00033
00034 KWordWrap*
KWordWrap::formatText(
QFontMetrics &fm,
const QRect & r,
int ,
const QString & str,
int len )
00035 {
00036
KWordWrap* kw =
new KWordWrap( r );
00037
00038
00039
00040
00041
int height = fm.height();
00042
if ( len == -1 )
00043 kw->
m_text = str;
00044
else
00045 kw->
m_text = str.left( len );
00046
if ( len == -1 )
00047 len = str.length();
00048
int lastBreak = -1;
00049
int lineWidth = 0;
00050
int x = 0;
00051
int y = 0;
00052
int w = r.width();
00053
int textwidth = 0;
00054
bool isBreakable =
false;
00055
bool wasBreakable =
false;
00056
bool isParens =
false;
00057
bool wasParens =
false;
00058
00059
for (
int i = 0 ; i < len; ++i )
00060 {
00061
QChar c = str[i];
00062
int ww = fm.charWidth( str, i );
00063
00064 isParens = ( c ==
'(' || c ==
'[' || c ==
'{' );
00065
00066 isBreakable = ( c.isSpace() || c.isPunct() || c.isSymbol() ) & !isParens;
00067
00068
00069
if ( !isBreakable && i < len-1 ) {
00070
QChar nextc = str[i+1];
00071 isBreakable = ( nextc ==
'(' || nextc ==
'[' || nextc ==
'{' );
00072 }
00073
00074
00075
00076
if ( c ==
'/' && (wasBreakable || wasParens) )
00077 isBreakable =
false;
00078
00079
00080
00081
00082
int breakAt = -1;
00083
if ( x + ww > w && lastBreak != -1 )
00084 breakAt = lastBreak;
00085
if ( x + ww > w - 4 && lastBreak == -1 )
00086 breakAt = i;
00087
if ( i == len - 2 && x + ww + fm.charWidth( str, i+1 ) > w )
00088 breakAt = lastBreak == -1 ? i - 1 : lastBreak;
00089
if ( c ==
'\n' )
00090 {
00091
if ( breakAt == -1 && lastBreak != -1)
00092 {
00093 breakAt = i - 1;
00094 lastBreak = -1;
00095 }
00096
00097 kw->
m_text.remove(i, 1);
00098 len--;
00099 }
00100
if ( breakAt != -1 )
00101 {
00102
00103 kw->
m_breakPositions.append( breakAt );
00104
int thisLineWidth = lastBreak == -1 ? x + ww : lineWidth;
00105 kw->
m_lineWidths.append( thisLineWidth );
00106 textwidth = QMAX( textwidth, thisLineWidth );
00107 x = 0;
00108 y += height;
00109 wasBreakable =
true;
00110 wasParens =
false;
00111
if ( lastBreak != -1 )
00112 {
00113
00114 i = lastBreak;
00115 lastBreak = -1;
00116
continue;
00117 }
00118 }
else if ( isBreakable )
00119 {
00120 lastBreak = i;
00121 lineWidth = x + ww;
00122 }
00123 x += ww;
00124 wasBreakable = isBreakable;
00125 wasParens = isParens;
00126 }
00127 textwidth = QMAX( textwidth, x );
00128 kw->
m_lineWidths.append( x );
00129 y += height;
00130
00131
if ( r.height() >= 0 && y > r.height() )
00132 textwidth = r.width();
00133
int realY = y;
00134
if ( r.height() >= 0 )
00135 {
00136
while ( realY > r.height() )
00137 realY -= height;
00138 realY = QMAX( realY, 0 );
00139 }
00140 kw->
m_boundingRect.setRect( 0, 0, textwidth, realY );
00141
return kw;
00142 }
00143
00144 KWordWrap::~KWordWrap() {
00145
delete d;
00146 }
00147
00148 QString KWordWrap::wrappedString()
const
00149
{
00150
00151
QString ws;
00152
int start = 0;
00153
QValueList<int>::ConstIterator it = m_breakPositions.begin();
00154
for ( ; it != m_breakPositions.end() ; ++it )
00155 {
00156
int end = (*it);
00157 ws += m_text.mid( start, end - start + 1 ) +
'\n';
00158 start = end + 1;
00159 }
00160 ws += m_text.mid( start );
00161
return ws;
00162 }
00163
00164 QString KWordWrap::truncatedString(
bool dots )
const
00165
{
00166
if ( m_breakPositions.isEmpty() )
00167
return m_text;
00168
00169
QString ts = m_text.left( m_breakPositions.first() + 1 );
00170
if ( dots )
00171 ts +=
"...";
00172
return ts;
00173 }
00174
00175
static QColor mixColors(
double p1,
QColor c1,
QColor c2) {
00176
return QColor(
int(c1.red() * p1 + c2.red() * (1.0-p1)),
00177 int(c1.green() * p1 + c2.green() * (1.0-p1)),
00178 int(c1.blue() * p1 + c2.blue() * (1.0-p1)));
00179 }
00180
00181 void KWordWrap::drawFadeoutText(
QPainter *p,
int x,
int y,
int maxW,
00182
const QString &t) {
00183
QFontMetrics fm = p->fontMetrics();
00184
QColor bgColor = p->backgroundColor();
00185
QColor textColor = p->pen().color();
00186
00187
if ( ( fm.boundingRect( t ).width() > maxW ) && ( t.length() > 1 ) ) {
00188
unsigned int tl = 0;
00189
int w = 0;
00190
while ( tl < t.length() ) {
00191 w += fm.charWidth( t, tl );
00192
if ( w >= maxW )
00193
break;
00194 tl++;
00195 }
00196
00197
if (tl > 3) {
00198 p->drawText( x, y, t.left( tl - 3 ) );
00199 x += fm.width( t.left( tl - 3 ) );
00200 }
00201
int n = QMIN( tl, 3);
00202
for (
int i = 0; i < n; i++) {
00203 p->setPen( mixColors( 0.70 - i * 0.25, textColor, bgColor ) );
00204
QString s( t.at( tl - n + i ) );
00205 p->drawText( x, y, s );
00206 x += fm.width( s );
00207 }
00208 }
00209
else
00210 p->drawText( x, y, t );
00211 }
00212
00213 void KWordWrap::drawTruncateText(
QPainter *p,
int x,
int y,
int maxW,
00214
const QString &t) {
00215
QString tmpText =
KStringHandler::rPixelSqueeze( t, p->fontMetrics(), maxW );
00216 p->drawText( x, y, tmpText, maxW );
00217 }
00218
00219 void KWordWrap::drawText(
QPainter *painter,
int textX,
int textY,
int flags )
const
00220
{
00221
00222
00223
int start = 0;
00224
int y = 0;
00225
QFontMetrics fm = painter->fontMetrics();
00226
int height = fm.height();
00227
int ascent = fm.ascent();
00228
int maxwidth = m_boundingRect.width();
00229
QValueList<int>::ConstIterator it = m_breakPositions.begin();
00230
QValueList<int>::ConstIterator itw = m_lineWidths.begin();
00231
for ( ; it != m_breakPositions.end() ; ++it, ++itw )
00232 {
00233
00234
if ( (d->m_constrainingRect.height() >= 0) &&
00235 ((y + 2 * height) > d->m_constrainingRect.height()) )
00236
break;
00237
int end = (*it);
00238
int x = textX;
00239
if ( flags & Qt::AlignHCenter )
00240 x += ( maxwidth - *itw ) / 2;
00241
else if ( flags & Qt::AlignRight )
00242 x += maxwidth - *itw;
00243 painter->drawText( x, textY + y + ascent, m_text.mid( start, end - start + 1 ) );
00244 y += height;
00245 start = end + 1;
00246 }
00247
00248
int x = textX;
00249
if ( flags & Qt::AlignHCenter )
00250 x += ( maxwidth - *itw ) / 2;
00251
else if ( flags & Qt::AlignRight )
00252 x += maxwidth - *itw;
00253
if ( (d->m_constrainingRect.height() < 0) ||
00254 ((y + height) <= d->m_constrainingRect.height()) ) {
00255
if ( it == m_breakPositions.end() )
00256 painter->drawText( x, textY + y + ascent, m_text.mid( start ) );
00257
else if (flags & FadeOut)
00258
drawFadeoutText( painter, textX, textY + y + ascent,
00259 d->m_constrainingRect.width(),
00260 m_text.mid( start ) );
00261
else if (flags & Truncate)
00262
drawTruncateText( painter, textX, textY + y + ascent,
00263 d->m_constrainingRect.width(),
00264 m_text.mid( start ) );
00265
else
00266 painter->drawText( x, textY + y + ascent,
00267 m_text.mid( start, (*it) - start + 1 ) );
00268 }
00269 }