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