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.setWidthF(qMax(0.5, spaceWidth() * .1));
00235 pen.setCapStyle(Qt::RoundCap);
00236 paint.setPen( pen );
00237
00238
00239 qreal dist = spaceWidth() * 0.3;
00240 QPointF points[8];
00241 points[0] = QPointF(x - dist, y - dist);
00242 points[1] = QPointF(x, y);
00243 points[2] = QPointF(x, y);
00244 points[3] = QPointF(x - dist, y + dist);
00245 x += spaceWidth() / 3.0;
00246 points[4] = QPointF(x - dist, y - dist);
00247 points[5] = QPointF(x, y);
00248 points[6] = QPointF(x, y);
00249 points[7] = QPointF(x - dist, y + dist);
00250 paint.drawLines(points, 4);
00251 paint.setPen( penBackup );
00252 }
00253
00254 void KateRenderer::paintTrailingSpace(QPainter &paint, qreal x, qreal y)
00255 {
00256 QPen penBackup( paint.pen() );
00257 QPen pen( config()->tabMarkerColor() );
00258 pen.setWidthF(spaceWidth() / 3.5);
00259 pen.setCapStyle(Qt::RoundCap);
00260 paint.setPen( pen );
00261
00262 paint.drawPoint( QPointF(x, y) );
00263 paint.setPen( penBackup );
00264 }
00265
00266 void KateRenderer::paintIndentMarker(QPainter &paint, uint x, uint row)
00267 {
00268 QPen penBackup( paint.pen() );
00269 paint.setPen( config()->tabMarkerColor() );
00270
00271 const int height = config()->fontMetrics().height();
00272 const int top = 0;
00273 const int bottom = height-1;
00274 const int h = bottom - top + 1;
00275
00276
00277 int pad = 0;
00278 if(row & 1 && h & 1) pad = 1;
00279
00280 for(int i = top; i <= bottom; i++)
00281 {
00282 if((i + pad) & 1)
00283 {
00284 paint.drawPoint(x + 2, i);
00285 }
00286 }
00287
00288 paint.setPen( penBackup );
00289 }
00290
00291 QList<QTextLayout::FormatRange> KateRenderer::decorationsForLine( const KateTextLine::Ptr& textLine, int line, bool selectionsOnly, KateRenderRange* completionHighlight, bool completionSelected ) const
00292 {
00293 QList<QTextLayout::FormatRange> newHighlight;
00294
00295
00296 if (selectionsOnly || textLine->attributesList().count() || m_view->externalHighlights().count() || m_view->internalHighlights().count() || m_doc->documentHighlights().count()) {
00297 RenderRangeList renderRanges;
00298
00299
00300 NormalRenderRange* inbuiltHighlight = new NormalRenderRange();
00301 const QVector<int> &al = textLine->attributesList();
00302 for (int i = 0; i+2 < al.count(); i += 3) {
00303 inbuiltHighlight->addRange(new KTextEditor::Range(KTextEditor::Cursor(line, al[i]), al[i+1]), specificAttribute(al[i+2]));
00304 }
00305 renderRanges.append(inbuiltHighlight);
00306
00307 if (!completionHighlight) {
00308
00309 renderRanges.appendRanges(m_view->internalHighlights(), selectionsOnly, view());
00310 renderRanges.appendRanges(m_view->externalHighlights(), selectionsOnly, view());
00311
00312 } else {
00313
00314 renderRanges.append(completionHighlight);
00315 }
00316
00317
00318 if ((selectionsOnly && showSelections() && m_view->selection()) || (completionHighlight && completionSelected) || m_view->blockSelection()) {
00319 NormalRenderRange* selectionHighlight = new NormalRenderRange();
00320
00321
00322 static KTextEditor::Attribute::Ptr backgroundAttribute;
00323 if (!backgroundAttribute)
00324 backgroundAttribute = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute());
00325
00326 backgroundAttribute->setBackground(config()->selectionColor());
00327
00328
00329 if (completionHighlight && completionSelected)
00330 selectionHighlight->addRange(new KTextEditor::Range(line, 0, line + 1, 0), backgroundAttribute);
00331 else
00332 if(m_view->blockSelection() && m_view->selectionRange().overlapsLine(line))
00333 selectionHighlight->addRange(new KTextEditor::Range(line, m_view->selectionRange().start().column(), line, m_view->selectionRange().end().column()), backgroundAttribute);
00334 else
00335 selectionHighlight->addRange(new KTextEditor::Range(m_view->selectionRange()), backgroundAttribute);
00336
00337 renderRanges.append(selectionHighlight);
00338 }
00339
00340 KTextEditor::Cursor currentPosition, endPosition;
00341
00342
00343 if (selectionsOnly) {
00344 if(m_view->blockSelection()) {
00345 int startColumn = m_view->selectionRange().start().column();
00346 int endColumn = m_view->selectionRange().end().column();
00347 currentPosition = KTextEditor::Cursor(line, qMin(startColumn, endColumn));
00348 endPosition = KTextEditor::Cursor(line, qMax(startColumn, endColumn));
00349 } else {
00350 KTextEditor::Range rangeNeeded = m_view->selectionRange().encompass(m_dynamicRegion.boundingRange());
00351 rangeNeeded &= KTextEditor::Range(line, 0, line + 1, 0);
00352
00353 currentPosition = qMax(KTextEditor::Cursor(line, 0), rangeNeeded.start());
00354 endPosition = qMin(KTextEditor::Cursor(line + 1, 0), rangeNeeded.end());
00355 }
00356 } else {
00357 currentPosition = KTextEditor::Cursor(line, 0);
00358 endPosition = KTextEditor::Cursor(line + 1, 0);
00359 }
00360
00361
00362
00363 while (currentPosition < endPosition) {
00364 renderRanges.advanceTo(currentPosition);
00365
00366 if (!renderRanges.hasAttribute()) {
00367
00368 currentPosition = renderRanges.nextBoundary();
00369 continue;
00370 }
00371
00372 KTextEditor::Cursor nextPosition = renderRanges.nextBoundary();
00373
00374
00375 QTextLayout::FormatRange fr;
00376 fr.start = currentPosition.column();
00377
00378 if (nextPosition < endPosition || endPosition.line() <= line) {
00379 fr.length = nextPosition.column() - currentPosition.column();
00380
00381 } else {
00382
00383 fr.length = textLine->length() - currentPosition.column() + 1;
00384 }
00385
00386 KTextEditor::Attribute::Ptr a = renderRanges.generateAttribute();
00387 if(a) {
00388 fr.format = *a;
00389
00390 if(selectionsOnly) {
00391 if(m_view->blockSelection()) {
00392 int minSelectionColumn = qMin(m_view->selectionRange().start().column(), m_view->selectionRange().end().column());
00393 int maxSelectionColumn = qMax(m_view->selectionRange().start().column(), m_view->selectionRange().end().column());
00394
00395 if(currentPosition.column() >= minSelectionColumn && currentPosition.column() < maxSelectionColumn)
00396 assignSelectionBrushesFromAttribute(fr, *a);
00397
00398 } else if (m_view->selection() && m_view->selectionRange().contains(currentPosition)) {
00399 assignSelectionBrushesFromAttribute(fr, *a);
00400 }
00401 }
00402 }
00403
00404 newHighlight.append(fr);
00405
00406 currentPosition = nextPosition;
00407 }
00408
00409 if (completionHighlight)
00410
00411 renderRanges.removeAll(completionHighlight);
00412
00413 qDeleteAll(renderRanges);
00414 }
00415
00416 return newHighlight;
00417 }
00418
00419 void KateRenderer::assignSelectionBrushesFromAttribute(QTextLayout::FormatRange& target, const KTextEditor::Attribute& attribute) const
00420 {
00421 if(attribute.hasProperty(KTextEditor::Attribute::SelectedForeground)) {
00422 target.format.setForeground(attribute.selectedForeground());
00423 }
00424 if(attribute.hasProperty(KTextEditor::Attribute::SelectedBackground)) {
00425 target.format.setBackground(attribute.selectedBackground());
00426 }
00427 }
00428
00429
00430
00431
00432
00433
00434 void KateRenderer::paintTextLine(QPainter& paint, KateLineLayoutPtr range, int xStart, int xEnd, const KTextEditor::Cursor* cursor)
00435 {
00436 Q_ASSERT(range->isValid());
00437
00438
00439
00440
00441 const QFontMetrics& fm = config()->fontMetrics();
00442
00443 int currentViewLine = -1;
00444 if (cursor && cursor->line() == range->line())
00445 currentViewLine = range->viewLineForColumn(cursor->column());
00446
00447 paintTextLineBackground(paint, range, currentViewLine, xStart, xEnd);
00448
00449
00450 if (range->startsInvisibleBlock()) {
00451 paint.setPen(QPen(config()->wordWrapMarkerColor(), 1, Qt::DashLine));
00452 paint.drawLine(0, (fm.height() * range->viewLineCount()) - 1, xEnd - xStart, (fm.height() * range->viewLineCount()) - 1);
00453 }
00454
00455 if (range->layout()) {
00456 QVector<QTextLayout::FormatRange> additionalFormats;
00457 if (range->length() > 0) {
00458
00459
00460
00461 paint.setPen(attribute(KateExtendedAttribute::dsNormal)->foreground().color());
00462
00463 if (m_dynamicRegion.boundingRange().isValid() || (m_view->selection() && showSelections() && m_view->selectionRange().overlapsLine(range->line()))) {
00464
00465 additionalFormats = decorationsForLine(range->textLine(), range->line(), true).toVector();
00466 range->layout()->draw(&paint, QPoint(-xStart,0), additionalFormats);
00467
00468 } else {
00469 range->layout()->draw(&paint, QPoint(-xStart,0));
00470 }
00471 }
00472
00473 QBrush backgroundBrush;
00474 bool backgroundBrushSet = false;
00475
00476
00477 QListIterator<QTextLayout::FormatRange> it = range->layout()->additionalFormats();
00478 QVectorIterator<QTextLayout::FormatRange> it2 = additionalFormats;
00479 for (int i = 0; i < range->viewLineCount(); ++i) {
00480 KateTextLayout line = range->viewLine(i);
00481
00482
00483 backgroundBrushSet = false;
00484 while (it2.hasNext()) {
00485 const QTextLayout::FormatRange& fr = it2.peekNext();
00486 if (fr.start > line.endCol())
00487 goto backgroundDetermined;
00488
00489 if (fr.start + fr.length > line.endCol()) {
00490 if (fr.format.hasProperty(QTextFormat::BackgroundBrush)) {
00491 backgroundBrushSet = true;
00492 backgroundBrush = fr.format.background();
00493 }
00494
00495 goto backgroundDetermined;
00496 }
00497
00498 it2.next();
00499 }
00500
00501 while (it.hasNext()) {
00502 const QTextLayout::FormatRange& fr = it.peekNext();
00503 if (fr.start > line.endCol())
00504 break;
00505
00506 if (fr.start + fr.length > line.endCol()) {
00507 if (fr.format.hasProperty(QTextFormat::BackgroundBrush)) {
00508 backgroundBrushSet = true;
00509 backgroundBrush = fr.format.background();
00510 }
00511
00512 break;
00513 }
00514
00515 it.next();
00516 }
00517
00518 backgroundDetermined:
00519
00520
00521 if (!m_printerFriendly ) {
00522 bool draw = false;
00523 QBrush drawBrush;
00524 if (m_view->selection() && !m_view->blockSelection() && m_view->lineEndSelected(line.end(true))) {
00525 draw = true;
00526 drawBrush = config()->selectionColor();
00527 } else if (backgroundBrushSet && !m_view->blockSelection()) {
00528 draw = true;
00529 drawBrush = backgroundBrush;
00530 }
00531
00532 if (draw) {
00533 int fillStartX = line.endX() - line.startX() + line.xOffset() - xStart;
00534 int fillStartY = fm.height() * i;
00535 int width= xEnd - xStart - fillStartX;
00536 int height= fm.height();
00537
00538
00539 if (range->layout()->textOption().alignment() == Qt::AlignRight)
00540 fillStartX = 0;
00541
00542 QRect area(fillStartX, fillStartY, width, height);
00543 paint.fillRect(area, drawBrush);
00544 }
00545 }
00546
00547 if (showIndentLines() && i == 0)
00548 {
00549 const int w = spaceWidth();
00550 const int lastIndentColumn = range->textLine()->indentDepth(m_tabWidth);
00551
00552 for (int x = m_indentWidth; x < lastIndentColumn; x += m_indentWidth)
00553 {
00554 paintIndentMarker(paint, x * w + 1 - xStart, range->line());
00555 }
00556 }
00557
00558
00559 if (showTabs() || showTrailingSpaces()) {
00560 const QString& text = range->textLine()->string();
00561 int y = fm.height() * i + fm.ascent() - fm.strikeOutPos();
00562
00563 if (showTabs()) {
00564 int tabIndex = text.indexOf(tabChar, line.startCol());
00565 while (tabIndex != -1 && tabIndex < line.endCol()) {
00566 paintTabstop(paint, line.lineLayout().cursorToX(tabIndex) - xStart + spaceWidth()/2.0, y);
00567 tabIndex = text.indexOf(tabChar, tabIndex + 1);
00568 }
00569 }
00570
00571 if (showTrailingSpaces()) {
00572 int spaceIndex = line.endCol() - 1;
00573 int trailingPos = range->textLine()->lastChar();
00574 if (trailingPos < 0)
00575 trailingPos = 0;
00576 if (spaceIndex >= trailingPos) {
00577 while (spaceIndex >= line.startCol() && text.at(spaceIndex).isSpace()) {
00578 if (text.at(spaceIndex) != '\t' || !showTabs())
00579 paintTrailingSpace(paint, line.lineLayout().cursorToX(spaceIndex) - xStart + spaceWidth()/2.0, y);
00580 --spaceIndex;
00581 }
00582 }
00583 }
00584 }
00585 }
00586
00587
00588 if ( (range->viewLineCount() > 1) && range->shiftX() && (range->shiftX() > xStart) )
00589 {
00590 if (backgroundBrushSet)
00591 paint.fillRect(0, fm.height(), range->shiftX() - xStart, fm.height() * (range->viewLineCount() - 1),
00592 backgroundBrush);
00593 paint.fillRect(0, fm.height(), range->shiftX() - xStart, fm.height() * (range->viewLineCount() - 1),
00594 QBrush(config()->wordWrapMarkerColor(), Qt::Dense4Pattern));
00595 }
00596
00597
00598 if (drawCaret() && cursor && range->includesCursor(*cursor)) {
00599
00600 int caretWidth = 2;
00601 QTextLine line = range->layout()->lineForTextPosition(cursor->column());
00602 if (caretStyle() == Block || (m_view->viInputMode() && m_view->getCurrentViMode() != InsertMode)) {
00603 if (line.isValid() && cursor->column() < range->length()) {
00604 caretWidth = int(line.cursorToX(cursor->column() + 1) - line.cursorToX(cursor->column()));
00605 if (caretWidth < 0)
00606 caretWidth = -caretWidth;
00607
00608 } else {
00609 caretWidth = spaceWidth();
00610 }
00611 }
00612
00613 QColor c;
00614
00615 if (m_caretOverrideColor.isValid()) {
00616 c = m_caretOverrideColor;
00617
00618 } else {
00619 foreach (const QTextLayout::FormatRange &r, range->layout()->additionalFormats())
00620 {
00621 if ( (r.start <= cursor->column() ) && ( (r.start + r.length) > cursor->column()) ) {
00622 c = r.format.foreground().color();
00623 break;
00624 }
00625 }
00626
00627 if (!c.isValid())
00628 {
00629 if (range->layout()->additionalFormats().count())
00630 c = range->layout()->additionalFormats().last().format.foreground().color();
00631 else
00632 c = attribute(KateExtendedAttribute::dsNormal)->foreground().color();
00633 }
00634 }
00635
00636
00637 if (m_view->viInputMode() && m_view->getCurrentViMode() != InsertMode ) {
00638 c.setAlpha(128);
00639 }
00640
00641 if (cursor->column() <= range->length()) {
00642 paint.save();
00643 paint.setPen(QPen(c, caretWidth));
00644
00645
00646 paint.setClipRect(0, line.lineNumber() * fm.height(), xEnd - xStart, fm.height());
00647
00648 range->layout()->drawCursor(&paint, QPoint(-xStart,0), cursor->column(), caretWidth);
00649
00650 paint.restore();
00651
00652 } else {
00653
00654 const KateTextLayout& lastLine = range->viewLine(range->viewLineCount() - 1);
00655 int x = range->widthOfLastLine() + spaceWidth() * (cursor->column() - range->length());
00656 if ( (x >= xStart) && (x <= xEnd))
00657 paint.fillRect(x, (int)lastLine.lineLayout().y(), caretWidth, fm.height(), c);
00658 }
00659 }
00660 }
00661
00662
00663 if ((!isPrinterFriendly()) && config()->wordWrapMarker() && QFontInfo(config()->font()).fixedPitch())
00664 {
00665 paint.setPen( config()->wordWrapMarkerColor() );
00666 int _x = m_doc->config()->wordWrapAt() * fm.width('x') - xStart;
00667 paint.drawLine( _x,0,_x,fm.height() );
00668 }
00669 }
00670
00671 const QFont& KateRenderer::currentFont() const
00672 {
00673 return config()->font();
00674 }
00675
00676 const QFontMetrics& KateRenderer::currentFontMetrics() const
00677 {
00678 return config()->fontMetrics();
00679 }
00680
00681 uint KateRenderer::fontHeight()
00682 {
00683 return config()->fontMetrics().height();
00684 }
00685
00686 uint KateRenderer::documentHeight()
00687 {
00688 return m_doc->lines() * fontHeight();
00689 }
00690
00691 bool KateRenderer::getSelectionBounds(int line, int lineLength, int &start, int &end) const
00692 {
00693 bool hasSel = false;
00694
00695 if (m_view->selection() && !m_view->blockSelectionMode())
00696 {
00697 if (m_view->lineIsSelection(line))
00698 {
00699 start = m_view->selectionRange().start().column();
00700 end = m_view->selectionRange().end().column();
00701 hasSel = true;
00702 }
00703 else if (line == m_view->selectionRange().start().line())
00704 {
00705 start = m_view->selectionRange().start().column();
00706 end = lineLength;
00707 hasSel = true;
00708 }
00709 else if (m_view->selectionRange().containsLine(line))
00710 {
00711 start = 0;
00712 end = lineLength;
00713 hasSel = true;
00714 }
00715 else if (line == m_view->selectionRange().end().line())
00716 {
00717 start = 0;
00718 end = m_view->selectionRange().end().column();
00719 hasSel = true;
00720 }
00721 }
00722 else if (m_view->lineHasSelected(line))
00723 {
00724 start = m_view->selectionRange().start().column();
00725 end = m_view->selectionRange().end().column();
00726 hasSel = true;
00727 }
00728
00729 if (start > end) {
00730 int temp = end;
00731 end = start;
00732 start = temp;
00733 }
00734
00735 return hasSel;
00736 }
00737
00738 void KateRenderer::updateConfig ()
00739 {
00740
00741 updateAttributes ();
00742
00743 if (m_view)
00744 m_view->updateRendererConfig();
00745 }
00746
00747 uint KateRenderer::spaceWidth() const
00748 {
00749 return config()->fontMetrics().width(spaceChar);
00750 }
00751
00752 void KateRenderer::layoutLine(KateLineLayoutPtr lineLayout, int maxwidth, bool cacheLayout) const
00753 {
00754
00755
00756 KateTextLine::Ptr textLine = lineLayout->textLine();
00757 Q_ASSERT(textLine);
00758
00759 QTextLayout* l = lineLayout->layout();
00760 if (!l) {
00761 l = new QTextLayout(textLine->string(), config()->font());
00762 } else {
00763 l->setText(textLine->string());
00764 l->setFont(config()->font());
00765 }
00766
00767 l->setCacheEnabled(cacheLayout);
00768
00769
00770
00771
00772 QTextOption opt;
00773 opt.setFlags(QTextOption::IncludeTrailingSpaces);
00774 opt.setTabStop(m_tabWidth * config()->fontMetrics().width(spaceChar));
00775 opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
00776
00777
00778
00779
00780
00781
00782
00783
00784 if (isLineRightToLeft(lineLayout)) {
00785 opt.setAlignment( Qt::AlignRight );
00786 opt.setTextDirection( Qt::RightToLeft );
00787 }
00788 else {
00789 opt.setAlignment( Qt::AlignLeft );
00790 opt.setTextDirection( Qt::LeftToRight );
00791 }
00792
00793 l->setTextOption(opt);
00794
00795
00796 l->setAdditionalFormats(decorationsForLine(textLine, lineLayout->line()));
00797
00798
00799 l->beginLayout();
00800
00801 int height = 0;
00802 int shiftX = 0;
00803
00804 bool needShiftX = (maxwidth != -1)
00805 && (m_view->config()->dynWordWrapAlignIndent() > 0);
00806
00807 forever {
00808 QTextLine line = l->createLine();
00809 if (!line.isValid())
00810 break;
00811
00812 if (maxwidth > 0)
00813 line.setLineWidth(maxwidth);
00814
00815 line.setPosition(QPoint(line.lineNumber() ? shiftX : 0, height));
00816
00817 if (needShiftX) {
00818 needShiftX = false;
00819
00820 int pos = textLine->nextNonSpaceChar(0);
00821
00822 if (pos > 0) {
00823 shiftX = (int)line.cursorToX(pos);
00824 }
00825
00826
00827 if (shiftX > ((double)maxwidth / 100 * m_view->config()->dynWordWrapAlignIndent()))
00828 shiftX = 0;
00829
00830
00831 maxwidth -= shiftX;
00832
00833 lineLayout->setShiftX(shiftX);
00834 }
00835
00836 height += config()->fontMetrics().height();
00837 }
00838
00839 l->endLayout();
00840
00841 lineLayout->setLayout(l);
00842 }
00843
00844
00845
00846
00847
00848
00849
00850 bool KateRenderer::isLineRightToLeft( KateLineLayoutPtr lineLayout ) const
00851 {
00852 QString s = lineLayout->textLine()->string();
00853 int i = 0;
00854
00855
00856 while( i != s.length() )
00857 {
00858 QChar c = s.at(i);
00859
00860 switch(c.direction()) {
00861 case QChar::DirL:
00862 case QChar::DirLRO:
00863 case QChar::DirLRE:
00864 return false;
00865
00866 case QChar::DirR:
00867 case QChar::DirAL:
00868 case QChar::DirRLO:
00869 case QChar::DirRLE:
00870 return true;
00871
00872 default:
00873 break;
00874 }
00875 i ++;
00876 }
00877
00878 return false;
00879 #if 0
00880
00881 QWidget* display = qobject_cast<QWidget*>(view()->parent());
00882 if (!display)
00883 return false;
00884 return display->layoutDirection() == Qt::RightToLeft;
00885 #endif
00886 }
00887
00888 int KateRenderer::cursorToX(const KateTextLayout& range, int col) const
00889 {
00890 return cursorToX(range, KTextEditor::Cursor(range.line(), col));
00891 }
00892
00893 int KateRenderer::cursorToX(const KateTextLayout& range, const KTextEditor::Cursor & pos) const
00894 {
00895 Q_ASSERT(range.isValid());
00896
00897 return (int)range.lineLayout().cursorToX(pos.column());
00898 }
00899
00900 KTextEditor::Cursor KateRenderer::xToCursor(const KateTextLayout & range, int x, bool returnPastLine ) const
00901 {
00902 Q_ASSERT(range.isValid());
00903 KTextEditor::Cursor ret(range.line(), range.lineLayout().xToCursor(x));
00904
00905
00906 if (returnPastLine && x > range.width() + range.xOffset())
00907 ret.setColumn(ret.column() + ((x - (range.width() + range.xOffset())) / spaceWidth()));
00908
00909 return ret;
00910 }
00911
00912 void KateRenderer::setCaretOverrideColor(const QColor& color)
00913 {
00914 m_caretOverrideColor = color;
00915 }
00916
00917