22 #include "katerenderer.h"
24 #include "katelinerange.h"
25 #include "katedocument.h"
26 #include "katearbitraryhighlight.h"
27 #include "kateconfig.h"
28 #include "katehighlight.h"
29 #include "katefactory.h"
34 #include <tqpainter.h>
35 #include <tqpopupmenu.h>
38 : m_doc(doc), m_view (view), m_caretStyle(
KateRenderer::Insert)
40 , m_showSelections(true)
42 , m_printerFriendly(false)
44 KateFactory::self()->registerRenderer (
this );
45 m_config =
new KateRendererConfig (
this);
47 m_tabWidth = m_doc->config()->tabWidth();
48 m_indentWidth = m_tabWidth;
49 if (m_doc->config()->configFlags() & KateDocumentConfig::cfSpaceIndent)
51 m_indentWidth = m_doc->config()->indentationWidth();
60 KateFactory::self()->deregisterRenderer (
this );
65 m_schema =
config()->schema ();
66 m_attributes = m_doc->highlight()->attributes (m_schema);
71 if (pos < m_attributes->size())
72 return &m_attributes->at(pos);
74 return &m_attributes->at(0);
94 m_tabWidth = tabWidth;
99 return m_config->showIndentationLines();
104 m_config->setShowIndentationLines(showIndentLines);
109 m_indentWidth = m_tabWidth;
110 if (m_doc->config()->configFlags() & KateDocumentConfig::cfSpaceIndent)
112 m_indentWidth = indentWidth;
123 TQFont f ( *
config()->font () );
124 f.setPointSize (f.pointSize ()+1);
129 void KateRenderer::decreaseFontSizes()
131 TQFont f ( *
config()->font () );
133 if ((f.pointSize ()-1) > 0)
134 f.setPointSize (f.pointSize ()-1);
141 return m_printerFriendly;
146 m_printerFriendly = printerFriendly;
158 KateFontStruct *fs =
config()->fontStruct();
161 TQColor backgroundColor(
config()->backgroundColor() );
163 bool selectionPainted =
false;
166 backgroundColor =
config()->selectionColor();
167 selectionPainted =
true;
173 backgroundColor =
config()->highlightedLineColor();
176 int markRed = 0, markGreen = 0, markBlue = 0, markCount = 0;
179 uint mrk = m_doc->mark( line );
182 for (uint bit = 0; bit < 32; bit++)
184 KTextEditor::MarkInterface::MarkTypes markType = (KTextEditor::MarkInterface::MarkTypes)(1<<bit);
187 TQColor markColor =
config()->lineMarkerColor(markType);
189 if (markColor.isValid()) {
191 markRed += markColor.red();
192 markGreen += markColor.green();
193 markBlue += markColor.blue();
200 markRed /= markCount;
201 markGreen /= markCount;
202 markBlue /= markCount;
203 backgroundColor.setRgb(
204 int((backgroundColor.red() * 0.9) + (markRed * 0.1)),
205 int((backgroundColor.green() * 0.9) + (markGreen * 0.1)),
206 int((backgroundColor.blue() * 0.9) + (markBlue * 0.1))
212 paint.fillRect(0, 0, xEnd - xStart, fs->fontHeight, backgroundColor);
214 return selectionPainted;
217 void KateRenderer::paintWhitespaceMarker(TQPainter &paint, uint x, uint y)
219 TQPen penBackup( paint.pen() );
220 paint.setPen(
config()->tabMarkerColor() );
221 paint.drawPoint(x, y);
222 paint.drawPoint(x + 1, y);
223 paint.drawPoint(x, y - 1);
224 paint.setPen( penBackup );
228 void KateRenderer::paintIndentMarker(TQPainter &paint, uint x, uint row)
230 TQPen penBackup( paint.pen() );
231 paint.setPen(
config()->tabMarkerColor() );
233 const int top = paint.window().top();
234 const int bottom = paint.window().bottom();
235 const int h = bottom - top + 1;
239 if(row & 1 && h & 1) pad = 1;
241 for(
int i = top; i <= bottom; i++)
245 paint.drawPoint(x + 2, i);
249 paint.setPen( penBackup );
255 int line = range->line;
262 bool showCursor =
drawCaret() && cursor && range->includesCursor(*cursor);
264 KateSuperRangeList& superRanges = m_doc->arbitraryHL()->rangesIncluding(range->line, 0);
271 KateArbitraryHighlightRange* bracketStartRange (0L);
272 KateArbitraryHighlightRange* bracketEndRange (0L);
273 if (bracketmark && bracketmark->isValid()) {
274 if (range->includesCursor(bracketmark->start())) {
276 startend.setCol(startend.col()+1);
277 bracketStartRange =
new KateArbitraryHighlightRange(m_doc, bracketmark->start(), startend);
278 bracketStartRange->setBGColor(
config()->highlightedBracketColor());
279 bracketStartRange->setBold(
true);
280 superRanges.append(bracketStartRange);
283 if (range->includesCursor(bracketmark->end())) {
285 endend.setCol(endend.col()+1);
286 bracketEndRange =
new KateArbitraryHighlightRange(m_doc, bracketmark->end(), endend);
287 bracketEndRange->setBGColor(
config()->highlightedBracketColor());
288 bracketEndRange->setBold(
true);
289 superRanges.append(bracketEndRange);
292 Q_ASSERT(bracketmark->start().line() <= bracketmark->end().line());
293 if (bracketmark->start().line() < line && bracketmark->end().line() >= line)
295 minIndent = bracketmark->getMinIndent();
301 uint len = textLine->length();
305 bool cursorVisible =
false;
306 int cursorMaxWidth = 0;
309 KateFontStruct * fs =
config()->fontStruct();
318 bool selectionPainted =
false;
319 bool isCurrentLine = (cursor && range->includesCursor(*cursor));
321 if (selectionPainted)
328 int startcol = range->startCol;
329 if (startcol > (
int)len)
335 int endcol = range->wrap ? range->endCol : -1;
337 len = len - startcol;
339 len = endcol - startcol;
342 KateAttribute* attr = m_doc->highlight()->attributes(m_schema)->data();
344 const TQColor *cursorColor = &attr[0].textColor();
348 superRanges.firstBoundary(¤tPos);
351 hasSel = getSelectionBounds(line, oldLen, startSel, endSel);
354 if (range->startsInvisibleBlock) {
355 paint.setPen(TQPen(
config()->wordWrapMarkerColor(), 1, Qt::DashLine));
356 paint.drawLine(0, fs->fontHeight - 1, xEnd - xStart, fs->fontHeight - 1);
360 if (range->xOffset() && range->xOffset() > xStart)
362 paint.fillRect(0, 0, range->xOffset() - xStart, fs->fontHeight,
363 TQBrush(
config()->wordWrapMarkerColor(), TQBrush::DiagCrossPattern));
367 uint xPos = range->xOffset();
373 if (showCursor && (cursor->col() >= int(startcol)))
375 cursorVisible =
true;
376 cursorXPos = xPos + cursor->col() * fs->myFontMetrics.width(TQChar(
' '));
381 bool isIMSel =
false;
382 bool isIMEdit =
false;
388 const TQColor *curColor = 0;
389 const TQColor *oldColor = 0;
394 uint xPosAfter = xPos;
398 uint blockStartCol = startcol;
399 uint curCol = startcol;
400 uint nextCol = curCol + 1;
403 const uchar *textAttributes = textLine->attributes ();
404 bool noAttribs = !textAttributes;
407 textAttributes = textAttributes + startcol;
409 uint atLen = m_doc->highlight()->attributes(m_schema)->size();
413 uint trailingWhitespaceColumn = textLine->lastChar() + 1;
414 const uint lastIndentColumn = textLine->firstChar();
417 const uint
spaceWidth = fs->width (TQChar(
' '),
false,
false, m_tabWidth);
420 int curPos = textLine->cursorX(curCol, m_tabWidth);
422 while (curCol - startcol < len)
428 TQChar curChar = textLine->string()[curCol];
431 bool isTab = curChar == TQChar(
'\t');
435 KateAttribute* curAt = (noAttribs || ((*textAttributes) >= atLen)) ? &attr[0] : &attr[*textAttributes];
439 xPosAfter += curAt->width(*fs, curChar, m_tabWidth);
443 xPosAfter -= (xPosAfter % curAt->width(*fs, curChar, m_tabWidth));
447 if ((
int)xPosAfter >= xStart)
450 isSel = (
showSelections() && hasSel && (curCol >= startSel) && (curCol < endSel));
453 isIMEdit = m_view && m_view->isIMEdit( line, curCol );
456 isIMSel = m_view && m_view->isIMSelection( line, curCol );
459 curColor = isSel ? &(curAt->selectedTextColor()) : &(curAt->textColor());
462 if (curAt != oldAt || curColor != oldColor || (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)) {
463 if (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
464 customHL = KateArbitraryHighlightRange::merge(superRanges.rangesIncluding(currentPos));
471 if (!hl.itemSet(KateAttribute::TextColor))
472 hl.setTextColor(*curColor);
475 paint.setPen(hl.textColor());
477 paint.setPen(hl.selectedTextColor());
479 paint.setFont(hl.font(*currentFont()));
481 if (superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
482 superRanges.nextBoundary();
492 bool renderNow =
false;
495 || (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) ==
KateTextCursor(line, nextCol))
498 || (curCol - startcol >= len - 1)
501 || (curCol + 1 >= trailingWhitespaceColumn)
507 || ((
int)xPos > xEnd)
510 || (!noAttribs && curAt != &attr[*(textAttributes+1)])
513 || (isSel != (hasSel && (nextCol >= startSel) && (nextCol < endSel)))
517 || (textLine->string()[nextCol] == TQChar(
'\t'))
520 || ( m_view && (isIMEdit != m_view->isIMEdit( line, nextCol )) )
523 || ( m_view && (isIMSel != m_view->isIMSelection( line, nextCol )) )
533 bool paintBackground =
true;
534 uint width = xPosAfter - oldXPos;
537 if (isIMSel && !isTab)
540 fillColor = m_view->colorGroup().color(TQColorGroup::Foreground);
542 else if (isIMEdit && !isTab)
546 const TQColorGroup& cg = m_view->colorGroup();
547 int h1, s1, v1, h2, s2, v2;
548 TQColor(cg.color( TQColorGroup::Base )).hsv( &h1, &s1, &v1 );
549 TQColor(cg.color( TQColorGroup::Background )).hsv( &h2, &s2, &v2 );
550 fillColor.setHsv( h1, s1, ( v1 + v2 ) / 2 );
552 else if (!selectionPainted && (isSel || currentHL.itemSet(KateAttribute::BGColor)))
556 fillColor =
config()->selectionColor();
560 if ((curCol >= len - 1) && m_view->lineEndSelected (line, endcol))
561 width = xEnd - oldXPos;
565 fillColor = currentHL.bgColor();
570 paintBackground =
false;
574 paint.fillRect(oldXPos - xStart, 0, width, fs->fontHeight, fillColor);
576 if (isIMSel && paintBackground && !isTab)
579 paint.setPen( m_view->colorGroup().color( TQColorGroup::BrightText ) );
586 const int charWidth = isTab ? m_tabWidth - curPos % m_tabWidth : 1;
590 if (curPos == 0 || curPos % m_indentWidth > 0)
591 i = m_indentWidth - curPos % m_indentWidth;
593 for (; i < charWidth; i += m_indentWidth)
596 paintIndentMarker(paint, xPos - xStart + i * spaceWidth, line);
599 if (curPos+i == minIndent)
601 paintIndentMarker(paint, xPos - xStart + 1 + i * spaceWidth, line+1);
608 int y = fs->fontAscent;
612 if (isTab || (curCol >= trailingWhitespaceColumn))
615 static TQString spaces;
616 if (
int(spaces.length()) != m_tabWidth)
617 spaces.fill(
' ', m_tabWidth);
619 paint.drawText(oldXPos-xStart, y, isTab ? spaces : TQString(
" "));
625 paintWhitespaceMarker(paint, xPos - xStart, y);
629 blockStartCol = nextCol;
635 paint.drawText(oldXPos-xStart, y, textLine->string(), blockStartCol, nextCol-blockStartCol);
639 TQRect r( oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight );
640 paint.drawLine( r.bottomLeft(), r.bottomRight() );
644 if (isIMSel) paint.restore();
647 if ((
int)xPos > xEnd)
651 blockStartCol = nextCol;
658 if (showCursor && (cursor->col() == int(curCol)))
660 cursorVisible =
true;
662 cursorMaxWidth = xPosAfter - xPos;
663 cursorColor = &curAt->textColor();
669 blockStartCol = nextCol;
686 currentPos.setCol(currentPos.col() + 1);
691 curPos += m_tabWidth - (curPos % m_tabWidth);
701 if (
showSelections() && hasSel && !selectionPainted && xStart >= (int)xPos && m_view->lineEndSelected(line, -1))
703 paint.fillRect(0, 0, xEnd-xStart, fs->fontHeight,
config()->selectionColor());
707 if (showCursor && (cursor->col() >= int(curCol)))
709 cursorVisible =
true;
710 cursorXPos = xPos + (cursor->col() - int(curCol)) * fs->myFontMetrics.width(TQChar(
' '));
711 cursorMaxWidth = xPosAfter - xPos;
712 cursorColor = &oldAt->textColor();
719 uint cursorWidth = (
caretStyle() == Replace && (cursorMaxWidth > 2)) ? cursorMaxWidth : 2;
720 paint.fillRect(cursorXPos-xStart, 0, cursorWidth, fs->fontHeight, *cursorColor);
726 paint.setPen(
config()->wordWrapMarkerColor() );
727 int _x = m_doc->config()->wordWrapAt() * fs->myFontMetrics.width(
'x') - xStart;
728 paint.drawLine( _x,0,_x,fs->fontHeight );
732 delete bracketStartRange;
733 delete bracketEndRange;
741 const int len = textLine->length();
746 KateFontStruct *fs =
config()->fontStruct();
748 const TQChar *unicode = textLine->text();
749 const TQString &textString = textLine->string();
753 for (
int z = 0; z < cursorCol; z++) {
757 width = a->width(*fs, textString, z, m_tabWidth);
761 width = a->width(*fs, TQChar(
' '), m_tabWidth);
766 if (z < len && unicode[z] == TQChar(
'\t'))
773 uint KateRenderer::textWidth(
const KateTextLine::Ptr &textLine, uint startcol, uint maxwidth,
bool *needWrap,
int *endX)
775 KateFontStruct *fs =
config()->fontStruct();
777 uint endcol = startcol;
779 int lastWhiteSpace = -1;
780 int lastWhiteSpaceX = -1;
784 bool foundNonWhitespace = startcol != 0;
785 bool foundWhitespaceAfterNonWhitespace = startcol != 0;
789 const uint len = textLine->length();
790 const TQChar *unicode = textLine->text();
791 const TQString &textString = textLine->string();
797 int width = a->width(*fs, textString, z, m_tabWidth);
803 if (unicode[z] == TQChar(
'\t'))
806 if (unicode[z].isSpace())
808 lastWhiteSpace = z+1;
811 if (foundNonWhitespace)
812 foundWhitespaceAfterNonWhitespace =
true;
816 if (!foundWhitespaceAfterNonWhitespace) {
817 foundNonWhitespace =
true;
819 lastWhiteSpace = z+1;
826 if (lastWhiteSpace > -1)
828 endcol = lastWhiteSpace;
829 endX2 = lastWhiteSpaceX;
837 else if (z == startcol)
870 int line = kMin(kMax(0, cursor.line()), (
int)m_doc->numLines() - 1);
871 int col = kMax(0, cursor.col());
873 return textWidth(m_doc->kateTextLine(line), col);
878 bool wrapCursor = m_view->wrapCursor();
881 KateFontStruct *fs =
config()->fontStruct();
883 if (cursor.line() < 0) cursor.setLine(0);
884 if (cursor.line() > (int)m_doc->lastLine()) cursor.setLine(m_doc->lastLine());
887 if (!textLine)
return 0;
889 const uint len = textLine->length();
890 const TQChar *unicode = textLine->text();
891 const TQString &textString = textLine->string();
895 while (x < xPos && (!wrapCursor || z < len)) {
903 width = a->width(*fs, textString, z, m_tabWidth);
905 width = a->width(*fs, TQChar(
' '), m_tabWidth);
909 if (z < len && unicode[z] == TQChar(
'\t'))
914 if (xPos - oldX < x - xPos && z > 0) {
922 const TQFont *KateRenderer::currentFont()
927 const TQFontMetrics* KateRenderer::currentFontMetrics()
929 return config()->fontMetrics();
934 return textPos(m_doc->kateTextLine(line), xPos, startCol, nearest);
943 KateFontStruct *fs =
config()->fontStruct();
949 const uint len = textLine->length();
950 const TQString &textString = textLine->string();
952 while ( (x < xPos) && (z < len)) {
956 x += a->width(*fs, textString, z, m_tabWidth);
960 if ( ( (! nearest) || xPos - oldX < x - xPos ) && z > 0 ) {
967 uint KateRenderer::fontHeight()
969 return config()->fontStruct ()->fontHeight;
972 uint KateRenderer::documentHeight()
974 return m_doc->numLines() * fontHeight();
977 bool KateRenderer::getSelectionBounds(uint line, uint lineLength, uint &start, uint &end)
981 if (m_view->hasSelection() && !m_view->blockSelectionMode())
983 if (m_view->lineIsSelection(line))
985 start = m_view->selStartCol();
986 end = m_view->selEndCol();
989 else if ((
int)line == m_view->selStartLine())
991 start = m_view->selStartCol();
995 else if ((
int)line == m_view->selEndLine())
998 end = m_view->selEndCol();
1002 else if (m_view->lineHasSelected(line))
1004 start = m_view->selStartCol();
1005 end = m_view->selEndCol();
1018 void KateRenderer::updateConfig ()
1024 m_view->updateRendererConfig();
1029 return attribute(0)->width(*
config()->fontStruct(), TQChar(
' '), m_tabWidth);