00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "katerenderer.h"
00024
00025 #include "katedocument.h"
00026 #include "kateconfig.h"
00027 #include "katehighlight.h"
00028 #include "kateview.h"
00029 #include "katerenderrange.h"
00030 #include "katetextlayout.h"
00031
00032 #include <limits.h>
00033
00034 #include <kdebug.h>
00035
00036 #include <QtGui/QPainter>
00037 #include <QtGui/QTextLine>
00038 #include <QtCore/QStack>
00039 #include <QtGui/QBrush>
00040
00041 static const QChar tabChar('\t');
00042 static const QChar spaceChar(' ');
00043
00044 KateRenderer::KateRenderer(KateDocument* doc, KateView *view)
00045 : m_doc(doc), m_view (view), m_caretStyle(KateRenderer::Line)
00046 , m_drawCaret(true)
00047 , m_showSelections(true)
00048 , m_showTabs(true)
00049 , m_showSpaces(true)
00050 , m_printerFriendly(false)
00051 , m_dynamicRegion(doc)
00052 {
00053 m_config = new KateRendererConfig (this);
00054
00055 m_tabWidth = m_doc->config()->tabWidth();
00056 m_indentWidth = m_doc->config()->indentationWidth();
00057
00058 updateAttributes ();
00059 }
00060
00061 KateRenderer::~KateRenderer()
00062 {
00063 delete m_config;
00064 }
00065
00066 void KateRenderer::updateAttributes ()
00067 {
00068 m_attributes = m_doc->highlight()->attributes (config()->schema ());
00069 }
00070
00071 KTextEditor::Attribute::Ptr KateRenderer::attribute(uint pos) const
00072 {
00073 if (pos < (uint)m_attributes.count())
00074 return m_attributes[pos];
00075
00076 return m_attributes[0];
00077 }
00078
00079 KTextEditor::Attribute::Ptr KateRenderer::specificAttribute( int context ) const
00080 {
00081 if (context >= 0 && context < m_attributes.count())
00082 return m_attributes[context];
00083
00084 return m_attributes[0];
00085 }
00086
00087 void KateRenderer::setDrawCaret(bool drawCaret)
00088 {
00089 m_drawCaret = drawCaret;
00090 }
00091
00092 void KateRenderer::setCaretStyle(KateRenderer::caretStyles style)
00093 {
00094 m_caretStyle = style;
00095 }
00096
00097 void KateRenderer::setShowTabs(bool showTabs)
00098 {
00099 m_showTabs = showTabs;
00100 }
00101
00102 void KateRenderer::setShowTrailingSpaces(bool showSpaces)
00103 {
00104 m_showSpaces = showSpaces;
00105 }
00106
00107 void KateRenderer::setTabWidth(int tabWidth)
00108 {
00109 m_tabWidth = tabWidth;
00110 }
00111
00112 bool KateRenderer::showIndentLines() const
00113 {
00114 return m_config->showIndentationLines();
00115 }
00116
00117 void KateRenderer::setShowIndentLines(bool showIndentLines)
00118 {
00119 m_config->setShowIndentationLines(showIndentLines);
00120 }
00121
00122 void KateRenderer::setIndentWidth(int indentWidth)
00123 {
00124 m_indentWidth = indentWidth;
00125 }
00126
00127 void KateRenderer::setShowSelections(bool showSelections)
00128 {
00129 m_showSelections = showSelections;
00130 }
00131
00132 void KateRenderer::increaseFontSizes()
00133 {
00134 QFont f ( config()->font () );
00135 f.setPointSize (f.pointSize ()+1);
00136
00137 config()->setFont (f);
00138 }
00139
00140 void KateRenderer::decreaseFontSizes()
00141 {
00142 QFont f ( config()->font () );
00143
00144 if ((f.pointSize ()-1) > 0)
00145 f.setPointSize (f.pointSize ()-1);
00146
00147 config()->setFont (f);
00148 }
00149
00150 bool KateRenderer::isPrinterFriendly() const
00151 {
00152 return m_printerFriendly;
00153 }
00154
00155 void KateRenderer::setPrinterFriendly(bool printerFriendly)
00156 {
00157 m_printerFriendly = printerFriendly;
00158 setShowTabs(false);
00159 setShowTrailingSpaces(false);
00160 setShowSelections(false);
00161 setDrawCaret(false);
00162 }
00163
00164 void KateRenderer::paintTextLineBackground(QPainter& paint, KateLineLayoutPtr layout, int currentViewLine, int xStart, int xEnd)
00165 {
00166 if (isPrinterFriendly())
00167 return;
00168
00169
00170 QColor backgroundColor( config()->backgroundColor() );
00171
00172
00173 QColor currentLineColor = config()->highlightedLineColor();
00174
00175
00176 int markRed = 0, markGreen = 0, markBlue = 0, markCount = 0;
00177
00178
00179 uint mrk = m_doc->mark( layout->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 paint.fillRect(0, 0, xEnd - xStart, config()->fontMetrics().height() * layout->viewLineCount(), backgroundColor);
00212
00213
00214 if (currentViewLine != -1) {
00215 if (markCount) {
00216 markRed /= markCount;
00217 markGreen /= markCount;
00218 markBlue /= markCount;
00219 currentLineColor.setRgb(
00220 int((currentLineColor.red() * 0.9) + (markRed * 0.1)),
00221 int((currentLineColor.green() * 0.9) + (markGreen * 0.1)),
00222 int((currentLineColor.blue() * 0.9) + (markBlue * 0.1))
00223 );
00224 }
00225
00226 paint.fillRect(0, config()->fontMetrics().height() * currentViewLine, xEnd - xStart, config()->fontMetrics().height(), currentLineColor);
00227 }
00228 }
00229
00230 void KateRenderer::paintTabstop(QPainter &paint, qreal x, qreal y)
00231 {
00232 QPen penBackup( paint.pen() );
00233 QPen pen( config()->tabMarkerColor() );
00234 pen.setWidth(qMax(1u, spaceWidth() / 10));
00235 paint.setPen( pen );
00236 paint.setRenderHint(QPainter::Antialiasing, false);
00237
00238 int dist = spaceWidth() * 0.3;
00239 QPoint points[8];
00240 points[0] = QPoint(x - dist, y - dist);
00241 points[1] = QPoint(x, y);
00242 points[2] = QPoint(x, y);
00243 points[3] = QPoint(x - dist, y + dist);
00244 x += spaceWidth() / 3.0;
00245 points[4] = QPoint(x - dist, y - dist);
00246 points[5] = QPoint(x, y);
00247 points[6] = QPoint(x, y);
00248 points[7] = QPoint(x - dist, y + dist);
00249 paint.drawLines(points, 4);
00250 paint.setPen( penBackup );
00251 }
00252
00253 void KateRenderer::paintTrailingSpace(QPainter &paint, qreal x, qreal y)
00254 {
00255 QPen penBackup( paint.pen() );
00256 QPen pen( config()->tabMarkerColor() );
00257 pen.setWidthF(spaceWidth() / 3.5);
00258 pen.setCapStyle(Qt::RoundCap);
00259 paint.setPen( pen );
00260
00261 paint.drawPoint( QPointF(x, y) );
00262 paint.setPen( penBackup );
00263 }
00264
00265 void KateRenderer::paintIndentMarker(QPainter &paint, uint x, uint row)
00266 {
00267 QPen penBackup( paint.pen() );
00268 paint.setPen( config()->tabMarkerColor() );
00269
00270 const int height = config()->fontMetrics().height();
00271 const int top = 0;
00272 const int bottom = height-1;
00273 const int h = bottom - top + 1;
00274
00275
00276 int pad = 0;
00277 if(row & 1 && h & 1) pad = 1;
00278
00279 for(int i = top; i <= bottom; i++)
00280 {
00281 if((i + pad) & 1)
00282 {
00283 paint.drawPoint(x + 2, i);
00284 }
00285 }
00286
00287 paint.setPen( penBackup );
00288 }
00289
00290 QList<QTextLayout::FormatRange> KateRenderer::decorationsForLine( const KateTextLine::Ptr& textLine, int line, bool selectionsOnly, KateRenderRange* completionHighlight, bool completionSelected ) const
00291 {
00292 QList<QTextLayout::FormatRange> newHighlight;
00293
00294
00295 if (selectionsOnly || textLine->attributesList().count() || m_view->externalHighlights().count() || m_view->internalHighlights().count() || m_doc->documentHighlights().count()) {
00296 RenderRangeList renderRanges;
00297
00298
00299 NormalRenderRange* inbuiltHighlight = new NormalRenderRange();
00300 const QVector<int> &al = textLine->attributesList();
00301 for (int i = 0; i+2 < al.count(); i += 3) {
00302 inbuiltHighlight->addRange(new KTextEditor::Range(KTextEditor::Cursor(line, al[i]), al[i+1]), specificAttribute(al[i+2]));
00303 }
00304 renderRanges.append(inbuiltHighlight);
00305
00306 if (!completionHighlight) {
00307
00308 renderRanges.appendRanges(m_view->internalHighlights(), selectionsOnly, view());
00309 renderRanges.appendRanges(m_view->externalHighlights(), selectionsOnly, view());
00310
00311 } else {
00312
00313 renderRanges.append(completionHighlight);
00314 }
00315
00316
00317 if ((selectionsOnly && showSelections() && m_view->selection()) || (completionHighlight && completionSelected) || m_view->blockSelection()) {
00318 NormalRenderRange* selectionHighlight = new NormalRenderRange();
00319
00320
00321 static KTextEditor::Attribute::Ptr backgroundAttribute;
00322 if (!backgroundAttribute)
00323 backgroundAttribute = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute());
00324
00325 backgroundAttribute->setBackground(config()->selectionColor());
00326
00327
00328 if (completionHighlight && completionSelected)
00329 selectionHighlight->addRange(new KTextEditor::Range(line, 0, line + 1, 0), backgroundAttribute);
00330 else
00331 if(m_view->blockSelection() && m_view->selectionRange().overlapsLine(line))
00332 selectionHighlight->addRange(new KTextEditor::Range(line, m_view->selectionRange().start().column(), line, m_view->selectionRange().end().column()), backgroundAttribute);
00333 else
00334 selectionHighlight->addRange(new KTextEditor::Range(m_view->selectionRange()), backgroundAttribute);
00335
00336 renderRanges.append(selectionHighlight);
00337 }
00338
00339 KTextEditor::Cursor currentPosition, endPosition;
00340
00341
00342 if (selectionsOnly) {
00343 if(m_view->blockSelection()) {
00344 int startColumn = m_view->selectionRange().start().column();
00345 int endColumn = m_view->selectionRange().end().column();
00346 currentPosition = KTextEditor::Cursor(line, qMin(startColumn, endColumn));
00347 endPosition = KTextEditor::Cursor(line, qMax(startColumn, endColumn));
00348 } else {
00349 KTextEditor::Range rangeNeeded = m_view->selectionRange().encompass(m_dynamicRegion.boundingRange());
00350 rangeNeeded &= KTextEditor::Range(line, 0, line + 1, 0);
00351
00352 currentPosition = qMax(KTextEditor::Cursor(line, 0), rangeNeeded.start());
00353 endPosition = qMin(KTextEditor::Cursor(line + 1, 0), rangeNeeded.end());
00354 }
00355 } else {
00356 currentPosition = KTextEditor::Cursor(line, 0);
00357 endPosition = KTextEditor::Cursor(line + 1, 0);
00358 }
00359
00360
00361
00362 while (currentPosition < endPosition) {
00363 renderRanges.advanceTo(currentPosition);
00364
00365 if (!renderRanges.hasAttribute()) {
00366
00367 currentPosition = renderRanges.nextBoundary();
00368 continue;
00369 }
00370
00371 KTextEditor::Cursor nextPosition = renderRanges.nextBoundary();
00372
00373
00374 QTextLayout::FormatRange fr;
00375 fr.start = currentPosition.column();
00376
00377 if (nextPosition < endPosition || endPosition.line() <= line) {
00378 fr.length = nextPosition.column() - currentPosition.column();
00379
00380 } else {
00381
00382 fr.length = textLine->length() - currentPosition.column() + 1;
00383 }
00384
00385 KTextEditor::Attribute::Ptr a = renderRanges.generateAttribute();
00386 if(a) {
00387 fr.format = *a;
00388
00389 if(selectionsOnly) {
00390 if(m_view->blockSelection()) {
00391 int minSelectionColumn = qMin(m_view->selectionRange().start().column(), m_view->selectionRange().end().column());
00392 int maxSelectionColumn = qMax(m_view->selectionRange().start().column(), m_view->selectionRange().end().column());
00393
00394 if(currentPosition.column() >= minSelectionColumn && currentPosition.column() < maxSelectionColumn)
00395 assignSelectionBrushesFromAttribute(fr, *a);
00396
00397 } else if (m_view->selection() && m_view->selectionRange().contains(currentPosition)) {
00398 assignSelectionBrushesFromAttribute(fr, *a);
00399 }
00400 }
00401 }
00402
00403 newHighlight.append(fr);
00404
00405 currentPosition = nextPosition;
00406 }
00407
00408 if (completionHighlight)
00409
00410 renderRanges.removeAll(completionHighlight);
00411
00412 qDeleteAll(renderRanges);
00413 }
00414
00415 return newHighlight;
00416 }
00417
00418 void KateRenderer::assignSelectionBrushesFromAttribute(QTextLayout::FormatRange& target, const KTextEditor::Attribute& attribute) const
00419 {
00420 if(attribute.hasProperty(KTextEditor::Attribute::SelectedForeground)) {
00421 target.format.setForeground(attribute.selectedForeground());
00422 }
00423 if(attribute.hasProperty(KTextEditor::Attribute::SelectedBackground)) {
00424 target.format.setBackground(attribute.selectedBackground());
00425 }
00426 }
00427
00428
00429
00430
00431
00432
00433 void KateRenderer::paintTextLine(QPainter& paint, KateLineLayoutPtr range, int xStart, int xEnd, const KTextEditor::Cursor* cursor)
00434 {
00435 Q_ASSERT(range->isValid());
00436
00437
00438
00439
00440 const QFontMetrics& fm = config()->fontMetrics();
00441
00442 int currentViewLine = -1;
00443 if (cursor && cursor->line() == range->line())
00444 currentViewLine = range->viewLineForColumn(cursor->column());
00445
00446 paintTextLineBackground(paint, range, currentViewLine, xStart, xEnd);
00447
00448
00449 if (range->startsInvisibleBlock()) {
00450 paint.setRenderHint(QPainter::Antialiasing, false);
00451 QPen pen(config()->wordWrapMarkerColor());
00452 pen.setCosmetic(true);
00453 pen.setStyle(Qt::DashLine);
00454 QVector<qreal> dash = pen.dashPattern();
00455 pen.setDashOffset(xStart);
00456 pen.setDashPattern(dash);
00457 paint.setPen(pen);
00458 paint.drawLine(0, (fm.height() * range->viewLineCount()) - 1, xEnd - xStart, (fm.height() * range->viewLineCount()) - 1);
00459 }
00460
00461 if (range->layout()) {
00462 QVector<QTextLayout::FormatRange> additionalFormats;
00463 if (range->length() > 0) {
00464
00465
00466
00467 paint.setPen(attribute(KateExtendedAttribute::dsNormal)->foreground().color());
00468
00469 if (m_dynamicRegion.boundingRange().isValid() || (m_view->selection() && showSelections() && m_view->selectionRange().overlapsLine(range->line()))) {
00470
00471 additionalFormats = decorationsForLine(range->textLine(), range->line(), true).toVector();
00472 range->layout()->draw(&paint, QPoint(-xStart,0), additionalFormats);
00473
00474 } else {
00475 range->layout()->draw(&paint, QPoint(-xStart,0));
00476 }
00477 }
00478
00479 QBrush backgroundBrush;
00480 bool backgroundBrushSet = false;
00481
00482
00483 QListIterator<QTextLayout::FormatRange> it = range->layout()->additionalFormats();
00484 QVectorIterator<QTextLayout::FormatRange> it2 = additionalFormats;
00485 for (int i = 0; i < range->viewLineCount(); ++i) {
00486 KateTextLayout line = range->viewLine(i);
00487
00488
00489 backgroundBrushSet = false;
00490 while (it2.hasNext()) {
00491 const QTextLayout::FormatRange& fr = it2.peekNext();
00492 if (fr.start > line.endCol())
00493 goto backgroundDetermined;
00494
00495 if (fr.start + fr.length > line.endCol()) {
00496 if (fr.format.hasProperty(QTextFormat::BackgroundBrush)) {
00497 backgroundBrushSet = true;
00498 backgroundBrush = fr.format.background();
00499 }
00500
00501 goto backgroundDetermined;
00502 }
00503
00504 it2.next();
00505 }
00506
00507 while (it.hasNext()) {
00508 const QTextLayout::FormatRange& fr = it.peekNext();
00509 if (fr.start > line.endCol())
00510 break;
00511
00512 if (fr.start + fr.length > line.endCol()) {
00513 if (fr.format.hasProperty(QTextFormat::BackgroundBrush)) {
00514 backgroundBrushSet = true;
00515 backgroundBrush = fr.format.background();
00516 }
00517
00518 break;
00519 }
00520
00521 it.next();
00522 }
00523
00524 backgroundDetermined:
00525
00526
00527 if (!m_printerFriendly ) {
00528 bool draw = false;
00529 QBrush drawBrush;
00530 if (m_view->selection() && !m_view->blockSelection() && m_view->lineEndSelected(line.end(true))) {
00531 draw = true;
00532 drawBrush = config()->selectionColor();
00533 } else if (backgroundBrushSet && !m_view->blockSelection()) {
00534 draw = true;
00535 drawBrush = backgroundBrush;
00536 }
00537
00538 if (draw) {
00539 int fillStartX = line.endX() - line.startX() + line.xOffset() - xStart;
00540 int fillStartY = fm.height() * i;
00541 int width= xEnd - xStart - fillStartX;
00542 int height= fm.height();
00543
00544
00545 if (range->layout()->textOption().alignment() == Qt::AlignRight)
00546 fillStartX = 0;
00547
00548 QRect area(fillStartX, fillStartY, width, height);
00549 paint.fillRect(area, drawBrush);
00550 }
00551 }
00552
00553 if (showIndentLines() && i == 0)
00554 {
00555 const int w = spaceWidth();
00556 const int lastIndentColumn = range->textLine()->indentDepth(m_tabWidth);
00557
00558 for (int x = m_indentWidth; x < lastIndentColumn; x += m_indentWidth)
00559 {
00560 paintIndentMarker(paint, x * w + 1 - xStart, range->line());
00561 }
00562 }
00563
00564
00565 if (showTabs() || showTrailingSpaces()) {
00566 const QString& text = range->textLine()->string();
00567 int y = fm.height() * i + fm.ascent() - fm.strikeOutPos();
00568
00569 if (showTabs()) {
00570 int tabIndex = text.indexOf(tabChar, line.startCol());
00571 while (tabIndex != -1 && tabIndex < line.endCol()) {
00572 paintTabstop(paint, line.lineLayout().cursorToX(tabIndex) - xStart + spaceWidth()/2.0, y);
00573 tabIndex = text.indexOf(tabChar, tabIndex + 1);
00574 }
00575 }
00576
00577 if (showTrailingSpaces()) {
00578 int spaceIndex = line.endCol() - 1;
00579 int trailingPos = range->textLine()->lastChar();
00580 if (trailingPos < 0)
00581 trailingPos = 0;
00582 if (spaceIndex >= trailingPos) {
00583 while (spaceIndex >= line.startCol() && text.at(spaceIndex).isSpace()) {
00584 if (text.at(spaceIndex) != '\t' || !showTabs())
00585 paintTrailingSpace(paint, line.lineLayout().cursorToX(spaceIndex) - xStart + spaceWidth()/2.0, y);
00586 --spaceIndex;
00587 }
00588 }
00589 }
00590 }
00591 }
00592
00593
00594 if ( (range->viewLineCount() > 1) && range->shiftX() && (range->shiftX() > xStart) )
00595 {
00596 if (backgroundBrushSet)
00597 paint.fillRect(0, fm.height(), range->shiftX() - xStart, fm.height() * (range->viewLineCount() - 1),
00598 backgroundBrush);
00599 paint.fillRect(0, fm.height(), range->shiftX() - xStart, fm.height() * (range->viewLineCount() - 1),
00600 QBrush(config()->wordWrapMarkerColor(), Qt::Dense4Pattern));
00601 }
00602
00603
00604 if (drawCaret() && cursor && range->includesCursor(*cursor)) {
00605
00606 int caretWidth = 2;
00607 QTextLine line = range->layout()->lineForTextPosition(cursor->column());
00608 if (caretStyle() == Block || (m_view->viInputMode() && m_view->getCurrentViMode() != InsertMode)) {
00609 if (line.isValid() && cursor->column() < range->length()) {
00610 caretWidth = int(line.cursorToX(cursor->column() + 1) - line.cursorToX(cursor->column()));
00611 if (caretWidth < 0)
00612 caretWidth = -caretWidth;
00613
00614 } else {
00615 caretWidth = spaceWidth();
00616 }
00617 }
00618
00619 QColor c;
00620
00621 if (m_caretOverrideColor.isValid()) {
00622 c = m_caretOverrideColor;
00623
00624 } else {
00625
00626 foreach (const QTextLayout::FormatRange &r, range->layout()->additionalFormats()) {
00627 if ( (r.start <= cursor->column() ) && ( (r.start + r.length) > cursor->column()) ) {
00628
00629 QBrush foregroundBrush = r.format.foreground();
00630 if (foregroundBrush != Qt::NoBrush) {
00631 c = r.format.foreground().color();
00632 }
00633 break;
00634 }
00635 }
00636
00637
00638 if (!c.isValid())
00639 c = attribute(KateExtendedAttribute::dsNormal)->foreground().color();
00640 }
00641
00642
00643 if (m_view->viInputMode() && m_view->getCurrentViMode() != InsertMode ) {
00644 c.setAlpha(128);
00645 }
00646
00647 if (cursor->column() <= range->length()) {
00648 paint.save();
00649 paint.setPen(QPen(c, caretWidth));
00650
00651
00652 paint.setClipRect(0, line.lineNumber() * fm.height(), xEnd - xStart, fm.height());
00653
00654 range->layout()->drawCursor(&paint, QPoint(-xStart,0), cursor->column(), caretWidth);
00655
00656 paint.restore();
00657
00658 } else {
00659
00660 const KateTextLayout& lastLine = range->viewLine(range->viewLineCount() - 1);
00661 int x = range->widthOfLastLine() + spaceWidth() * (cursor->column() - range->length());
00662 if ( (x >= xStart) && (x <= xEnd))
00663 paint.fillRect(x-xStart, (int)lastLine.lineLayout().y(), caretWidth, fm.height(), c);
00664 }
00665 }
00666 }
00667
00668
00669 if ((!isPrinterFriendly()) && config()->wordWrapMarker() && QFontInfo(config()->font()).fixedPitch())
00670 {
00671 paint.setPen( config()->wordWrapMarkerColor() );
00672 int _x = m_doc->config()->wordWrapAt() * fm.width('x') - xStart;
00673 paint.drawLine( _x,0,_x,fm.height() );
00674 }
00675 }
00676
00677 const QFont& KateRenderer::currentFont() const
00678 {
00679 return config()->font();
00680 }
00681
00682 const QFontMetrics& KateRenderer::currentFontMetrics() const
00683 {
00684 return config()->fontMetrics();
00685 }
00686
00687 uint KateRenderer::fontHeight()
00688 {
00689 return config()->fontMetrics().height();
00690 }
00691
00692 uint KateRenderer::documentHeight()
00693 {
00694 return m_doc->lines() * fontHeight();
00695 }
00696
00697 bool KateRenderer::getSelectionBounds(int line, int lineLength, int &start, int &end) const
00698 {
00699 bool hasSel = false;
00700
00701 if (m_view->selection() && !m_view->blockSelectionMode())
00702 {
00703 if (m_view->lineIsSelection(line))
00704 {
00705 start = m_view->selectionRange().start().column();
00706 end = m_view->selectionRange().end().column();
00707 hasSel = true;
00708 }
00709 else if (line == m_view->selectionRange().start().line())
00710 {
00711 start = m_view->selectionRange().start().column();
00712 end = lineLength;
00713 hasSel = true;
00714 }
00715 else if (m_view->selectionRange().containsLine(line))
00716 {
00717 start = 0;
00718 end = lineLength;
00719 hasSel = true;
00720 }
00721 else if (line == m_view->selectionRange().end().line())
00722 {
00723 start = 0;
00724 end = m_view->selectionRange().end().column();
00725 hasSel = true;
00726 }
00727 }
00728 else if (m_view->lineHasSelected(line))
00729 {
00730 start = m_view->selectionRange().start().column();
00731 end = m_view->selectionRange().end().column();
00732 hasSel = true;
00733 }
00734
00735 if (start > end) {
00736 int temp = end;
00737 end = start;
00738 start = temp;
00739 }
00740
00741 return hasSel;
00742 }
00743
00744 void KateRenderer::updateConfig ()
00745 {
00746
00747 updateAttributes ();
00748
00749 if (m_view)
00750 m_view->updateRendererConfig();
00751 }
00752
00753 uint KateRenderer::spaceWidth() const
00754 {
00755 return config()->fontMetrics().width(spaceChar);
00756 }
00757
00758 void KateRenderer::layoutLine(KateLineLayoutPtr lineLayout, int maxwidth, bool cacheLayout) const
00759 {
00760
00761
00762 KateTextLine::Ptr textLine = lineLayout->textLine();
00763 Q_ASSERT(textLine);
00764
00765 QTextLayout* l = lineLayout->layout();
00766 if (!l) {
00767 l = new QTextLayout(textLine->string(), config()->font());
00768 } else {
00769 l->setText(textLine->string());
00770 l->setFont(config()->font());
00771 }
00772
00773 l->setCacheEnabled(cacheLayout);
00774
00775
00776
00777
00778 QTextOption opt;
00779 opt.setFlags(QTextOption::IncludeTrailingSpaces);
00780 opt.setTabStop(m_tabWidth * config()->fontMetrics().width(spaceChar));
00781 opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
00782
00783
00784
00785
00786
00787
00788
00789
00790 if (isLineRightToLeft(lineLayout)) {
00791 opt.setAlignment( Qt::AlignRight );
00792 opt.setTextDirection( Qt::RightToLeft );
00793 }
00794 else {
00795 opt.setAlignment( Qt::AlignLeft );
00796 opt.setTextDirection( Qt::LeftToRight );
00797 }
00798
00799 l->setTextOption(opt);
00800
00801
00802 l->setAdditionalFormats(decorationsForLine(textLine, lineLayout->line()));
00803
00804
00805 l->beginLayout();
00806
00807 int height = 0;
00808 int shiftX = 0;
00809
00810 bool needShiftX = (maxwidth != -1)
00811 && (m_view->config()->dynWordWrapAlignIndent() > 0);
00812
00813 forever {
00814 QTextLine line = l->createLine();
00815 if (!line.isValid())
00816 break;
00817
00818 if (maxwidth > 0)
00819 line.setLineWidth(maxwidth);
00820
00821 line.setPosition(QPoint(line.lineNumber() ? shiftX : 0, height));
00822
00823 if (needShiftX) {
00824 needShiftX = false;
00825
00826 int pos = textLine->nextNonSpaceChar(0);
00827
00828 if (pos > 0) {
00829 shiftX = (int)line.cursorToX(pos);
00830 }
00831
00832
00833 if (shiftX > ((double)maxwidth / 100 * m_view->config()->dynWordWrapAlignIndent()))
00834 shiftX = 0;
00835
00836
00837 maxwidth -= shiftX;
00838
00839 lineLayout->setShiftX(shiftX);
00840 }
00841
00842 height += config()->fontMetrics().height();
00843 }
00844
00845 l->endLayout();
00846
00847 lineLayout->setLayout(l);
00848 }
00849
00850
00851
00852
00853
00854
00855
00856 bool KateRenderer::isLineRightToLeft( KateLineLayoutPtr lineLayout ) const
00857 {
00858 QString s = lineLayout->textLine()->string();
00859 int i = 0;
00860
00861
00862 while( i != s.length() )
00863 {
00864 QChar c = s.at(i);
00865
00866 switch(c.direction()) {
00867 case QChar::DirL:
00868 case QChar::DirLRO:
00869 case QChar::DirLRE:
00870 return false;
00871
00872 case QChar::DirR:
00873 case QChar::DirAL:
00874 case QChar::DirRLO:
00875 case QChar::DirRLE:
00876 return true;
00877
00878 default:
00879 break;
00880 }
00881 i ++;
00882 }
00883
00884 return false;
00885 #if 0
00886
00887 QWidget* display = qobject_cast<QWidget*>(view()->parent());
00888 if (!display)
00889 return false;
00890 return display->layoutDirection() == Qt::RightToLeft;
00891 #endif
00892 }
00893
00894 int KateRenderer::cursorToX(const KateTextLayout& range, int col) const
00895 {
00896 return cursorToX(range, KTextEditor::Cursor(range.line(), col));
00897 }
00898
00899 int KateRenderer::cursorToX(const KateTextLayout& range, const KTextEditor::Cursor & pos) const
00900 {
00901 Q_ASSERT(range.isValid());
00902
00903 return (int)range.lineLayout().cursorToX(pos.column());
00904 }
00905
00906 int KateRenderer::cursorToX(const KateTextLayout& range, const KTextEditor::Cursor & pos, bool returnPastLine) const
00907 {
00908 int x = cursorToX(range, pos);
00909 int over = pos.column() * spaceWidth() - range.width();
00910
00911 if (returnPastLine && over > 0)
00912 x += over;
00913
00914 return x;
00915 }
00916
00917 KTextEditor::Cursor KateRenderer::xToCursor(const KateTextLayout & range, int x, bool returnPastLine ) const
00918 {
00919 Q_ASSERT(range.isValid());
00920 KTextEditor::Cursor ret(range.line(), range.lineLayout().xToCursor(x));
00921
00922
00923 if (returnPastLine && x > range.width() + range.xOffset())
00924 ret.setColumn(ret.column() + ((x - (range.width() + range.xOffset())) / spaceWidth()));
00925
00926 return ret;
00927 }
00928
00929 void KateRenderer::setCaretOverrideColor(const QColor& color)
00930 {
00931 m_caretOverrideColor = color;
00932 }
00933
00934