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();
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, TQt::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)
424 const TQString &textString = textLine->string();
425 int currCharNumCols = textString[curCol].isHighSurrogate() ? 2 : 1;
426 nextCol = curCol + currCharNumCols;
434 bool isTab = textString[curCol] == TQChar(
'\t');
438 KateAttribute* curAt = (noAttribs || ((*textAttributes) >= atLen)) ? &attr[0] : &attr[*textAttributes];
442 xPosAfter += curAt->width(*fs, textString, curCol, m_tabWidth);
446 xPosAfter -= (xPosAfter % curAt->width(*fs, textString[curCol], m_tabWidth));
450 if ((
int)xPosAfter >= xStart)
453 isSel = (
showSelections() && hasSel && (curCol >= startSel) && (curCol < endSel));
456 isIMEdit = m_view && m_view->isIMEdit( line, curCol );
459 isIMSel = m_view && m_view->isIMSelection( line, curCol );
462 curColor = isSel ? &(curAt->selectedTextColor()) : &(curAt->textColor());
465 if (curAt != oldAt || curColor != oldColor || (superRanges.count() &&
466 superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos))
468 if (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
469 customHL = KateArbitraryHighlightRange::merge(superRanges.rangesIncluding(currentPos));
476 if (!hl.itemSet(KateAttribute::TextColor))
477 hl.setTextColor(*curColor);
480 paint.setPen(hl.textColor());
482 paint.setPen(hl.selectedTextColor());
484 paint.setFont(hl.font(*currentFont()));
486 if (superRanges.currentBoundary() && *(superRanges.currentBoundary()) == currentPos)
487 superRanges.nextBoundary();
497 bool renderNow =
false;
500 || (superRanges.count() && superRanges.currentBoundary() && *(superRanges.currentBoundary()) ==
KateTextCursor(line, nextCol))
503 || ((curCol - startcol) >= (len - currCharNumCols))
506 || (nextCol >= trailingWhitespaceColumn)
512 || ((
int)xPos > xEnd)
515 || (!noAttribs && curAt != &attr[*(textAttributes+1)])
518 || (isSel != (hasSel && (nextCol >= startSel) && (nextCol < endSel)))
522 || (textString[nextCol] == TQChar(
'\t'))
525 || ( m_view && (isIMEdit != m_view->isIMEdit( line, nextCol )) )
528 || ( m_view && (isIMSel != m_view->isIMSelection( line, nextCol )) )
538 bool paintBackground =
true;
539 uint width = xPosAfter - oldXPos;
542 if (isIMSel && !isTab)
545 fillColor = m_view->colorGroup().color(TQColorGroup::Foreground);
547 else if (isIMEdit && !isTab)
551 const TQColorGroup& cg = m_view->colorGroup();
552 int h1, s1, v1, h2, s2, v2;
553 TQColor(cg.color( TQColorGroup::Base )).hsv( &h1, &s1, &v1 );
554 TQColor(cg.color( TQColorGroup::Background )).hsv( &h2, &s2, &v2 );
555 fillColor.setHsv( h1, s1, ( v1 + v2 ) / 2 );
557 else if (!selectionPainted && (isSel || currentHL.itemSet(KateAttribute::BGColor)))
561 fillColor =
config()->selectionColor();
565 if (curCol >= (len - currCharNumCols) && m_view->lineEndSelected(line, endcol))
566 width = xEnd - oldXPos;
570 fillColor = currentHL.bgColor();
575 paintBackground =
false;
579 paint.fillRect(oldXPos - xStart, 0, width, fs->fontHeight, fillColor);
581 if (isIMSel && paintBackground && !isTab)
584 paint.setPen( m_view->colorGroup().color( TQColorGroup::BrightText ) );
591 const int charWidth = isTab ? m_tabWidth - curPos % m_tabWidth : 1;
595 if (curPos == 0 || curPos % m_indentWidth > 0)
596 i = m_indentWidth - curPos % m_indentWidth;
598 for (; i < charWidth; i += m_indentWidth)
601 paintIndentMarker(paint, xPos - xStart + i *
spaceWidth, line);
604 if (curPos+i == minIndent)
606 paintIndentMarker(paint, xPos - xStart + 1 + i *
spaceWidth, line+1);
613 int y = fs->fontAscent;
617 if (isTab || (curCol >= trailingWhitespaceColumn))
620 static TQString spaces;
621 if (
int(spaces.length()) != m_tabWidth)
622 spaces.fill(
' ', m_tabWidth);
624 paint.drawText(oldXPos-xStart, y, isTab ? spaces : TQString(
" "));
630 paintWhitespaceMarker(paint, xPos - xStart, y);
634 blockStartCol = nextCol;
640 paint.drawText(oldXPos-xStart, y, textString, blockStartCol, nextCol-blockStartCol);
644 TQRect r( oldXPos - xStart, 0, xPosAfter - oldXPos, fs->fontHeight );
645 paint.drawLine( r.bottomLeft(), r.bottomRight() );
649 if (isIMSel) paint.restore();
652 if ((
int)xPos > xEnd)
656 blockStartCol = nextCol;
662 if (showCursor && (cursor->col() ==
int(curCol)))
664 cursorVisible =
true;
666 cursorMaxWidth = xPosAfter - xPos;
667 cursorColor = &curAt->textColor();
673 blockStartCol = nextCol;
688 curCol += currCharNumCols;
689 currentPos.setCol(currentPos.col() + currCharNumCols);
694 curPos += m_tabWidth - (curPos % m_tabWidth);
704 if (
showSelections() && hasSel && !selectionPainted && xStart >= (int)xPos && m_view->lineEndSelected(line, -1))
706 paint.fillRect(0, 0, xEnd-xStart, fs->fontHeight,
config()->selectionColor());
710 if (showCursor && (cursor->col() >= int(curCol)))
712 cursorVisible =
true;
713 cursorXPos = xPos + (cursor->col() - int(curCol)) * fs->myFontMetrics.width(TQChar(
' '));
714 cursorMaxWidth = xPosAfter - xPos;
715 cursorColor = &oldAt->textColor();
722 uint cursorWidth = (
caretStyle() == Replace && (cursorMaxWidth > 2)) ? cursorMaxWidth : 2;
723 paint.fillRect(cursorXPos-xStart, 0, cursorWidth, fs->fontHeight, *cursorColor);
729 paint.setPen(
config()->wordWrapMarkerColor() );
730 int _x = m_doc->config()->wordWrapAt() * fs->myFontMetrics.width(
'x') - xStart;
731 paint.drawLine( _x,0,_x,fs->fontHeight );
735 delete bracketStartRange;
736 delete bracketEndRange;
744 const int len = textLine->length();
749 KateFontStruct *fs =
config()->fontStruct();
751 const TQChar *unicode = textLine->text();
752 const TQString &textString = textLine->string();
756 for (
int z = 0; z < cursorCol; z++) {
760 width = a->width(*fs, textString, z, m_tabWidth);
762 width = a->width(*fs, TQChar(
' '), m_tabWidth);
767 if (z < len && unicode[z] == TQChar(
'\t'))
770 if (textString[z].isHighSurrogate())
779 uint KateRenderer::textWidth(
const KateTextLine::Ptr &textLine, uint startcol, uint maxwidth,
bool *needWrap,
int *endX)
781 KateFontStruct *fs =
config()->fontStruct();
783 uint endcol = startcol;
785 int lastWhiteSpace = -1;
786 int lastWhiteSpaceX = -1;
790 bool foundNonWhitespace = startcol != 0;
791 bool foundWhitespaceAfterNonWhitespace = startcol != 0;
795 const uint len = textLine->length();
796 const TQChar *unicode = textLine->text();
797 const TQString &textString = textLine->string();
803 int width = a->width(*fs, textString, z, m_tabWidth);
809 if (unicode[z] == TQChar(
'\t'))
812 if (textString[z].isHighSurrogate())
816 else if (unicode[z].isSpace())
818 lastWhiteSpace = z+1;
821 if (foundNonWhitespace)
822 foundWhitespaceAfterNonWhitespace =
true;
826 if (!foundWhitespaceAfterNonWhitespace) {
827 foundNonWhitespace =
true;
829 lastWhiteSpace = z+1;
836 if (lastWhiteSpace > -1)
838 endcol = lastWhiteSpace;
839 endX2 = lastWhiteSpaceX;
847 else if (z == startcol)
880 int line = kMin(kMax(0, cursor.line()), (
int)m_doc->numLines() - 1);
881 int col = kMax(0, cursor.col());
883 return textWidth(m_doc->kateTextLine(line), col);
886 uint KateRenderer::textWidth(
KateTextCursor &cursor,
int xPos, uint startCol)
888 bool wrapCursor = m_view->wrapCursor();
890 KateFontStruct *fs =
config()->fontStruct();
892 if (cursor.line() < 0) cursor.setLine(0);
893 if (cursor.line() > (
int)m_doc->lastLine()) cursor.setLine(m_doc->lastLine());
896 if (!textLine)
return 0;
898 const uint len = textLine->length();
899 const TQChar *unicode = textLine->text();
900 const TQString &textString = textLine->string();
907 while (x < xPos && (!wrapCursor || z < len)) {
914 width = a->width(*fs, textString, z, m_tabWidth);
916 width = a->width(*fs, TQChar(
' '), m_tabWidth);
920 if (z < len && unicode[z] == TQChar(
'\t'))
923 z += textString[z].isHighSurrogate() ? 2 : 1;
925 if (xPos - oldX < x - xPos && z > 0) {
933 const TQFont *KateRenderer::currentFont()
938 const TQFontMetrics* KateRenderer::currentFontMetrics()
940 return config()->fontMetrics();
945 return textPos(m_doc->kateTextLine(line), xPos, startCol, nearest);
954 KateFontStruct *fs =
config()->fontStruct();
960 const uint len = textLine->length();
961 const TQString &textString = textLine->string();
963 while ( (x < xPos) && (z < len)) {
968 x += a->width(*fs, textString, z, m_tabWidth);
970 z += textString[z].isHighSurrogate() ? 2 : 1;
972 if ( ( (! nearest) || xPos - oldX < x - xPos ) && z > 0 ) {
979 uint KateRenderer::fontHeight()
981 return config()->fontStruct ()->fontHeight;
984 uint KateRenderer::documentHeight()
986 return m_doc->numLines() * fontHeight();
989 bool KateRenderer::getSelectionBounds(uint line, uint lineLength, uint &start, uint &end)
993 if (m_view->hasSelection() && !m_view->blockSelectionMode())
995 if (m_view->lineIsSelection(line))
997 start = m_view->selStartCol();
998 end = m_view->selEndCol();
1001 else if ((
int)line == m_view->selStartLine())
1003 start = m_view->selStartCol();
1007 else if ((
int)line == m_view->selEndLine())
1010 end = m_view->selEndCol();
1014 else if (m_view->lineHasSelected(line))
1016 start = m_view->selStartCol();
1017 end = m_view->selEndCol();
1030 void KateRenderer::updateConfig ()
1036 m_view->updateRendererConfig();
1041 return attribute(0)->width(*
config()->fontStruct(), TQChar(
' '), m_tabWidth);