kate Library API Documentation

katerenderer.cpp

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