kate Library API Documentation

katerenderer.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2003 Hamish Rodda <rodda@kde.org>
00003    Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00004    Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
00005    Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License version 2 as published by the Free Software Foundation.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include "katerenderer.h"
00023 
00024 #include "katelinerange.h"
00025 #include "katedocument.h"
00026 #include "katearbitraryhighlight.h"
00027 #include "kateconfig.h"
00028 #include "katehighlight.h"
00029 #include "katefactory.h"
00030 #include "kateview.h"
00031 
00032 #include <kdebug.h>
00033 
00034 #include <qpainter.h>
00035 
00036 static const QChar tabChar('\t');
00037 static const QChar spaceChar(' ');
00038 
00039 KateRenderer::KateRenderer(KateDocument* doc, KateView *view)
00040   : m_doc(doc), m_view (view), m_caretStyle(KateRenderer::Insert)
00041     , m_drawCaret(true)
00042     , m_showSelections(true)
00043     , m_showTabs(true)
00044     , m_printerFriendly(false)
00045 {
00046   KateFactory::self()->registerRenderer ( this );
00047   m_config = new KateRendererConfig (this);
00048 
00049   m_tabWidth = m_doc->config()->tabWidth();
00050 
00051   updateAttributes ();
00052 }
00053 
00054 KateRenderer::~KateRenderer()
00055 {
00056   delete m_config;
00057   KateFactory::self()->deregisterRenderer ( this );
00058 }
00059 
00060 void KateRenderer::updateAttributes ()
00061 {
00062   m_schema = config()->schema ();
00063   m_attributes = m_doc->m_highlight->attributes (m_schema);
00064 }
00065 
00066 KateAttribute* KateRenderer::attribute(uint pos)
00067 {
00068   if (pos < m_attributes->size())
00069     return &m_attributes->at(pos);
00070 
00071   return &m_attributes->at(0);
00072 }
00073 
00074 void KateRenderer::setDrawCaret(bool drawCaret)
00075 {
00076   m_drawCaret = drawCaret;
00077 }
00078 
00079 void KateRenderer::setCaretStyle(KateRenderer::caretStyles style)
00080 {
00081   m_caretStyle = style;
00082 }
00083 
00084 void KateRenderer::setShowTabs(bool showTabs)
00085 {
00086   m_showTabs = showTabs;
00087 }
00088 
00089 void KateRenderer::setTabWidth(int tabWidth)
00090 {
00091   m_tabWidth = tabWidth;
00092 }
00093 
00094 void KateRenderer::setShowSelections(bool showSelections)
00095 {
00096   m_showSelections = showSelections;
00097 }
00098 
00099 void KateRenderer::increaseFontSizes()
00100 {
00101   QFont f ( *config()->font () );
00102   f.setPointSize (f.pointSize ()+1);
00103 
00104   config()->setFont (f);
00105 }
00106 
00107 void KateRenderer::decreaseFontSizes()
00108 {
00109   QFont f ( *config()->font () );
00110 
00111   if ((f.pointSize ()-1) > 0)
00112     f.setPointSize (f.pointSize ()-1);
00113 
00114   config()->setFont (f);
00115 }
00116 
00117 bool KateRenderer::isPrinterFriendly() const
00118 {
00119   return m_printerFriendly;
00120 }
00121 
00122 void KateRenderer::setPrinterFriendly(bool printerFriendly)
00123 {
00124   m_printerFriendly = printerFriendly;
00125   setShowTabs(false);
00126   setShowSelections(false);
00127   setDrawCaret(false);
00128 }
00129 
00130 void KateRenderer::paintTextLine(QPainter& paint, const KateLineRange* range, int xStart, int xEnd, const KateTextCursor* cursor, const KateTextRange* bracketmark)
00131 {
00132   int line = range->line;
00133 
00134   // textline
00135   KateTextLine::Ptr textLine = m_doc->kateTextLine(line);
00136 
00137   if (!textLine)
00138     return;
00139 
00140   int showCursor = (drawCaret() && cursor && range->includesCursor(*cursor)) ? cursor->col() : -1;
00141 
00142   KateSuperRangeList& superRanges = m_doc->arbitraryHL()->rangesIncluding(range->line, 0);
00143 
00144   // A bit too verbose for my tastes
00145   // Re-write a bracketmark class? put into its own function? add more helper constructors to the range stuff?
00146   // Also, need a light-weight arbitraryhighlightrange class for static stuff
00147   KateArbitraryHighlightRange* bracketStartRange (0L);
00148   KateArbitraryHighlightRange* bracketEndRange (0L);
00149   if (bracketmark && bracketmark->isValid()) {
00150     if (range->includesCursor(bracketmark->start())) {
00151       KateTextCursor startend = bracketmark->start();
00152       startend.setCol(startend.col()+1);
00153       bracketStartRange = new KateArbitraryHighlightRange(m_doc, bracketmark->start(), startend);
00154       bracketStartRange->setBGColor(config()->highlightedBracketColor());
00155       superRanges.append(bracketStartRange);
00156     }
00157 
00158     if (range->includesCursor(bracketmark->end())) {
00159       KateTextCursor endend = bracketmark->end();
00160       endend.setCol(endend.col()+1);
00161       bracketEndRange = new KateArbitraryHighlightRange(m_doc, bracketmark->end(), endend);
00162       bracketEndRange->setBGColor(config()->highlightedBracketColor());
00163       superRanges.append(bracketEndRange);
00164     }
00165   }
00166 
00167   // font data
00168   KateFontStruct * fs = config()->fontStruct();
00169 
00170   bool currentLine = false;
00171 
00172   if (cursor && range->includesCursor(*cursor))
00173     currentLine = true;
00174 
00175   int startcol = range->startCol;
00176   int endcol = range->wrap ? range->endCol : -1;
00177 
00178   // text attribs font/style data
00179   KateAttribute* at = m_doc->m_highlight->attributes(m_schema)->data();
00180   uint atLen = m_doc->m_highlight->attributes(m_schema)->size();
00181 
00182   // length, chars + raw attribs
00183   uint len = textLine->length();
00184   uint oldLen = len;
00185   //const QChar *s;
00186   const uchar *a;
00187 
00188    // selection startcol/endcol calc
00189   bool hasSel = false;
00190   uint startSel = 0;
00191   uint endSel = 0;
00192 
00193   // was the selection background already completely painted ?
00194   bool selectionPainted = false;
00195 
00196   // should the cursor be painted (if it is in the current xstart - xend range)
00197   bool cursorVisible = false;
00198   int cursorXPos = 0, cursorXPos2 = 0;
00199   int cursorMaxWidth = 0;
00200 
00201   // should we paint the word wrap marker?
00202   bool paintWWMarker = !isPrinterFriendly() && config()->wordWrapMarker() && fs->fixedPitch();
00203 
00204   // Normal background color
00205   QColor backgroundColor (config()->backgroundColor());
00206 
00207   // Paint selection background as the whole line is selected
00208   if (!isPrinterFriendly())
00209   {
00210     if (showSelections() && m_doc->lineSelected(line))
00211     {
00212       backgroundColor = config()->selectionColor();
00213       selectionPainted = true;
00214       hasSel = true;
00215       startSel = 0;
00216       endSel = len + 1;
00217     }
00218     else
00219     {
00220       // paint the current line background if we're on the current line
00221       if (currentLine)
00222         backgroundColor = config()->highlightedLineColor();
00223 
00224       // Check for mark background
00225       int markRed = 0, markGreen = 0, markBlue = 0, markCount = 0;
00226 
00227       // Retrieve marks for this line
00228       uint mrk = m_doc->mark( line );
00229 
00230       if (mrk)
00231       {
00232         for (uint bit = 0; bit < 32; bit++)
00233         {
00234           KTextEditor::MarkInterface::MarkTypes markType = (KTextEditor::MarkInterface::MarkTypes)(1<<bit);
00235           if (mrk & markType)
00236           {
00237             QColor markColor = m_doc->markColor( markType );
00238 
00239             if (markColor.isValid()) {
00240               markCount++;
00241               markRed += markColor.red();
00242               markGreen += markColor.green();
00243               markBlue += markColor.blue();
00244             }
00245           }
00246         }
00247       }
00248 
00249       if (markCount) {
00250         markRed /= markCount;
00251         markGreen /= markCount;
00252         markBlue /= markCount;
00253         backgroundColor.setRgb(
00254           int((backgroundColor.red() * 0.9) + (markRed * 0.1)),
00255           int((backgroundColor.green() * 0.9) + (markGreen * 0.1)),
00256           int((backgroundColor.blue() * 0.9) + (markBlue * 0.1))
00257         );
00258       }
00259     }
00260 
00261     // Draw line background
00262     paint.fillRect(0, 0, xEnd - xStart, fs->fontHeight, backgroundColor);
00263   }
00264 
00265   if (startcol > (int)len)
00266     startcol = len;
00267 
00268   if (startcol < 0)
00269     startcol = 0;
00270 
00271   if (endcol < 0)
00272     len = len - startcol;
00273   else
00274     len = endcol - startcol;
00275 
00276   // text + attrib data from line
00277   a = textLine->attributes ();
00278   bool noAttribs = !a;
00279 
00280   // adjust to startcol ;)
00281   a = a + startcol;
00282 
00283   uint curCol = startcol;
00284 
00285   // or we will see no text ;)
00286   int y = fs->fontAscent;
00287 
00288   // painting loop
00289   uint xPos = range->xOffset();
00290   uint xPosAfter = xPos;
00291 
00292   KateAttribute* oldAt = &at[0];
00293   const QColor *cursorColor = &at[0].textColor();
00294 
00295   const QColor *curColor = 0;
00296   const QColor *oldColor = 0;
00297 
00298   // Start arbitrary highlighting
00299   KateTextCursor currentPos(line, curCol);
00300   superRanges.firstBoundary(&currentPos);
00301   KateAttribute currentHL;
00302 
00303   if (showSelections() && !selectionPainted)
00304   {
00305     hasSel = selectBounds(line, startSel, endSel, oldLen);
00306   }
00307 
00308   uint oldCol = startcol;
00309   uint oldXPos = xPos;
00310 
00311   bool isSel = false;
00312 
00313   // Draws the dashed underline at the start of a folded block of text.
00314   if (range->startsInvisibleBlock) {
00315     paint.setPen(QPen(config()->wordWrapMarkerColor(), 1, Qt::DashLine));
00316     paint.drawLine(0, fs->fontHeight - 1, xEnd - xStart, fs->fontHeight - 1);
00317   }
00318 
00319   bool isIMEdit = false;
00320   bool isIMSel = false;
00321   uint imStartLine, imStart, imEnd, imSelStart, imSelEnd;
00322   m_doc->getIMSelectionValue( &imStartLine, &imStart, &imEnd, &imSelStart, &imSelEnd );
00323 
00324   KateAttribute customHL;
00325 
00326   // draw word-wrap-honor-indent filling
00327   if (range->xOffset() && range->xOffset() > xStart)
00328     paint.fillRect(0, 0, range->xOffset() - xStart, fs->fontHeight, QBrush(config()->wordWrapMarkerColor(), QBrush::DiagCrossPattern));
00329 
00330   // Optimisation to quickly draw an empty line of text
00331   if (len < 1)
00332   {
00333     if ((showCursor > -1) && (showCursor >= (int)curCol))
00334     {
00335       cursorVisible = true;
00336       cursorXPos = xPos + (showCursor - (int) curCol) * fs->myFontMetrics.width(spaceChar);
00337       cursorMaxWidth = xPosAfter - xPos;
00338     }
00339 
00340   }
00341   else
00342   {
00343     // loop each character (tmp goes backwards, but curCol doesn't)
00344     for (uint tmp = len; (tmp > 0); tmp--)
00345     {
00346       // Determine cursor position
00347       if (showCursor > -1 && cursor->col() == (int)curCol)
00348         cursorXPos2 = xPos;
00349 
00350       QChar curChar = textLine->string()[curCol];
00351       // Decide if this character is a tab - we treat the spacing differently
00352       // TODO: move tab width calculation elsewhere?
00353       bool isTab = curChar == tabChar;
00354 
00355       // Determine current syntax highlighting attribute
00356       // A bit legacy but doesn't need to change
00357       KateAttribute* curAt = (noAttribs || ((*a) >= atLen)) ? &at[0] : &at[*a];
00358       // X position calculation. Incorrect for fonts with non-zero leftBearing() and rightBearing() results.
00359       // TODO: make internal charWidth() function, use QFontMetrics::charWidth().
00360       xPosAfter += curAt->width(*fs, curChar, m_tabWidth);
00361 
00362       // Tab special treatment, move to charWidth().
00363       if (isTab)
00364         xPosAfter -= (xPosAfter % curAt->width(*fs, curChar, m_tabWidth));
00365 
00366       // Only draw after the starting X value
00367       // Haha, this was always wrong, due to the use of individual char width calculations...?? :(
00368       if ((int)xPosAfter >= xStart)
00369       {
00370         // Determine if we're in a selection and should be drawing it
00371         isSel = (showSelections() && hasSel && (curCol >= startSel) && (curCol < endSel));
00372 
00373         // input method edit area
00374         isIMEdit = ( ( int( imStartLine ) == line ) & ( imStart < imEnd ) & ( curCol >= imStart ) & ( curCol < imEnd ) );
00375 
00376         // input method selection
00377         isIMSel = ( ( int( imStartLine ) == line ) & ( imSelStart < imSelEnd ) & ( curCol >= imSelStart ) & ( curCol < imSelEnd ) );
00378 
00379         // Determine current color, taking into account selection
00380         curColor = isSel ? &(curAt->selectedTextColor()) : &(curAt->textColor());
00381 
00382         // Incorporate in arbitrary highlighting
00383         if (curAt != oldAt || curColor != oldColor || (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)) {
00384           if (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
00385             customHL = KateArbitraryHighlightRange::merge(superRanges.rangesIncluding(currentPos));
00386 
00387           KateAttribute hl = customHL;
00388 
00389           hl += *curAt;
00390 
00391           // use default highlighting color if we haven't defined one above.
00392           if (!hl.itemSet(KateAttribute::TextColor))
00393             hl.setTextColor(*curColor);
00394 
00395           if (!isSel)
00396             paint.setPen(hl.textColor());
00397           else
00398             paint.setPen(hl.selectedTextColor());
00399 
00400           paint.setFont(hl.font(*currentFont()));
00401 
00402           if (superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
00403             superRanges.nextBoundary();
00404 
00405           currentHL = hl;
00406         }
00407 
00408         // make sure we redraw the right character groups on attrib/selection changes
00409         // Special case... de-special case some of it
00410         if (isTab)
00411         {
00412           if (!isPrinterFriendly() && !selectionPainted) {
00413             if (isSel)
00414               paint.fillRect(oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight, config()->selectionColor());
00415             else if (currentHL.itemSet(KateAttribute::BGColor))
00416               paint.fillRect(oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight, currentHL.bgColor());
00417           }
00418 
00419           // Draw spaces too, because it might be eg. underlined
00420           static QString spaces;
00421           if (int(spaces.length()) != m_tabWidth)
00422             spaces.fill(' ', m_tabWidth);
00423 
00424           paint.drawText(oldXPos-xStart, y, spaces);
00425 
00426           if (showTabs())
00427           {
00428             QPen penBackup( paint.pen() );
00429             paint.setPen( config()->tabMarkerColor() );
00430             paint.drawPoint(xPos - xStart, y);
00431             paint.drawPoint(xPos - xStart + 1, y);
00432             paint.drawPoint(xPos - xStart, y - 1);
00433             paint.setPen( penBackup );
00434           }
00435 
00436           // variable advancement
00437           oldCol = curCol+1;
00438           oldXPos = xPosAfter;
00439         }
00440         // Reasons for NOT delaying the drawing until the next character
00441         // You have to detect the change one character in advance.
00442         // TODO: KateAttribute::canBatchRender()
00443         else if (
00444             // formatting has changed OR
00445             (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == KateTextCursor(line, curCol+1)) ||
00446 
00447             // it is the end of the line OR
00448             (tmp < 2) ||
00449 
00450             // the x position is past the end OR
00451             ((int)xPos > xEnd) ||
00452 
00453             // it is a different attribute OR
00454             (!noAttribs && curAt != &at[*(a+1)]) ||
00455 
00456             // the selection boundary was crossed OR
00457             (isSel != (hasSel && ((curCol+1) >= startSel) && ((curCol+1) < endSel))) ||
00458 
00459             // the next char is a tab (removed the "and this isn't" because that's dealt with above)
00460             // i.e. we have to draw the current text so the tab can be rendered as above.
00461             (textLine->string()[curCol+1] == tabChar) ||
00462 
00463             // input method edit area
00464             ( isIMEdit != ( imStart < imEnd && ( (curCol+1) >= imStart && (curCol+1) < imEnd ) ) ) ||
00465 
00466             // input method selection
00467             ( isIMSel != ( imSelStart < imSelEnd && ( (curCol+1) >= imSelStart && (curCol+1) < imSelEnd ) ) )
00468           )
00469         {
00470           // TODO: genericise background painting
00471           if (!isPrinterFriendly() && !selectionPainted) {
00472             if (isSel)
00473               paint.fillRect(oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight, config()->selectionColor());
00474             else if (currentHL.itemSet(KateAttribute::BGColor))
00475               paint.fillRect(oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight, currentHL.bgColor());
00476           }
00477 
00478           // XIM support
00479           if (!isPrinterFriendly()) {
00480             // input method edit area
00481             if ( isIMEdit ) {
00482               const QColorGroup& cg = m_view->colorGroup();
00483               int h1, s1, v1, h2, s2, v2;
00484               cg.color( QColorGroup::Base ).hsv( &h1, &s1, &v1 );
00485               cg.color( QColorGroup::Background ).hsv( &h2, &s2, &v2 );
00486               QColor imCol;
00487               imCol.setHsv( h1, s1, ( v1 + v2 ) / 2 );
00488               paint.fillRect( oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight, imCol );
00489             }
00490 
00491             // input method selection
00492             if ( isIMSel ) {
00493               const QColorGroup& cg = m_view->colorGroup();
00494               paint.fillRect( oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight, cg.color( QColorGroup::Foreground ) );
00495               paint.save();
00496               paint.setPen( cg.color( QColorGroup::BrightText ) );
00497             }
00498           }
00499 
00500           // Here's where the money is...
00501           paint.drawText(oldXPos-xStart, y, textLine->string(), oldCol, curCol+1-oldCol);
00502 
00503           // Draw preedit's underline
00504           if (isIMEdit) {
00505             QRect r( oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight );
00506             paint.drawLine( r.bottomLeft(), r.bottomRight() );
00507           }
00508 
00509           // Put pen color back
00510           if (isIMSel) paint.restore();
00511 
00512           // We're done drawing?
00513           if ((int)xPos > xEnd)
00514             break;
00515 
00516           // variable advancement
00517           oldCol = curCol+1;
00518           oldXPos = xPosAfter;
00519           //oldS = s+1;
00520         }
00521 
00522         // determine cursor X position
00523         if ((showCursor > -1) && (showCursor == (int)curCol))
00524         {
00525           cursorVisible = true;
00526           cursorXPos = xPos;
00527           cursorMaxWidth = xPosAfter - xPos;
00528           cursorColor = &curAt->textColor();
00529         }
00530       }
00531       else
00532       {
00533         // variable advancement
00534         oldCol = curCol+1;
00535         oldXPos = xPosAfter;
00536       }
00537 
00538       // increase xPos
00539       xPos = xPosAfter;
00540 
00541       // increase attribs pos
00542       a++;
00543 
00544       // to only switch font/color if needed
00545       oldAt = curAt;
00546       oldColor = curColor;
00547 
00548       // col move
00549       curCol++;
00550       currentPos.setCol(currentPos.col() + 1);
00551     }
00552 
00553     // Determine cursor position (if it is not within the range being drawn)
00554     if ((showCursor > -1) && (showCursor >= (int)curCol))
00555     {
00556       cursorVisible = true;
00557       cursorXPos = xPos + (showCursor - (int) curCol) * fs->myFontMetrics.width(spaceChar);
00558       cursorMaxWidth = xPosAfter - xPos;
00559       cursorColor = &oldAt->textColor();
00560     }
00561   }
00562 
00563   // Draw dregs of the selection
00564   // TODO: genericise background painting
00565   if (!isPrinterFriendly() && showSelections() && !selectionPainted && m_doc->lineEndSelected (line, endcol))
00566   {
00567     paint.fillRect(xPos-xStart, 0, xEnd - xStart, fs->fontHeight, config()->selectionColor());
00568     selectionPainted = true;
00569   }
00570 
00571   // Paint cursor
00572   if (cursorVisible)
00573   {
00574     if (caretStyle() == Replace && (cursorMaxWidth > 2))
00575       paint.fillRect(cursorXPos-xStart, 0, cursorMaxWidth, fs->fontHeight, *cursorColor);
00576     else
00577       paint.fillRect(cursorXPos-xStart, 0, 2, fs->fontHeight, *cursorColor);
00578   }
00579   // Draw the cursor at the function user's specified position.
00580   // TODO: Why?????
00581   else if (showCursor > -1)
00582   {
00583     if ((cursorXPos2>=xStart) && (cursorXPos2<=xEnd))
00584     {
00585       cursorMaxWidth = fs->myFontMetrics.width(spaceChar);
00586 
00587       if (caretStyle() == Replace && (cursorMaxWidth > 2))
00588         paint.fillRect(cursorXPos2-xStart, 0, cursorMaxWidth, fs->fontHeight, attribute(0)->textColor());
00589       else
00590         paint.fillRect(cursorXPos2-xStart, 0, 2, fs->fontHeight, attribute(0)->textColor());
00591     }
00592   }
00593 
00594   // show word wrap marker if desirable
00595   if ( paintWWMarker ) {
00596     paint.setPen( config()->wordWrapMarkerColor() );
00597     int _x = m_doc->config()->wordWrapAt() * fs->myFontMetrics.width('x') - xStart;
00598     paint.drawLine( _x,0,_x,fs->fontHeight );
00599   }
00600 
00601   // cleanup ;)
00602   delete bracketStartRange;
00603   delete bracketEndRange;
00604 }
00605 
00606 uint KateRenderer::textWidth(const KateTextLine::Ptr &textLine, int cursorCol)
00607 {
00608   if (!textLine)
00609     return 0;
00610 
00611   int len = textLine->length();
00612 
00613   if (cursorCol < 0)
00614     cursorCol = len;
00615 
00616   KateFontStruct *fs = config()->fontStruct();
00617 
00618   int x = 0;
00619   int width;
00620   for (int z = 0; z < cursorCol; z++) {
00621     KateAttribute* a = attribute(textLine->attribute(z));
00622 
00623     if (z < len) {
00624       width = a->width(*fs, textLine->string(), z, m_tabWidth);
00625     } else {
00626       Q_ASSERT(!m_doc->wrapCursor());
00627       width = a->width(*fs, spaceChar, m_tabWidth);
00628     }
00629 
00630     x += width;
00631 
00632     if (textLine->getChar(z) == tabChar)
00633       x -= x % width;
00634   }
00635 
00636   return x;
00637 }
00638 
00639 uint KateRenderer::textWidth(const KateTextLine::Ptr &textLine, uint startcol, uint maxwidth, bool *needWrap, int *endX)
00640 {
00641   KateFontStruct *fs = config()->fontStruct();
00642   uint x = 0;
00643   uint endcol = startcol;
00644   int endX2 = 0;
00645   int lastWhiteSpace = -1;
00646   int lastWhiteSpaceX = -1;
00647 
00648   // used to not wrap a solitary word off the first line, ie. the
00649   // first line should not wrap until some characters have been displayed if possible
00650   bool foundNonWhitespace = startcol != 0;
00651   bool foundWhitespaceAfterNonWhitespace = startcol != 0;
00652 
00653   *needWrap = false;
00654 
00655   uint z = startcol;
00656   for (; z < textLine->length(); z++)
00657   {
00658     KateAttribute* a = attribute(textLine->attribute(z));
00659     int width = a->width(*fs, textLine->string(), z, m_tabWidth);
00660     Q_ASSERT(width);
00661     x += width;
00662 
00663     if (textLine->getChar(z).isSpace())
00664     {
00665       lastWhiteSpace = z+1;
00666       lastWhiteSpaceX = x;
00667 
00668       if (foundNonWhitespace)
00669         foundWhitespaceAfterNonWhitespace = true;
00670     }
00671     else
00672     {
00673       if (!foundWhitespaceAfterNonWhitespace) {
00674         foundNonWhitespace = true;
00675 
00676         lastWhiteSpace = z+1;
00677         lastWhiteSpaceX = x;
00678       }
00679     }
00680 
00681     // How should tabs be treated when they word-wrap on a print-out?
00682     // if startcol != 0, this messes up (then again, word wrapping messes up anyway)
00683     if (textLine->getChar(z) == tabChar)
00684       x -= x % width;
00685 
00686     if (x <= maxwidth)
00687     {
00688       if (lastWhiteSpace > -1)
00689       {
00690         endcol = lastWhiteSpace;
00691         endX2 = lastWhiteSpaceX;
00692       }
00693       else
00694       {
00695         endcol = z+1;
00696         endX2 = x;
00697       }
00698     }
00699     else if (z == startcol)
00700     {
00701       // require a minimum of 1 character advancement per call, even if it means drawing gets cut off
00702       // (geez gideon causes troubles with starting the views very small)
00703       endcol = z+1;
00704       endX2 = x;
00705     }
00706 
00707     if (x >= maxwidth)
00708     {
00709       *needWrap = true;
00710       break;
00711     }
00712   }
00713 
00714   if (*needWrap)
00715   {
00716     if (endX)
00717       *endX = endX2;
00718 
00719     return endcol;
00720   }
00721   else
00722   {
00723     if (endX)
00724       *endX = x;
00725 
00726     return z+1;
00727   }
00728 }
00729 
00730 uint KateRenderer::textWidth(const KateTextCursor &cursor)
00731 {
00732   int line = QMIN(QMAX(0, cursor.line()), (int)m_doc->numLines() - 1);
00733   int col = QMAX(0, cursor.col());
00734 
00735   return textWidth(m_doc->kateTextLine(line), col);
00736 }
00737 
00738 uint KateRenderer::textWidth( KateTextCursor &cursor, int xPos, uint startCol)
00739 {
00740   bool wrapCursor = m_doc->wrapCursor();
00741   int len;
00742   int x, oldX;
00743 
00744   KateFontStruct *fs = config()->fontStruct();
00745 
00746   if (cursor.line() < 0) cursor.setLine(0);
00747   if (cursor.line() > (int)m_doc->lastLine()) cursor.setLine(m_doc->lastLine());
00748   KateTextLine::Ptr textLine = m_doc->kateTextLine(cursor.line());
00749 
00750   if (!textLine) return 0;
00751 
00752   len = textLine->length();
00753 
00754   x = oldX = 0;
00755   int z = startCol;
00756   while (x < xPos && (!wrapCursor || z < len)) {
00757     oldX = x;
00758 
00759     KateAttribute* a = attribute(textLine->attribute(z));
00760 
00761     int width = 0;
00762 
00763     if (z < len)
00764       width = a->width(*fs, textLine->string(), z, m_tabWidth);
00765     else
00766       width = a->width(*fs, spaceChar, m_tabWidth);
00767 
00768     x += width;
00769 
00770     if (textLine->getChar(z) == tabChar)
00771       x -= x % width;
00772 
00773     z++;
00774   }
00775   if (xPos - oldX < x - xPos && z > 0) {
00776     z--;
00777     x = oldX;
00778   }
00779   cursor.setCol(z);
00780   return x;
00781 }
00782 
00783 const QFont *KateRenderer::currentFont()
00784 {
00785   return config()->font();
00786 }
00787 
00788 const QFontMetrics* KateRenderer::currentFontMetrics()
00789 {
00790   return config()->fontMetrics();
00791 }
00792 
00793 uint KateRenderer::textPos(uint line, int xPos, uint startCol, bool nearest)
00794 {
00795   return textPos(m_doc->kateTextLine(line), xPos, startCol, nearest);
00796 }
00797 
00798 uint KateRenderer::textPos(const KateTextLine::Ptr &textLine, int xPos, uint startCol, bool nearest)
00799 {
00800   Q_ASSERT(textLine);
00801   if (!textLine)
00802     return 0;
00803 
00804   KateFontStruct *fs = config()->fontStruct();
00805 
00806   int x, oldX;
00807   x = oldX = 0;
00808 
00809   uint z = startCol;
00810   uint len= textLine->length();
00811   while ( (x < xPos)  && (z < len)) {
00812     oldX = x;
00813 
00814     KateAttribute* a = attribute(textLine->attribute(z));
00815     x += a->width(*fs, textLine->string(), z, m_tabWidth);
00816 
00817     z++;
00818   }
00819   if ( ( (! nearest) || xPos - oldX < x - xPos ) && z > 0 ) {
00820     z--;
00821    // newXPos = oldX;
00822   }// else newXPos = x;
00823   return z;
00824 }
00825 
00826 uint KateRenderer::fontHeight()
00827 {
00828   return config()->fontStruct ()->fontHeight;
00829 }
00830 
00831 uint KateRenderer::documentHeight()
00832 {
00833   return m_doc->numLines() * fontHeight();
00834 }
00835 
00836 
00837 bool KateRenderer::selectBounds(uint line, uint &start, uint &end, uint lineLength)
00838 {
00839   bool hasSel = false;
00840 
00841   if (m_doc->hasSelection() && !m_doc->blockSelect)
00842   {
00843     if (m_doc->lineIsSelection(line))
00844     {
00845       start = m_doc->selectStart.col();
00846       end = m_doc->selectEnd.col();
00847       hasSel = true;
00848     }
00849     else if ((int)line == m_doc->selectStart.line())
00850     {
00851       start = m_doc->selectStart.col();
00852       end = lineLength;
00853       hasSel = true;
00854     }
00855     else if ((int)line == m_doc->selectEnd.line())
00856     {
00857       start = 0;
00858       end = m_doc->selectEnd.col();
00859       hasSel = true;
00860     }
00861   }
00862   else if (m_doc->lineHasSelected(line))
00863   {
00864     start = m_doc->selectStart.col();
00865     end = m_doc->selectEnd.col();
00866     hasSel = true;
00867   }
00868 
00869   if (start > end) {
00870     int temp = end;
00871     end = start;
00872     start = temp;
00873   }
00874 
00875   return hasSel;
00876 }
00877 
00878 void KateRenderer::updateConfig ()
00879 {
00880   // update the attribute list pointer
00881   updateAttributes ();
00882 
00883   if (m_view)
00884     m_view->updateRendererConfig();
00885 }
00886 
00887 uint KateRenderer::spaceWidth()
00888 {
00889   return attribute(0)->width(*config()->fontStruct(), spaceChar, m_tabWidth);
00890 }
00891 
00892 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Logo
This file is part of the documentation for kate Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 30 10:24:44 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003