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