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