• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Kate

katerenderer.cpp

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

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal