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 ( breakAt != -1 )
00089 {
00090
00091 kw->m_breakPositions.append( breakAt );
00092 int thisLineWidth = lastBreak == -1 ? x + ww : lineWidth;
00093 kw->m_lineWidths.append( thisLineWidth );
00094 textwidth = QMAX( textwidth, thisLineWidth );
00095 x = 0;
00096 y += height;
00097 wasBreakable = true;
00098 wasParens = false;
00099 if ( lastBreak != -1 )
00100 {
00101
00102 i = lastBreak;
00103 lastBreak = -1;
00104 continue;
00105 }
00106 } else if ( isBreakable )
00107 {
00108 lastBreak = i;
00109 lineWidth = x + ww;
00110 }
00111 x += ww;
00112 wasBreakable = isBreakable;
00113 wasParens = isParens;
00114 }
00115 textwidth = QMAX( textwidth, x );
00116 kw->m_lineWidths.append( x );
00117 y += height;
00118
00119 kw->m_boundingRect.setRect( 0, 0, textwidth, y );
00120 return kw;
00121 }
00122
00123 KWordWrap::~KWordWrap() {
00124 delete d;
00125 }
00126
00127 QString KWordWrap::wrappedString() const
00128 {
00129
00130 QString ws;
00131 int start = 0;
00132 QValueList<int>::ConstIterator it = m_breakPositions.begin();
00133 for ( ; it != m_breakPositions.end() ; ++it )
00134 {
00135 int end = (*it);
00136 ws += m_text.mid( start, end - start + 1 ) + '\n';
00137 start = end + 1;
00138 }
00139 ws += m_text.mid( start );
00140 return ws;
00141 }
00142
00143 QString KWordWrap::truncatedString( bool dots ) const
00144 {
00145 QString ts;
00146 QValueList<int>::ConstIterator it = m_breakPositions.begin();
00147 if ( it != m_breakPositions.end() )
00148 {
00149 ts = m_text.left( (*it) + 1 );
00150 if ( dots )
00151 ts += "...";
00152 }
00153 else
00154 ts = m_text;
00155 return ts;
00156 }
00157
00158 static QColor mixColors(double p1, QColor c1, QColor c2) {
00159 return QColor(int(c1.red() * p1 + c2.red() * (1.0-p1)),
00160 int(c1.green() * p1 + c2.green() * (1.0-p1)),
00161 int(c1.blue() * p1 + c2.blue() * (1.0-p1)));
00162 }
00163
00164 void KWordWrap::drawFadeoutText(QPainter *p, int x, int y, int maxW,
00165 const QString &t) {
00166 QFontMetrics fm = p->fontMetrics();
00167 QColor bgColor = p->backgroundColor();
00168 QColor textColor = p->pen().color();
00169
00170 if ( ( fm.boundingRect( t ).width() > maxW ) && ( t.length() > 1 ) ) {
00171 unsigned int tl = 0;
00172 int w = 0;
00173 while ( tl < t.length() ) {
00174 w += fm.charWidth( t, tl );
00175 if ( w >= maxW )
00176 break;
00177 tl++;
00178 }
00179
00180 if (tl > 3) {
00181 p->drawText( x, y, t.left( tl - 3 ) );
00182 x += fm.width( t.left( tl - 3 ) );
00183 }
00184 int n = QMIN( tl, 3);
00185 for (int i = 0; i < n; i++) {
00186 p->setPen( mixColors( 0.70 - i * 0.25, textColor, bgColor ) );
00187 QString s( t.at( tl - n + i ) );
00188 p->drawText( x, y, s );
00189 x += fm.width( s );
00190 }
00191 }
00192 else
00193 p->drawText( x, y, t );
00194 }
00195
00196 void KWordWrap::drawText( QPainter *painter, int textX, int textY, int flags ) const
00197 {
00198
00199
00200 int start = 0;
00201 int y = 0;
00202 QFontMetrics fm = painter->fontMetrics();
00203 int height = fm.height();
00204 int ascent = fm.ascent();
00205 int maxwidth = m_boundingRect.width();
00206 QValueList<int>::ConstIterator it = m_breakPositions.begin();
00207 QValueList<int>::ConstIterator itw = m_lineWidths.begin();
00208 for ( ; it != m_breakPositions.end() ; ++it, ++itw )
00209 {
00210
00211 if ( (d->m_constrainingRect.height() >= 0) &&
00212 ((y + 2 * height) > d->m_constrainingRect.height()) )
00213 break;
00214 int end = (*it);
00215 int x = textX;
00216 if ( flags & Qt::AlignHCenter )
00217 x += ( maxwidth - *itw ) / 2;
00218 else if ( flags & Qt::AlignRight )
00219 x += maxwidth - *itw;
00220 painter->drawText( x, textY + y + ascent, m_text.mid( start, end - start + 1 ) );
00221 y += height;
00222 start = end + 1;
00223 }
00224
00225 int x = textX;
00226 if ( flags & Qt::AlignHCenter )
00227 x += ( maxwidth - *itw ) / 2;
00228 else if ( flags & Qt::AlignRight )
00229 x += maxwidth - *itw;
00230 if ( (d->m_constrainingRect.height() < 0) ||
00231 ((y + height) <= d->m_constrainingRect.height()) ) {
00232 if ( it == m_breakPositions.end() )
00233 painter->drawText( x, textY + y + ascent, m_text.mid( start ) );
00234 else if (flags & FadeOut)
00235 drawFadeoutText( painter, x, textY + y + ascent,
00236 d->m_constrainingRect.width() - x + textX,
00237 m_text.mid( start ) );
00238 else
00239 painter->drawText( x, textY + y + ascent,
00240 m_text.mid( start, (*it) - start + 1 ) );
00241 }
00242 }
00243