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.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 10 18:56:23 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003