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