| # kate Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

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

This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:36:36 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003