00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "katerenderer.h"
00023
00024 #include "katelinerange.h"
00025 #include "katedocument.h"
00026 #include "katearbitraryhighlight.h"
00027 #include "kateconfig.h"
00028 #include "katehighlight.h"
00029 #include "katefactory.h"
00030 #include "kateview.h"
00031
00032 #include <kdebug.h>
00033
00034 #include <qpainter.h>
00035 #include <qpopupmenu.h>
00036
00037 KateRenderer::KateRenderer(KateDocument* doc, KateView *view)
00038 : m_doc(doc), m_view (view), m_caretStyle(KateRenderer::Insert)
00039 , m_drawCaret(true)
00040 , m_showSelections(true)
00041 , m_showTabs(true)
00042 , m_printerFriendly(false)
00043 {
00044 KateFactory::self()->registerRenderer ( this );
00045 m_config = new KateRendererConfig (this);
00046
00047 m_tabWidth = m_doc->config()->tabWidth();
00048 m_indentWidth = m_tabWidth;
00049 if (m_doc->config()->configFlags() & KateDocumentConfig::cfSpaceIndent)
00050 {
00051 m_indentWidth = m_doc->config()->indentationWidth();
00052 }
00053
00054 updateAttributes ();
00055 }
00056
00057 KateRenderer::~KateRenderer()
00058 {
00059 delete m_config;
00060 KateFactory::self()->deregisterRenderer ( this );
00061 }
00062
00063 void KateRenderer::updateAttributes ()
00064 {
00065 m_schema = config()->schema ();
00066 m_attributes = m_doc->highlight()->attributes (m_schema);
00067 }
00068
00069 KateAttribute* KateRenderer::attribute(uint pos)
00070 {
00071 if (pos < m_attributes->size())
00072 return &m_attributes->at(pos);
00073
00074 return &m_attributes->at(0);
00075 }
00076
00077 void KateRenderer::setDrawCaret(bool drawCaret)
00078 {
00079 m_drawCaret = drawCaret;
00080 }
00081
00082 void KateRenderer::setCaretStyle(KateRenderer::caretStyles style)
00083 {
00084 m_caretStyle = style;
00085 }
00086
00087 void KateRenderer::setShowTabs(bool showTabs)
00088 {
00089 m_showTabs = showTabs;
00090 }
00091
00092 void KateRenderer::setTabWidth(int tabWidth)
00093 {
00094 m_tabWidth = tabWidth;
00095 }
00096
00097 bool KateRenderer::showIndentLines() const
00098 {
00099 return m_config->showIndentationLines();
00100 }
00101
00102 void KateRenderer::setShowIndentLines(bool showIndentLines)
00103 {
00104 m_config->setShowIndentationLines(showIndentLines);
00105 }
00106
00107 void KateRenderer::setIndentWidth(int indentWidth)
00108 {
00109 m_indentWidth = m_tabWidth;
00110 if (m_doc->config()->configFlags() & KateDocumentConfig::cfSpaceIndent)
00111 {
00112 m_indentWidth = indentWidth;
00113 }
00114 }
00115
00116 void KateRenderer::setShowSelections(bool showSelections)
00117 {
00118 m_showSelections = showSelections;
00119 }
00120
00121 void KateRenderer::increaseFontSizes()
00122 {
00123 QFont f ( *config()->font () );
00124 f.setPointSize (f.pointSize ()+1);
00125
00126 config()->setFont (f);
00127 }
00128
00129 void KateRenderer::decreaseFontSizes()
00130 {
00131 QFont f ( *config()->font () );
00132
00133 if ((f.pointSize ()-1) > 0)
00134 f.setPointSize (f.pointSize ()-1);
00135
00136 config()->setFont (f);
00137 }
00138
00139 bool KateRenderer::isPrinterFriendly() const
00140 {
00141 return m_printerFriendly;
00142 }
00143
00144 void KateRenderer::setPrinterFriendly(bool printerFriendly)
00145 {
00146 m_printerFriendly = printerFriendly;
00147 setShowTabs(false);
00148 setShowSelections(false);
00149 setDrawCaret(false);
00150 }
00151
00152 bool KateRenderer::paintTextLineBackground(QPainter& paint, int line, bool isCurrentLine, int xStart, int xEnd)
00153 {
00154 if (isPrinterFriendly())
00155 return false;
00156
00157
00158 KateFontStruct *fs = config()->fontStruct();
00159
00160
00161 QColor backgroundColor( config()->backgroundColor() );
00162
00163 bool selectionPainted = false;
00164 if (showSelections() && m_view->lineSelected(line))
00165 {
00166 backgroundColor = config()->selectionColor();
00167 selectionPainted = true;
00168 }
00169 else
00170 {
00171
00172 if (isCurrentLine)
00173 backgroundColor = config()->highlightedLineColor();
00174
00175
00176 int markRed = 0, markGreen = 0, markBlue = 0, markCount = 0;
00177
00178
00179 uint mrk = m_doc->mark( line );
00180 if (mrk)
00181 {
00182 for (uint bit = 0; bit < 32; bit++)
00183 {
00184 KTextEditor::MarkInterface::MarkTypes markType = (KTextEditor::MarkInterface::MarkTypes)(1<<bit);
00185 if (mrk & markType)
00186 {
00187 QColor markColor = config()->lineMarkerColor(markType);
00188
00189 if (markColor.isValid()) {
00190 markCount++;
00191 markRed += markColor.red();
00192 markGreen += markColor.green();
00193 markBlue += markColor.blue();
00194 }
00195 }
00196 }
00197 }
00198
00199 if (markCount) {
00200 markRed /= markCount;
00201 markGreen /= markCount;
00202 markBlue /= markCount;
00203 backgroundColor.setRgb(
00204 int((backgroundColor.red() * 0.9) + (markRed * 0.1)),
00205 int((backgroundColor.green() * 0.9) + (markGreen * 0.1)),
00206 int((backgroundColor.blue() * 0.9) + (markBlue * 0.1))
00207 );
00208 }
00209 }
00210
00211
00212 paint.fillRect(0, 0, xEnd - xStart, fs->fontHeight, backgroundColor);
00213
00214 return selectionPainted;
00215 }
00216
00217 void KateRenderer::paintWhitespaceMarker(QPainter &paint, uint x, uint y)
00218 {
00219 QPen penBackup( paint.pen() );
00220 paint.setPen( config()->tabMarkerColor() );
00221 paint.drawPoint(x, y);
00222 paint.drawPoint(x + 1, y);
00223 paint.drawPoint(x, y - 1);
00224 paint.setPen( penBackup );
00225 }
00226
00227
00228 void KateRenderer::paintIndentMarker(QPainter &paint, uint x, uint row)
00229 {
00230 QPen penBackup( paint.pen() );
00231 paint.setPen( config()->tabMarkerColor() );
00232
00233 const int top = paint.window().top();
00234 const int bottom = paint.window().bottom();
00235 const int h = bottom - top + 1;
00236
00237
00238 int pad = 0;
00239 if(row & 1 && h & 1) pad = 1;
00240
00241 for(int i = top; i <= bottom; i++)
00242 {
00243 if((i + pad) & 1)
00244 {
00245 paint.drawPoint(x + 2, i);
00246 }
00247 }
00248
00249 paint.setPen( penBackup );
00250 }
00251
00252
00253 void KateRenderer::paintTextLine(QPainter& paint, const KateLineRange* range, int xStart, int xEnd, const KateTextCursor* cursor, const KateBracketRange* bracketmark)
00254 {
00255 int line = range->line;
00256
00257
00258 KateTextLine::Ptr textLine = m_doc->kateTextLine(line);
00259 if (!textLine)
00260 return;
00261
00262 bool showCursor = drawCaret() && cursor && range->includesCursor(*cursor);
00263
00264 KateSuperRangeList& superRanges = m_doc->arbitraryHL()->rangesIncluding(range->line, 0);
00265
00266 int minIndent = 0;
00267
00268
00269
00270
00271 KateArbitraryHighlightRange* bracketStartRange (0L);
00272 KateArbitraryHighlightRange* bracketEndRange (0L);
00273 if (bracketmark && bracketmark->isValid()) {
00274 if (range->includesCursor(bracketmark->start())) {
00275 KateTextCursor startend = bracketmark->start();
00276 startend.setCol(startend.col()+1);
00277 bracketStartRange = new KateArbitraryHighlightRange(m_doc, bracketmark->start(), startend);
00278 bracketStartRange->setBGColor(config()->highlightedBracketColor());
00279 bracketStartRange->setBold(true);
00280 superRanges.append(bracketStartRange);
00281 }
00282
00283 if (range->includesCursor(bracketmark->end())) {
00284 KateTextCursor endend = bracketmark->end();
00285 endend.setCol(endend.col()+1);
00286 bracketEndRange = new KateArbitraryHighlightRange(m_doc, bracketmark->end(), endend);
00287 bracketEndRange->setBGColor(config()->highlightedBracketColor());
00288 bracketEndRange->setBold(true);
00289 superRanges.append(bracketEndRange);
00290 }
00291
00292 Q_ASSERT(bracketmark->start().line() <= bracketmark->end().line());
00293 if (bracketmark->start().line() < line && bracketmark->end().line() >= line)
00294 {
00295 minIndent = bracketmark->getMinIndent();
00296 }
00297 }
00298
00299
00300
00301 uint len = textLine->length();
00302 uint oldLen = len;
00303
00304
00305 bool cursorVisible = false;
00306 int cursorMaxWidth = 0;
00307
00308
00309 KateFontStruct * fs = config()->fontStruct();
00310
00311
00312
00313 bool hasSel = false;
00314 uint startSel = 0;
00315 uint endSel = 0;
00316
00317
00318 bool selectionPainted = false;
00319 bool isCurrentLine = (cursor && range->includesCursor(*cursor));
00320 selectionPainted = paintTextLineBackground(paint, line, isCurrentLine, xStart, xEnd);
00321 if (selectionPainted)
00322 {
00323 hasSel = true;
00324 startSel = 0;
00325 endSel = len + 1;
00326 }
00327
00328 int startcol = range->startCol;
00329 if (startcol > (int)len)
00330 startcol = len;
00331
00332 if (startcol < 0)
00333 startcol = 0;
00334
00335 int endcol = range->wrap ? range->endCol : -1;
00336 if (endcol < 0)
00337 len = len - startcol;
00338 else
00339 len = endcol - startcol;
00340
00341
00342 KateAttribute* attr = m_doc->highlight()->attributes(m_schema)->data();
00343
00344 const QColor *cursorColor = &attr[0].textColor();
00345
00346
00347 KateTextCursor currentPos(line, startcol);
00348 superRanges.firstBoundary(¤tPos);
00349
00350 if (showSelections() && !selectionPainted)
00351 hasSel = getSelectionBounds(line, oldLen, startSel, endSel);
00352
00353
00354 if (range->startsInvisibleBlock) {
00355 paint.setPen(QPen(config()->wordWrapMarkerColor(), 1, Qt::DashLine));
00356 paint.drawLine(0, fs->fontHeight - 1, xEnd - xStart, fs->fontHeight - 1);
00357 }
00358
00359
00360 if (range->xOffset() && range->xOffset() > xStart)
00361 {
00362 paint.fillRect(0, 0, range->xOffset() - xStart, fs->fontHeight,
00363 QBrush(config()->wordWrapMarkerColor(), QBrush::DiagCrossPattern));
00364 }
00365
00366
00367 uint xPos = range->xOffset();
00368 int cursorXPos = 0;
00369
00370
00371 if (len < 1)
00372 {
00373 if (showCursor && (cursor->col() >= int(startcol)))
00374 {
00375 cursorVisible = true;
00376 cursorXPos = xPos + cursor->col() * fs->myFontMetrics.width(QChar(' '));
00377 }
00378 }
00379 else
00380 {
00381 bool isIMSel = false;
00382 bool isIMEdit = false;
00383
00384 bool isSel = false;
00385
00386 KateAttribute customHL;
00387
00388 const QColor *curColor = 0;
00389 const QColor *oldColor = 0;
00390
00391 KateAttribute* oldAt = &attr[0];
00392
00393 uint oldXPos = xPos;
00394 uint xPosAfter = xPos;
00395
00396 KateAttribute currentHL;
00397
00398 uint blockStartCol = startcol;
00399 uint curCol = startcol;
00400 uint nextCol = curCol + 1;
00401
00402
00403 const uchar *textAttributes = textLine->attributes ();
00404 bool noAttribs = !textAttributes;
00405
00406
00407 textAttributes = textAttributes + startcol;
00408
00409 uint atLen = m_doc->highlight()->attributes(m_schema)->size();
00410
00411
00412
00413 uint trailingWhitespaceColumn = textLine->lastChar() + 1;
00414 const uint lastIndentColumn = textLine->firstChar();
00415
00416
00417 const uint spaceWidth = fs->width (QChar(' '), false, false, m_tabWidth);
00418
00419
00420 int curPos = textLine->cursorX(curCol, m_tabWidth);
00421
00422 while (curCol - startcol < len)
00423 {
00424
00425
00426
00427
00428 QChar curChar = textLine->string()[curCol];
00429
00430
00431 bool isTab = curChar == QChar('\t');
00432
00433
00434
00435 KateAttribute* curAt = (noAttribs || ((*textAttributes) >= atLen)) ? &attr[0] : &attr[*textAttributes];
00436
00437
00438
00439 xPosAfter += curAt->width(*fs, curChar, m_tabWidth);
00440
00441
00442 if (isTab)
00443 xPosAfter -= (xPosAfter % curAt->width(*fs, curChar, m_tabWidth));
00444
00445
00446
00447 if ((int)xPosAfter >= xStart)
00448 {
00449
00450 isSel = (showSelections() && hasSel && (curCol >= startSel) && (curCol < endSel));
00451
00452
00453 isIMEdit = m_view && m_view->isIMEdit( line, curCol );
00454
00455
00456 isIMSel = m_view && m_view->isIMSelection( line, curCol );
00457
00458
00459 curColor = isSel ? &(curAt->selectedTextColor()) : &(curAt->textColor());
00460
00461
00462 if (curAt != oldAt || curColor != oldColor || (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)) {
00463 if (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
00464 customHL = KateArbitraryHighlightRange::merge(superRanges.rangesIncluding(currentPos));
00465
00466 KateAttribute hl = customHL;
00467
00468 hl += *curAt;
00469
00470
00471 if (!hl.itemSet(KateAttribute::TextColor))
00472 hl.setTextColor(*curColor);
00473
00474 if (!isSel)
00475 paint.setPen(hl.textColor());
00476 else
00477 paint.setPen(hl.selectedTextColor());
00478
00479 paint.setFont(hl.font(*currentFont()));
00480
00481 if (superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
00482 superRanges.nextBoundary();
00483
00484 currentHL = hl;
00485 }
00486
00487
00488
00489
00490
00491
00492 bool renderNow = false;
00493 if ((isTab)
00494
00495 || (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == KateTextCursor(line, nextCol))
00496
00497
00498 || (curCol - startcol >= len - 1)
00499
00500
00501 || (curCol + 1 >= trailingWhitespaceColumn)
00502
00503
00504 || (showIndentLines() && curCol < lastIndentColumn)
00505
00506
00507 || ((int)xPos > xEnd)
00508
00509
00510 || (!noAttribs && curAt != &attr[*(textAttributes+1)])
00511
00512
00513 || (isSel != (hasSel && (nextCol >= startSel) && (nextCol < endSel)))
00514
00515
00516
00517 || (textLine->string()[nextCol] == QChar('\t'))
00518
00519
00520 || ( m_view && (isIMEdit != m_view->isIMEdit( line, nextCol )) )
00521
00522
00523 || ( m_view && (isIMSel != m_view->isIMSelection( line, nextCol )) )
00524 )
00525 {
00526 renderNow = true;
00527 }
00528
00529 if (renderNow)
00530 {
00531 if (!isPrinterFriendly())
00532 {
00533 bool paintBackground = true;
00534 uint width = xPosAfter - oldXPos;
00535 QColor fillColor;
00536
00537 if (isIMSel && !isTab)
00538 {
00539
00540 fillColor = m_view->colorGroup().color(QColorGroup::Foreground);
00541 }
00542 else if (isIMEdit && !isTab)
00543 {
00544
00545
00546 const QColorGroup& cg = m_view->colorGroup();
00547 int h1, s1, v1, h2, s2, v2;
00548 cg.color( QColorGroup::Base ).hsv( &h1, &s1, &v1 );
00549 cg.color( QColorGroup::Background ).hsv( &h2, &s2, &v2 );
00550 fillColor.setHsv( h1, s1, ( v1 + v2 ) / 2 );
00551 }
00552 else if (!selectionPainted && (isSel || currentHL.itemSet(KateAttribute::BGColor)))
00553 {
00554 if (isSel)
00555 {
00556 fillColor = config()->selectionColor();
00557
00558
00559
00560 if ((curCol >= len - 1) && m_view->lineEndSelected (line, endcol))
00561 width = xEnd - oldXPos;
00562 }
00563 else
00564 {
00565 fillColor = currentHL.bgColor();
00566 }
00567 }
00568 else
00569 {
00570 paintBackground = false;
00571 }
00572
00573 if (paintBackground)
00574 paint.fillRect(oldXPos - xStart, 0, width, fs->fontHeight, fillColor);
00575
00576 if (isIMSel && paintBackground && !isTab)
00577 {
00578 paint.save();
00579 paint.setPen( m_view->colorGroup().color( QColorGroup::BrightText ) );
00580 }
00581
00582
00583 if (showIndentLines() && curCol < lastIndentColumn)
00584 {
00585
00586 const int charWidth = isTab ? m_tabWidth - curPos % m_tabWidth : 1;
00587
00588
00589 int i = 0;
00590 if (curPos == 0 || curPos % m_indentWidth > 0)
00591 i = m_indentWidth - curPos % m_indentWidth;
00592
00593 for (; i < charWidth; i += m_indentWidth)
00594 {
00595
00596 paintIndentMarker(paint, xPos - xStart + i * spaceWidth, line);
00597
00598
00599 if (curPos+i == minIndent)
00600 {
00601 paintIndentMarker(paint, xPos - xStart + 1 + i * spaceWidth, line+1);
00602 }
00603 }
00604 }
00605 }
00606
00607
00608 int y = fs->fontAscent;
00609
00610
00611
00612 if (isTab || (curCol >= trailingWhitespaceColumn))
00613 {
00614
00615 static QString spaces;
00616 if (int(spaces.length()) != m_tabWidth)
00617 spaces.fill(' ', m_tabWidth);
00618
00619 paint.drawText(oldXPos-xStart, y, isTab ? spaces : QString(" "));
00620
00621 if (showTabs())
00622 {
00623
00624
00625 paintWhitespaceMarker(paint, xPos - xStart, y);
00626 }
00627
00628
00629 blockStartCol = nextCol;
00630 oldXPos = xPosAfter;
00631 }
00632 else
00633 {
00634
00635 paint.drawText(oldXPos-xStart, y, textLine->string(), blockStartCol, nextCol-blockStartCol);
00636
00637
00638 if (isIMEdit) {
00639 QRect r( oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight );
00640 paint.drawLine( r.bottomLeft(), r.bottomRight() );
00641 }
00642
00643
00644 if (isIMSel) paint.restore();
00645
00646
00647 if ((int)xPos > xEnd)
00648 break;
00649
00650
00651 blockStartCol = nextCol;
00652 oldXPos = xPosAfter;
00653
00654 }
00655 }
00656
00657
00658 if (showCursor && (cursor->col() == int(curCol)))
00659 {
00660 cursorVisible = true;
00661 cursorXPos = xPos;
00662 cursorMaxWidth = xPosAfter - xPos;
00663 cursorColor = &curAt->textColor();
00664 }
00665 }
00666 else
00667 {
00668
00669 blockStartCol = nextCol;
00670 oldXPos = xPosAfter;
00671 }
00672
00673
00674 xPos = xPosAfter;
00675
00676
00677 textAttributes++;
00678
00679
00680 oldAt = curAt;
00681 oldColor = curColor;
00682
00683
00684 curCol++;
00685 nextCol++;
00686 currentPos.setCol(currentPos.col() + 1);
00687
00688
00689 if (isTab)
00690 {
00691 curPos += m_tabWidth - (curPos % m_tabWidth);
00692 }
00693 else
00694 {
00695 curPos++;
00696 }
00697 }
00698
00699
00700
00701 if (showSelections() && hasSel && !selectionPainted && xStart >= (int)xPos && m_view->lineEndSelected(line, -1))
00702 {
00703 paint.fillRect(0, 0, xEnd-xStart, fs->fontHeight, config()->selectionColor());
00704 }
00705
00706
00707 if (showCursor && (cursor->col() >= int(curCol)))
00708 {
00709 cursorVisible = true;
00710 cursorXPos = xPos + (cursor->col() - int(curCol)) * fs->myFontMetrics.width(QChar(' '));
00711 cursorMaxWidth = xPosAfter - xPos;
00712 cursorColor = &oldAt->textColor();
00713 }
00714 }
00715
00716
00717 if (cursorVisible)
00718 {
00719 uint cursorWidth = (caretStyle() == Replace && (cursorMaxWidth > 2)) ? cursorMaxWidth : 2;
00720 paint.fillRect(cursorXPos-xStart, 0, cursorWidth, fs->fontHeight, *cursorColor);
00721 }
00722
00723
00724 if (!isPrinterFriendly() && config()->wordWrapMarker() && fs->fixedPitch())
00725 {
00726 paint.setPen( config()->wordWrapMarkerColor() );
00727 int _x = m_doc->config()->wordWrapAt() * fs->myFontMetrics.width('x') - xStart;
00728 paint.drawLine( _x,0,_x,fs->fontHeight );
00729 }
00730
00731
00732 delete bracketStartRange;
00733 delete bracketEndRange;
00734 }
00735
00736 uint KateRenderer::textWidth(const KateTextLine::Ptr &textLine, int cursorCol)
00737 {
00738 if (!textLine)
00739 return 0;
00740
00741 const int len = textLine->length();
00742
00743 if (cursorCol < 0)
00744 cursorCol = len;
00745
00746 KateFontStruct *fs = config()->fontStruct();
00747
00748 const QChar *unicode = textLine->text();
00749 const QString &textString = textLine->string();
00750
00751 int x = 0;
00752 int width;
00753 for (int z = 0; z < cursorCol; z++) {
00754 KateAttribute* a = attribute(textLine->attribute(z));
00755
00756 if (z < len) {
00757 width = a->width(*fs, textString, z, m_tabWidth);
00758 } else {
00759
00760
00761 width = a->width(*fs, QChar(' '), m_tabWidth);
00762 }
00763
00764 x += width;
00765
00766 if (z < len && unicode[z] == QChar('\t'))
00767 x -= x % width;
00768 }
00769
00770 return x;
00771 }
00772
00773 uint KateRenderer::textWidth(const KateTextLine::Ptr &textLine, uint startcol, uint maxwidth, bool *needWrap, int *endX)
00774 {
00775 KateFontStruct *fs = config()->fontStruct();
00776 uint x = 0;
00777 uint endcol = startcol;
00778 int endX2 = 0;
00779 int lastWhiteSpace = -1;
00780 int lastWhiteSpaceX = -1;
00781
00782
00783
00784 bool foundNonWhitespace = startcol != 0;
00785 bool foundWhitespaceAfterNonWhitespace = startcol != 0;
00786
00787 *needWrap = false;
00788
00789 const uint len = textLine->length();
00790 const QChar *unicode = textLine->text();
00791 const QString &textString = textLine->string();
00792
00793 uint z = startcol;
00794 for (; z < len; z++)
00795 {
00796 KateAttribute* a = attribute(textLine->attribute(z));
00797 int width = a->width(*fs, textString, z, m_tabWidth);
00798 Q_ASSERT(width);
00799 x += width;
00800
00801
00802
00803 if (unicode[z] == QChar('\t'))
00804 x -= x % width;
00805
00806 if (unicode[z].isSpace())
00807 {
00808 lastWhiteSpace = z+1;
00809 lastWhiteSpaceX = x;
00810
00811 if (foundNonWhitespace)
00812 foundWhitespaceAfterNonWhitespace = true;
00813 }
00814 else
00815 {
00816 if (!foundWhitespaceAfterNonWhitespace) {
00817 foundNonWhitespace = true;
00818
00819 lastWhiteSpace = z+1;
00820 lastWhiteSpaceX = x;
00821 }
00822 }
00823
00824 if (x <= maxwidth)
00825 {
00826 if (lastWhiteSpace > -1)
00827 {
00828 endcol = lastWhiteSpace;
00829 endX2 = lastWhiteSpaceX;
00830 }
00831 else
00832 {
00833 endcol = z+1;
00834 endX2 = x;
00835 }
00836 }
00837 else if (z == startcol)
00838 {
00839
00840
00841 endcol = z+1;
00842 endX2 = x;
00843 }
00844
00845 if (x >= maxwidth)
00846 {
00847 *needWrap = true;
00848 break;
00849 }
00850 }
00851
00852 if (*needWrap)
00853 {
00854 if (endX)
00855 *endX = endX2;
00856
00857 return endcol;
00858 }
00859 else
00860 {
00861 if (endX)
00862 *endX = x;
00863
00864 return z+1;
00865 }
00866 }
00867
00868 uint KateRenderer::textWidth(const KateTextCursor &cursor)
00869 {
00870 int line = kMin(kMax(0, cursor.line()), (int)m_doc->numLines() - 1);
00871 int col = kMax(0, cursor.col());
00872
00873 return textWidth(m_doc->kateTextLine(line), col);
00874 }
00875
00876 uint KateRenderer::textWidth( KateTextCursor &cursor, int xPos, uint startCol)
00877 {
00878 bool wrapCursor = m_view->wrapCursor();
00879 int x, oldX;
00880
00881 KateFontStruct *fs = config()->fontStruct();
00882
00883 if (cursor.line() < 0) cursor.setLine(0);
00884 if (cursor.line() > (int)m_doc->lastLine()) cursor.setLine(m_doc->lastLine());
00885 KateTextLine::Ptr textLine = m_doc->kateTextLine(cursor.line());
00886
00887 if (!textLine) return 0;
00888
00889 const uint len = textLine->length();
00890 const QChar *unicode = textLine->text();
00891 const QString &textString = textLine->string();
00892
00893 x = oldX = 0;
00894 uint z = startCol;
00895 while (x < xPos && (!wrapCursor || z < len)) {
00896 oldX = x;
00897
00898 KateAttribute* a = attribute(textLine->attribute(z));
00899
00900 int width = 0;
00901
00902 if (z < len)
00903 width = a->width(*fs, textString, z, m_tabWidth);
00904 else
00905 width = a->width(*fs, QChar(' '), m_tabWidth);
00906
00907 x += width;
00908
00909 if (z < len && unicode[z] == QChar('\t'))
00910 x -= x % width;
00911
00912 z++;
00913 }
00914 if (xPos - oldX < x - xPos && z > 0) {
00915 z--;
00916 x = oldX;
00917 }
00918 cursor.setCol(z);
00919 return x;
00920 }
00921
00922 const QFont *KateRenderer::currentFont()
00923 {
00924 return config()->font();
00925 }
00926
00927 const QFontMetrics* KateRenderer::currentFontMetrics()
00928 {
00929 return config()->fontMetrics();
00930 }
00931
00932 uint KateRenderer::textPos(uint line, int xPos, uint startCol, bool nearest)
00933 {
00934 return textPos(m_doc->kateTextLine(line), xPos, startCol, nearest);
00935 }
00936
00937 uint KateRenderer::textPos(const KateTextLine::Ptr &textLine, int xPos, uint startCol, bool nearest)
00938 {
00939 Q_ASSERT(textLine);
00940 if (!textLine)
00941 return 0;
00942
00943 KateFontStruct *fs = config()->fontStruct();
00944
00945 int x, oldX;
00946 x = oldX = 0;
00947
00948 uint z = startCol;
00949 const uint len = textLine->length();
00950 const QString &textString = textLine->string();
00951
00952 while ( (x < xPos) && (z < len)) {
00953 oldX = x;
00954
00955 KateAttribute* a = attribute(textLine->attribute(z));
00956 x += a->width(*fs, textString, z, m_tabWidth);
00957
00958 z++;
00959 }
00960 if ( ( (! nearest) || xPos - oldX < x - xPos ) && z > 0 ) {
00961 z--;
00962
00963 }
00964 return z;
00965 }
00966
00967 uint KateRenderer::fontHeight()
00968 {
00969 return config()->fontStruct ()->fontHeight;
00970 }
00971
00972 uint KateRenderer::documentHeight()
00973 {
00974 return m_doc->numLines() * fontHeight();
00975 }
00976
00977 bool KateRenderer::getSelectionBounds(uint line, uint lineLength, uint &start, uint &end)
00978 {
00979 bool hasSel = false;
00980
00981 if (m_view->hasSelection() && !m_view->blockSelectionMode())
00982 {
00983 if (m_view->lineIsSelection(line))
00984 {
00985 start = m_view->selStartCol();
00986 end = m_view->selEndCol();
00987 hasSel = true;
00988 }
00989 else if ((int)line == m_view->selStartLine())
00990 {
00991 start = m_view->selStartCol();
00992 end = lineLength;
00993 hasSel = true;
00994 }
00995 else if ((int)line == m_view->selEndLine())
00996 {
00997 start = 0;
00998 end = m_view->selEndCol();
00999 hasSel = true;
01000 }
01001 }
01002 else if (m_view->lineHasSelected(line))
01003 {
01004 start = m_view->selStartCol();
01005 end = m_view->selEndCol();
01006 hasSel = true;
01007 }
01008
01009 if (start > end) {
01010 int temp = end;
01011 end = start;
01012 start = temp;
01013 }
01014
01015 return hasSel;
01016 }
01017
01018 void KateRenderer::updateConfig ()
01019 {
01020
01021 updateAttributes ();
01022
01023 if (m_view)
01024 m_view->updateRendererConfig();
01025 }
01026
01027 uint KateRenderer::spaceWidth()
01028 {
01029 return attribute(0)->width(*config()->fontStruct(), QChar(' '), m_tabWidth);
01030 }
01031
01032