Initial refactoring TerminalPainter class.

wilder
Gustavo Carneiro 5 years ago
parent 2a6e520a7a
commit 4ee99c6c17
  1. 51
      src/terminalDisplay/TerminalDisplay.cpp
  2. 140
      src/terminalDisplay/TerminalDisplay.h
  3. 267
      src/terminalDisplay/TerminalPainter.cpp
  4. 51
      src/terminalDisplay/TerminalPainter.hpp

@ -471,8 +471,6 @@ TerminalDisplay::TerminalDisplay(QWidget* parent)
, _filterChain(new TerminalImageFilterChain(this))
, _filterUpdateRequired(true)
, _cursorShape(Enum::BlockCursor)
, _cursorColor(QColor())
, _cursorTextColor(QColor())
, _antialiasText(true)
, _useFontLineCharacters(false)
, _sessionController(nullptr)
@ -565,13 +563,21 @@ TerminalDisplay::TerminalDisplay(QWidget* parent)
connect(KonsoleSettings::self(), &KonsoleSettings::configChanged, this, &TerminalDisplay::setupHeaderVisibility);
_terminalPainter = new TerminalPainter(this);
connect(this, &TerminalDisplay::drawContents, _terminalPainter, &TerminalPainter::drawContents);
connect(this, &TerminalDisplay::drawCurrentResultRect, _terminalPainter, &TerminalPainter::drawCurrentResultRect);
connect(this, &TerminalDisplay::highlightScrolledLines, _terminalPainter, &TerminalPainter::highlightScrolledLines);
connect(this, &TerminalDisplay::highlightScrolledLinesRegion, _terminalPainter, &TerminalPainter::highlightScrolledLinesRegion);
connect(this, &TerminalDisplay::drawBackground, _terminalPainter, &TerminalPainter::drawBackground);
connect(this, &TerminalDisplay::drawCursor, _terminalPainter, &TerminalPainter::drawCursor);
connect(this, &TerminalDisplay::drawCharacters, _terminalPainter, &TerminalPainter::drawCharacters);
connect(this, &TerminalDisplay::drawInputMethodPreeditString, _terminalPainter, &TerminalPainter::drawInputMethodPreeditString);
auto ldrawBackground = [this](QPainter &painter,
const QRect &rect, const QColor &backgroundColor, bool useOpacitySetting) {
_terminalPainter->drawBackground(painter, rect, backgroundColor, useOpacitySetting);
emit drawBackground(painter, rect, backgroundColor, useOpacitySetting);
};
auto ldrawContents = [this](QPainter &paint, const QRect &rect, bool friendly) {
_terminalPainter->drawContents(paint, rect, friendly);
emit drawContents(_image, paint, rect, friendly, _imageSize, _bidiEnabled, _fixedFont, _lineProperties);
};
auto lgetBackgroundColor = [this]() {
return getBackgroundColor();
@ -671,16 +677,6 @@ void TerminalDisplay::resetCursorStyle()
}
}
void TerminalDisplay::setKeyboardCursorColor(const QColor& color)
{
_cursorColor = color;
}
void TerminalDisplay::setKeyboardCursorTextColor(const QColor& color)
{
_cursorTextColor = color;
}
void TerminalDisplay::setOpacity(qreal opacity)
{
QColor color(_blendColor);
@ -924,7 +920,12 @@ void TerminalDisplay::updateImage()
}
if (_highlightScrolledLinesControl.enabled) {
dirtyRegion |= _terminalPainter->highlightScrolledLinesRegion(dirtyRegion.isEmpty());
dirtyRegion |= emit highlightScrolledLinesRegion(dirtyRegion.isEmpty(),
_highlightScrolledLinesControl.timer,
_highlightScrolledLinesControl.previousScrollCount,
_highlightScrolledLinesControl.rect,
_highlightScrolledLinesControl.needToClear,
HIGHLIGHT_SCROLLED_LINES_WIDTH);
}
_screenWindow->resetScrollCount();
@ -983,7 +984,7 @@ void TerminalDisplay::paintEvent(QPaintEvent* pe)
for (const QRect &rect : region) {
dirtyImageRegion += widgetToImage(rect);
_terminalPainter->drawBackground(paint, rect, getBackgroundColor(), true /* use opacity setting */);
emit drawBackground(paint, rect, getBackgroundColor(), true /* use opacity setting */);
}
if (_displayVerticalLine) {
@ -999,11 +1000,13 @@ void TerminalDisplay::paintEvent(QPaintEvent* pe)
paint.setRenderHint(QPainter::TextAntialiasing, _antialiasText);
for (const QRect &rect : qAsConst(dirtyImageRegion)) {
_terminalPainter->drawContents(paint, rect, false);
emit drawContents(_image, paint, rect, false, _imageSize, _bidiEnabled, _fixedFont, _lineProperties);
}
emit drawCurrentResultRect(paint, _searchResultRect);
if (_highlightScrolledLinesControl.enabled) {
emit highlightScrolledLines(paint, _highlightScrolledLinesControl.timer, _highlightScrolledLinesControl.rect);
}
_terminalPainter->drawCurrentResultRect(paint);
_terminalPainter->highlightScrolledLines(paint);
_terminalPainter->drawInputMethodPreeditString(paint, preeditRect());
emit drawInputMethodPreeditString(paint, preeditRect(), _inputMethodData, _image);
paintFilters(paint);
const bool drawDimmed = _dimWhenInactive && !hasFocus();
@ -3131,12 +3134,6 @@ void TerminalDisplay::applyProfile(const Profile::Ptr &profile)
// cursor shape
setKeyboardCursorShape(Enum::CursorShapeEnum(profile->property<int>(Profile::CursorShape)));
// cursor color
// an invalid QColor is used to inform the view widget to
// draw the cursor using the default color( matching the text)
setKeyboardCursorColor(profile->useCustomCursorColor() ? profile->customCursorColor() : QColor());
setKeyboardCursorTextColor(profile->useCustomCursorColor() ? profile->customCursorTextColor() : QColor());
// word characters
setWordCharacters(profile->wordCharacters());
@ -3155,6 +3152,8 @@ void TerminalDisplay::applyProfile(const Profile::Ptr &profile)
_filterChain->setReverseUrlHints(profile->property<bool>(Profile::ReverseUrlHints));
_peekPrimaryShortcut = profile->peekPrimaryKeySequence();
_terminalPainter->applyProfile(profile);
}
void TerminalDisplay::printScreen()

@ -166,36 +166,6 @@ public:
*/
void resetCursorStyle();
/**
* Sets the color used to draw the keyboard cursor.
*
* The keyboard cursor defaults to using the foreground color of the character
* underneath it.
*
* @param color By default, the widget uses the color of the
* character under the cursor to draw the cursor, and inverts the
* color of that character to make sure it is still readable. If @p
* color is a valid QColor, the widget uses that color to draw the
* cursor. If @p color is not an valid QColor, the widget falls back
* to the default behavior.
*/
void setKeyboardCursorColor(const QColor &color);
/**
* Sets the color used to draw the character underneath the keyboard cursor.
*
* The keyboard cursor defaults to using the background color of the
* terminal cell to draw the character at the cursor position.
*
* @param color By default, the widget uses the color of the
* character under the cursor to draw the cursor, and inverts the
* color of that character to make sure it is still readable. If @p
* color is a valid QColor, the widget uses that color to draw the
* character underneath the cursor. If @p color is not an valid QColor,
* the widget falls back to the default behavior.
*/
void setKeyboardCursorTextColor(const QColor &color);
/**
* Returns the number of lines of text which can be displayed in the widget.
*
@ -219,6 +189,11 @@ public:
return _columns;
}
int usedColumns() const
{
return _usedColumns;
}
/**
* Returns the height of the characters in the font used to draw the text in the display.
*/
@ -369,14 +344,79 @@ public:
// toggle the header bar Minimize/Maximize button.
void setExpandedMode(bool expand);
friend class TerminalPainter;
friend class TerminalScrollBar;
TerminalScrollBar *scrollBar()
TerminalScrollBar *scrollBar() const
{
return _scrollBar;
}
qreal opacity() const
{
return _opacity;
}
QRgb blendColor() const
{
return _blendColor;
}
bool cursorBlinking() const
{
return _cursorBlinking;
}
bool textBlinking() const
{
return _textBlinking;
}
Enum::CursorShapeEnum cursorShape() const
{
return _cursorShape;
}
bool boldIntense() const
{
return _boldIntense;
}
bool useFontLineCharacters() const
{
return _useFontLineCharacters;
}
bool bidiEnabled() const
{
return _bidiEnabled;
}
int fontAscent() const
{
return _fontAscent;
}
bool antialiasText() const
{
return _antialiasText;
}
ColorSchemeWallpaper::Ptr wallpaper() const
{
return _wallpaper;
}
struct InputMethodData {
QString preeditString;
QRect previousPreeditRect;
};
// returns true if the cursor's position is on display.
bool isCursorOnDisplay() const;
// returns the position of the cursor in columns and lines
QPoint cursorPosition() const;
public Q_SLOTS:
/**
* Scrolls current ScreenWindow
@ -504,6 +544,8 @@ public Q_SLOTS:
void printScreen();
Character getCursorCharacter(int column, int line);
int loc(int x, int y) const;
Q_SIGNALS:
void requestToggleExpansion();
/**
@ -547,6 +589,20 @@ Q_SIGNALS:
void peekPrimaryRequested(bool doPeek);
void drawContents(Character *image, QPainter &paint, const QRect &rect, bool printerFriendly, int imageSize, bool bidiEnabled, bool &fixedFont,
QVector<LineProperty> lineProperties);
void drawCurrentResultRect(QPainter &painter, QRect searchResultRect);
void highlightScrolledLines(QPainter& painter, QTimer *timer, QRect rect);
QRegion highlightScrolledLinesRegion(bool nothingChanged, QTimer *timer, int &previousScrollCount, QRect &rect, bool &needToClear, int HighlightScrolledLinesWidth);
void drawBackground(QPainter &painter, const QRect &rect, const QColor &backgroundColor, bool useOpacitySetting);
void drawCursor(QPainter &painter, const QRect &rect, const QColor &foregroundColor,
const QColor &backgroundColor, QColor &characterColor);
void drawCharacters(QPainter &painter, const QRect &rect, const QString &text,
const Character *style, const QColor &characterColor);
void drawInputMethodPreeditString(QPainter &painter, const QRect &rect, TerminalDisplay::InputMethodData &inputMethodData, Character *image);
protected:
// events
bool event(QEvent *event) override;
@ -634,12 +690,6 @@ private:
void setupHeaderVisibility();
// returns the position of the cursor in columns and lines
QPoint cursorPosition() const;
// returns true if the cursor's position is on display.
bool isCursorOnDisplay() const;
// redraws the cursor
void updateCursor();
@ -660,8 +710,6 @@ private:
// Boilerplate setup for MessageWidget
KMessageWidget* createMessageWidget(const QString &text);
int loc(int x, int y) const;
// the window onto the terminal screen which this display
// is currently showing.
QPointer<ScreenWindow> _screenWindow;
@ -762,18 +810,6 @@ private:
Enum::CursorShapeEnum _cursorShape;
// cursor color. If it is invalid (by default) then the foreground
// color of the character under the cursor is used
QColor _cursorColor;
// cursor text color. If it is invalid (by default) then the background
// color of the character under the cursor is used
QColor _cursorTextColor;
struct InputMethodData {
QString preeditString;
QRect previousPreeditRect;
};
InputMethodData _inputMethodData;
bool _antialiasText; // do we anti-alias or not

@ -10,7 +10,6 @@
#include "TerminalPainter.hpp"
// Konsole
#include "TerminalDisplay.h"
#include "TerminalScrollBar.hpp"
#include "ExtendedCharTable.h"
#include "../characters/LineBlockCharacters.h"
@ -36,9 +35,20 @@ const QChar LTR_OVERRIDE_CHAR(0x202D);
namespace Konsole
{
TerminalPainter::TerminalPainter(TerminalDisplay *display)
: _display(display)
TerminalPainter::TerminalPainter(QObject *parent)
: QObject(parent)
, m_cursorColor(QColor())
, m_cursorTextColor(QColor())
{}
void TerminalPainter::applyProfile(const Profile::Ptr &profile)
{
// cursor color
// an invalid QColor is used to inform the view widget to
// draw the cursor using the default color( matching the text)7
m_cursorColor = profile->useCustomCursorColor() ? profile->customCursorColor() : QColor();
m_cursorTextColor = profile->useCustomCursorColor() ? profile->customCursorTextColor() : QColor();
}
static inline bool isLineCharString(const QString &string)
{
@ -60,14 +70,17 @@ namespace Konsole
}
}
void TerminalPainter::drawContents(QPainter &paint, const QRect &rect, bool printerFriendly)
void TerminalPainter::drawContents(Character *image, QPainter &paint, const QRect &rect, bool printerFriendly, int imageSize, bool bidiEnabled, bool &fixedFont,
QVector<LineProperty> lineProperties)
{
const int numberOfColumns = _display->_usedColumns;
const auto display = qobject_cast<TerminalDisplay*>(sender());
const int numberOfColumns = display->usedColumns();
QVector<uint> univec;
univec.reserve(numberOfColumns);
for (int y = rect.y(); y <= rect.bottom(); y++) {
int x = rect.x();
if ((_display->_image[_display->loc(rect.x(), y)].character == 0u) && (x != 0)) {
if ((image[display->loc(rect.x(), y)].character == 0u) && (x != 0)) {
x--; // Search for start of multi-column character
}
for (; x <= rect.right(); x++) {
@ -80,10 +93,10 @@ namespace Konsole
uint *disstrU = univec.data();
// is this a single character or a sequence of characters ?
if ((_display->_image[_display->loc(x, y)].rendition & RE_EXTENDED_CHAR) != 0) {
if ((image[display->loc(x, y)].rendition & RE_EXTENDED_CHAR) != 0) {
// sequence of characters
ushort extendedCharLength = 0;
const uint *chars = ExtendedCharTable::instance.lookupExtendedChar(_display->_image[_display->loc(x, y)].character, extendedCharLength);
const uint *chars = ExtendedCharTable::instance.lookupExtendedChar(image[display->loc(x, y)].character, extendedCharLength);
if (chars != nullptr) {
Q_ASSERT(extendedCharLength > 1);
bufferSize += extendedCharLength - 1;
@ -95,39 +108,39 @@ namespace Konsole
}
}
} else {
const uint c = _display->_image[_display->loc(x, y)].character;
const uint c = image[display->loc(x, y)].character;
if (c != 0u) {
Q_ASSERT(p < bufferSize);
disstrU[p++] = c;
}
}
const bool lineDraw = LineBlockCharacters::canDraw(_display->_image[_display->loc(x, y)].character);
const bool doubleWidth = (_display->_image[qMin(_display->loc(x, y) + 1, _display->_imageSize - 1)].character == 0);
const CharacterColor currentForeground = _display->_image[_display->loc(x, y)].foregroundColor;
const CharacterColor currentBackground = _display->_image[_display->loc(x, y)].backgroundColor;
const RenditionFlags currentRendition = _display->_image[_display->loc(x, y)].rendition;
const QChar::Script currentScript = QChar::script(baseCodePoint(_display->_image[_display->loc(x, y)]));
const bool lineDraw = LineBlockCharacters::canDraw(image[display->loc(x, y)].character);
const bool doubleWidth = (image[qMin(display->loc(x, y) + 1, imageSize - 1)].character == 0);
const CharacterColor currentForeground = image[display->loc(x, y)].foregroundColor;
const CharacterColor currentBackground = image[display->loc(x, y)].backgroundColor;
const RenditionFlags currentRendition = image[display->loc(x, y)].rendition;
const QChar::Script currentScript = QChar::script(baseCodePoint(image[display->loc(x, y)]));
const auto isInsideDrawArea = [&](int column) { return column <= rect.right(); };
const auto hasSameColors = [&](int column) {
return _display->_image[_display->loc(column, y)].foregroundColor == currentForeground
&& _display->_image[_display->loc(column, y)].backgroundColor == currentBackground;
return image[display->loc(column, y)].foregroundColor == currentForeground
&& image[display->loc(column, y)].backgroundColor == currentBackground;
};
const auto hasSameRendition = [&](int column) {
return (_display->_image[_display->loc(column, y)].rendition & ~RE_EXTENDED_CHAR)
return (image[display->loc(column, y)].rendition & ~RE_EXTENDED_CHAR)
== (currentRendition & ~RE_EXTENDED_CHAR);
};
const auto hasSameWidth = [&](int column) {
const int characterLoc = qMin(_display->loc(column, y) + 1, _display->_imageSize - 1);
return (_display->_image[characterLoc].character == 0) == doubleWidth;
const int characterLoc = qMin(display->loc(column, y) + 1, imageSize - 1);
return (image[characterLoc].character == 0) == doubleWidth;
};
const auto hasSameLineDrawStatus = [&](int column) {
return LineBlockCharacters::canDraw(_display->_image[_display->loc(column, y)].character)
return LineBlockCharacters::canDraw(image[display->loc(column, y)].character)
== lineDraw;
};
const auto isSameScript = [&](int column) {
const QChar::Script script = QChar::script(baseCodePoint(_display->_image[_display->loc(column, y)]));
const QChar::Script script = QChar::script(baseCodePoint(image[display->loc(column, y)]));
if (currentScript == QChar::Script_Common || script == QChar::Script_Common
|| currentScript == QChar::Script_Inherited || script == QChar::Script_Inherited) {
return true;
@ -135,9 +148,9 @@ namespace Konsole
return currentScript == script;
};
const auto canBeGrouped = [&](int column) {
return _display->_image[_display->loc(column, y)].character <= 0x7e
|| (_display->_image[_display->loc(column, y)].rendition & RE_EXTENDED_CHAR)
|| (_display->_bidiEnabled && !doubleWidth);
return image[display->loc(column, y)].character <= 0x7e
|| (image[display->loc(column, y)].rendition & RE_EXTENDED_CHAR)
|| (bidiEnabled && !doubleWidth);
};
if (canBeGrouped(x)) {
@ -145,8 +158,8 @@ namespace Konsole
&& hasSameRendition(x + len) && hasSameWidth(x + len)
&& hasSameLineDrawStatus(x + len) && isSameScript(x + len)
&& canBeGrouped(x + len)) {
const uint c = _display->_image[_display->loc(x + len, y)].character;
if ((_display->_image[_display->loc(x + len, y)].rendition & RE_EXTENDED_CHAR) != 0) {
const uint c = image[display->loc(x + len, y)].character;
if ((image[display->loc(x + len, y)].rendition & RE_EXTENDED_CHAR) != 0) {
// sequence of characters
ushort extendedCharLength = 0;
const uint *chars = ExtendedCharTable::instance.lookupExtendedChar(c, extendedCharLength);
@ -177,33 +190,33 @@ namespace Konsole
// Group spaces following any non-wide character with the character. This allows for
// rendering ambiguous characters with wide glyphs without clipping them.
while (!doubleWidth && isInsideDrawArea(x + len)
&& _display->_image[_display->loc(x + len, y)].character == ' ' && hasSameColors(x + len)
&& image[display->loc(x + len, y)].character == ' ' && hasSameColors(x + len)
&& hasSameRendition(x + len)) {
// disstrU intentionally not modified - trailing spaces are meaningless
len++;
}
}
if ((x + len < _display->_usedColumns) && (_display->_image[_display->loc(x + len, y)].character == 0u)) {
if ((x + len < display->usedColumns()) && (image[display->loc(x + len, y)].character == 0u)) {
len++; // Adjust for trailing part of multi-column character
}
const bool save__fixedFont = _display->_fixedFont;
const bool save__fixedFont = fixedFont;
if (lineDraw) {
_display->_fixedFont = false;
fixedFont = false;
}
if (doubleWidth) {
_display->_fixedFont = false;
fixedFont = false;
}
univec.resize(p);
QMatrix textScale;
if (y < _display->_lineProperties.size()) {
if ((_display->_lineProperties[y] & LINE_DOUBLEWIDTH) != 0) {
if (y < lineProperties.size()) {
if ((lineProperties[y] & LINE_DOUBLEWIDTH) != 0) {
textScale.scale(2, 1);
}
if ((_display->_lineProperties[y] & LINE_DOUBLEHEIGHT) != 0) {
if ((lineProperties[y] & LINE_DOUBLEHEIGHT) != 0) {
textScale.scale(1, 2);
}
}
@ -212,10 +225,10 @@ namespace Konsole
paint.setWorldTransform(QTransform(textScale), true);
// Calculate the area in which the text will be drawn
QRect textArea = QRect(_display->contentRect().left() + _display->contentsRect().left() + _display->fontWidth() * x,
_display->contentRect().top() + _display->contentsRect().top() + _display->fontHeight() * y,
_display->fontWidth() * len,
_display->fontHeight());
QRect textArea = QRect(display->contentRect().left() + display->contentsRect().left() + display->fontWidth() * x,
display->contentRect().top() + display->contentsRect().top() + display->fontHeight() * y,
display->fontWidth() * len,
display->fontHeight());
//move the calculated area to take account of scaling applied to the painter.
//the position of the area from the origin (0,0) is scaled
@ -232,21 +245,22 @@ namespace Konsole
drawPrinterFriendlyTextFragment(paint,
textArea,
unistr,
&_display->_image[_display->loc(x, y)]);
&image[display->loc(x, y)]);
} else {
drawTextFragment(paint,
textArea,
unistr,
&_display->_image[_display->loc(x, y)]);
&image[display->loc(x, y)],
display->colorTable());
}
_display->_fixedFont = save__fixedFont;
fixedFont = save__fixedFont;
paint.setWorldTransform(QTransform(textScale.inverted()), true);
if (y < _display->_lineProperties.size() - 1) {
if (y < lineProperties.size() - 1) {
if ((_display->_lineProperties[y] & LINE_DOUBLEHEIGHT) != 0) {
if ((lineProperties[y] & LINE_DOUBLEHEIGHT) != 0) {
y++;
}
}
@ -256,83 +270,85 @@ namespace Konsole
}
}
void TerminalPainter::drawCurrentResultRect(QPainter &painter)
void TerminalPainter::drawCurrentResultRect(QPainter &painter, QRect searchResultRect)
{
if (_display->_screenWindow->currentResultLine() == -1) {
const auto display = qobject_cast<TerminalDisplay*>(sender());
if (display->screenWindow()->currentResultLine() == -1) {
return;
}
_display->_searchResultRect.setRect(0, _display->contentRect().top() + (_display->_screenWindow->currentResultLine() - _display->_screenWindow->currentLine()) * _display->fontHeight(),
_display->columns() * _display->fontWidth(), _display->fontHeight());
painter.fillRect(_display->_searchResultRect, QColor(0, 0, 255, 80));
searchResultRect.setRect(0, display->contentRect().top() + (display->screenWindow()->currentResultLine() - display->screenWindow()->currentLine()) * display->fontHeight(),
display->columns() * display->fontWidth(), display->fontHeight());
painter.fillRect(searchResultRect, QColor(0, 0, 255, 80));
}
void TerminalPainter::highlightScrolledLines(QPainter& painter)
void TerminalPainter::highlightScrolledLines(QPainter& painter, QTimer *timer, QRect rect)
{
if (!_display->_highlightScrolledLinesControl.enabled) {
return;
}
const auto display = qobject_cast<TerminalDisplay*>(sender());
QColor color = QColor(_display->_colorTable[Color4Index]);
color.setAlpha(_display->_highlightScrolledLinesControl.timer->isActive() ? 255 : 150);
painter.fillRect(_display->_highlightScrolledLinesControl.rect, color);
QColor color = QColor(display->colorTable()[Color4Index]);
color.setAlpha(timer->isActive() ? 255 : 150);
painter.fillRect(rect, color);
}
QRegion TerminalPainter::highlightScrolledLinesRegion(bool nothingChanged)
QRegion TerminalPainter::highlightScrolledLinesRegion(bool nothingChanged, QTimer *timer, int &previousScrollCount, QRect &rect, bool &needToClear, int HighlightScrolledLinesWidth)
{
const auto display = qobject_cast<TerminalDisplay*>(sender());
QRegion dirtyRegion;
const int highlightLeftPosition = _display->scrollBar()->scrollBarPosition() == Enum::ScrollBarLeft ? _display->scrollBar()->width() : 0;
const int highlightLeftPosition = display->scrollBar()->scrollBarPosition() == Enum::ScrollBarLeft ? display->scrollBar()->width() : 0;
int start = 0;
int nb_lines = abs(_display->_screenWindow->scrollCount());
if (nb_lines > 0 && _display->scrollBar()->maximum() > 0) {
int nb_lines = abs(display->screenWindow()->scrollCount());
if (nb_lines > 0 && display->scrollBar()->maximum() > 0) {
QRect new_highlight;
bool addToCurrentHighlight = _display->_highlightScrolledLinesControl.timer->isActive() &&
(_display->_screenWindow->scrollCount() * _display->_highlightScrolledLinesControl.previousScrollCount > 0);
bool addToCurrentHighlight = timer->isActive() &&
(display->screenWindow()->scrollCount() * previousScrollCount > 0);
if (addToCurrentHighlight) {
if (_display->_screenWindow->scrollCount() > 0) {
start = -1 * (_display->_highlightScrolledLinesControl.previousScrollCount + _display->screenWindow()->scrollCount()) + _display->screenWindow()->windowLines();
if (display->screenWindow()->scrollCount() > 0) {
start = -1 * (previousScrollCount + display->screenWindow()->scrollCount()) + display->screenWindow()->windowLines();
} else {
start = -1 * _display->_highlightScrolledLinesControl.previousScrollCount;
start = -1 * previousScrollCount;
}
_display->_highlightScrolledLinesControl.previousScrollCount += _display->_screenWindow->scrollCount();
previousScrollCount += display->screenWindow()->scrollCount();
} else {
start = _display->_screenWindow->scrollCount() > 0 ? _display->_screenWindow->windowLines() - nb_lines : 0;
_display->_highlightScrolledLinesControl.previousScrollCount = _display->_screenWindow->scrollCount();
start = display->screenWindow()->scrollCount() > 0 ? display->screenWindow()->windowLines() - nb_lines : 0;
previousScrollCount = display->screenWindow()->scrollCount();
}
new_highlight.setRect(highlightLeftPosition, _display->contentRect().top() + start * _display->fontHeight(), _display->HIGHLIGHT_SCROLLED_LINES_WIDTH, nb_lines * _display->fontHeight());
new_highlight.setTop(std::max(new_highlight.top(), _display->contentRect().top()));
new_highlight.setBottom(std::min(new_highlight.bottom(), _display->contentRect().bottom()));
new_highlight.setRect(highlightLeftPosition, display->contentRect().top() + start * display->fontHeight(), HighlightScrolledLinesWidth, nb_lines * display->fontHeight());
new_highlight.setTop(std::max(new_highlight.top(), display->contentRect().top()));
new_highlight.setBottom(std::min(new_highlight.bottom(), display->contentRect().bottom()));
if (!new_highlight.isValid()) {
new_highlight = QRect(0, 0, 0, 0);
}
if (addToCurrentHighlight) {
_display->_highlightScrolledLinesControl.rect |= new_highlight;
rect |= new_highlight;
} else {
dirtyRegion |= _display->_highlightScrolledLinesControl.rect;
_display->_highlightScrolledLinesControl.rect = new_highlight;
dirtyRegion |= rect;
rect = new_highlight;
}
_display->_highlightScrolledLinesControl.timer->start();
} else if (!nothingChanged || _display->_highlightScrolledLinesControl.needToClear) {
dirtyRegion = _display->_highlightScrolledLinesControl.rect;
_display->_highlightScrolledLinesControl.rect.setRect(0, 0, 0, 0);
_display->_highlightScrolledLinesControl.needToClear = false;
timer->start();
} else if (!nothingChanged || needToClear) {
dirtyRegion = rect;
rect.setRect(0, 0, 0, 0);
needToClear = false;
}
return dirtyRegion;
}
void TerminalPainter::drawTextFragment(QPainter &painter, const QRect &rect, const QString &text,
const Character *style)
const Character *style, const ColorEntry *colorTable)
{
// setup painter
const QColor foregroundColor = style->foregroundColor.color(_display->_colorTable);
const QColor backgroundColor = style->backgroundColor.color(_display->_colorTable);
const QColor foregroundColor = style->foregroundColor.color(colorTable);
const QColor backgroundColor = style->backgroundColor.color(colorTable);
if (backgroundColor != _display->_colorTable[DEFAULT_BACK_COLOR]) {
if (backgroundColor != colorTable[DEFAULT_BACK_COLOR]) {
drawBackground(painter, rect, backgroundColor, false);
}
@ -358,16 +374,18 @@ namespace Konsole
void TerminalPainter::drawBackground(QPainter &painter, const QRect &rect, const QColor &backgroundColor,
bool useOpacitySetting)
{
if (useOpacitySetting && !_display->_wallpaper->isNull() &&
_display->_wallpaper->draw(painter, rect, _display->_opacity)) {
} else if (qAlpha(_display->_blendColor) < 0xff && useOpacitySetting) {
const auto display = qobject_cast<TerminalDisplay*>(sender());
if (useOpacitySetting && !display->wallpaper()->isNull() &&
display->wallpaper()->draw(painter, rect, display->opacity())) {
} else if (qAlpha(display->blendColor()) < 0xff && useOpacitySetting) {
#if defined(Q_OS_MACOS)
// TODO: On MacOS, using CompositionMode doesn't work. Altering the
// transparency in the color scheme alters the brightness.
painter.fillRect(rect, backgroundColor);
#else
QColor color(backgroundColor);
color.setAlpha(qAlpha(_display->_blendColor));
color.setAlpha(qAlpha(display->blendColor()));
const QPainter::CompositionMode originalMode = painter.compositionMode();
painter.setCompositionMode(QPainter::CompositionMode_Source);
@ -382,38 +400,40 @@ namespace Konsole
void TerminalPainter::drawCursor(QPainter &painter, const QRect &rect, const QColor &foregroundColor,
const QColor &backgroundColor, QColor &characterColor)
{
if (_display->_cursorBlinking) {
const auto display = qobject_cast<TerminalDisplay*>(sender());
if (display->cursorBlinking()) {
return;
}
QRectF cursorRect = rect.adjusted(0, 1, 0, 0);
QColor cursorColor = _display->_cursorColor.isValid() ? _display->_cursorColor : foregroundColor;
QColor cursorColor = m_cursorColor.isValid() ? m_cursorColor : foregroundColor;
QPen pen(cursorColor);
// TODO: the relative pen width to draw the cursor is a bit hacky
// and set to 1/12 of the font width. Visually it seems to work at
// all scales but there must be better ways to do it
const qreal width = qMax(_display->fontWidth() / 12.0, 1.0);
const qreal width = qMax(display->fontWidth() / 12.0, 1.0);
const qreal halfWidth = width / 2.0;
pen.setWidthF(width);
painter.setPen(pen);
if (_display->_cursorShape == Enum::BlockCursor) {
if (display->cursorShape() == Enum::BlockCursor) {
painter.drawRect(cursorRect.adjusted(halfWidth, halfWidth, -halfWidth, -halfWidth));
if (_display->hasFocus()) {
if (display->hasFocus()) {
painter.fillRect(cursorRect, cursorColor);
characterColor = _display->_cursorTextColor.isValid() ? _display->_cursorTextColor : backgroundColor;
characterColor = m_cursorTextColor.isValid() ? m_cursorTextColor : backgroundColor;
}
} else if (_display->_cursorShape == Enum::UnderlineCursor) {
} else if (display->cursorShape() == Enum::UnderlineCursor) {
QLineF line(cursorRect.left() + halfWidth,
cursorRect.bottom() - halfWidth,
cursorRect.right() - halfWidth,
cursorRect.bottom() - halfWidth);
painter.drawLine(line);
} else if (_display->_cursorShape == Enum::IBeamCursor) {
} else if (display->cursorShape() == Enum::IBeamCursor) {
QLineF line(cursorRect.left() + halfWidth,
cursorRect.top() + halfWidth,
cursorRect.left() + halfWidth,
@ -425,7 +445,9 @@ namespace Konsole
void TerminalPainter::drawCharacters(QPainter &painter, const QRect &rect, const QString &text,
const Character *style, const QColor &characterColor)
{
if (_display->_textBlinking && ((style->rendition & RE_BLINK) != 0)) {
const auto display = qobject_cast<TerminalDisplay*>(sender());
if (display->textBlinking() && ((style->rendition & RE_BLINK) != 0)) {
return;
}
@ -435,17 +457,17 @@ namespace Konsole
static constexpr int MaxFontWeight = 99;
const int normalWeight = _display->font().weight();
const int normalWeight = display->font().weight();
const int boldWeight = qMin(normalWeight + 26, MaxFontWeight);
const auto isBold = [boldWeight](const QFont &font) { return font.weight() >= boldWeight; };
const bool useBold = (((style->rendition & RE_BOLD) != 0) && _display->_boldIntense);
const bool useUnderline = ((style->rendition & RE_UNDERLINE) != 0) || _display->font().underline();
const bool useItalic = ((style->rendition & RE_ITALIC) != 0) || _display->font().italic();
const bool useStrikeOut = ((style->rendition & RE_STRIKEOUT) != 0) || _display->font().strikeOut();
const bool useOverline = ((style->rendition & RE_OVERLINE) != 0) || _display->font().overline();
const bool useBold = (((style->rendition & RE_BOLD) != 0) && display->boldIntense());
const bool useUnderline = ((style->rendition & RE_UNDERLINE) != 0) || display->font().underline();
const bool useItalic = ((style->rendition & RE_ITALIC) != 0) || display->font().italic();
const bool useStrikeOut = ((style->rendition & RE_STRIKEOUT) != 0) || display->font().strikeOut();
const bool useOverline = ((style->rendition & RE_OVERLINE) != 0) || display->font().overline();
QFont currentFont = painter.font();
@ -464,7 +486,7 @@ namespace Konsole
}
// setup pen
const QColor foregroundColor = style->foregroundColor.color(_display->_colorTable);
const QColor foregroundColor = style->foregroundColor.color(display->colorTable());
const QColor color = characterColor.isValid() ? characterColor : foregroundColor;
QPen pen = painter.pen();
if (pen.color() != color) {
@ -476,53 +498,54 @@ namespace Konsole
const auto origClipRegion = painter.clipRegion();
painter.setClipRect(rect);
// draw text
if (isLineCharString(text) && !_display->_useFontLineCharacters) {
drawLineCharString(painter, rect.x(), rect.y(), text, style);
if (isLineCharString(text) && !display->useFontLineCharacters()) {
drawLineCharString(display, painter, rect.x(), rect.y(), text, style);
} else {
painter.setLayoutDirection(Qt::LeftToRight);
if (_display->_bidiEnabled) {
painter.drawText(rect.x(), rect.y() + _display->_fontAscent + _display->lineSpacing(), text);
if (display->bidiEnabled()) {
painter.drawText(rect.x(), rect.y() + display->fontAscent() + display->lineSpacing(), text);
} else {
painter.drawText(rect.x(), rect.y() + _display->_fontAscent + _display->lineSpacing(), LTR_OVERRIDE_CHAR + text);
painter.drawText(rect.x(), rect.y() + display->fontAscent() + display->lineSpacing(), LTR_OVERRIDE_CHAR + text);
}
}
painter.setClipRegion(origClipRegion);
painter.setClipping(origClipping);
}
void TerminalPainter::drawLineCharString(QPainter &painter, int x, int y, const QString &str,
const Character *attributes)
void TerminalPainter::drawLineCharString(TerminalDisplay *display, QPainter &painter, int x, int y, const QString &str, const Character *attributes)
{
painter.setRenderHint(QPainter::Antialiasing, _display->_antialiasText);
painter.setRenderHint(QPainter::Antialiasing, display->antialiasText());
const bool useBoldPen = (attributes->rendition & RE_BOLD) != 0 && _display->_boldIntense;
const bool useBoldPen = (attributes->rendition & RE_BOLD) != 0 && display->boldIntense();
QRect cellRect = {x, y, _display->fontWidth(), _display->fontHeight()};
QRect cellRect = {x, y, display->fontWidth(), display->fontHeight()};
for (int i = 0; i < str.length(); i++) {
LineBlockCharacters::draw(painter, cellRect.translated(i * _display->fontWidth(), 0), str[i], useBoldPen);
LineBlockCharacters::draw(painter, cellRect.translated(i * display->fontWidth(), 0), str[i], useBoldPen);
}
painter.setRenderHint(QPainter::Antialiasing, false);
}
void TerminalPainter::drawInputMethodPreeditString(QPainter &painter, const QRect &rect)
void TerminalPainter::drawInputMethodPreeditString(QPainter &painter, const QRect &rect, TerminalDisplay::InputMethodData &inputMethodData, Character *image)
{
if (_display->_inputMethodData.preeditString.isEmpty() || !_display->isCursorOnDisplay()) {
const auto display = qobject_cast<TerminalDisplay*>(sender());
if (inputMethodData.preeditString.isEmpty() || !display->isCursorOnDisplay()) {
return;
}
const QPoint cursorPos = _display->cursorPosition();
const QPoint cursorPos = display->cursorPosition();
QColor characterColor;
const QColor background = _display->_colorTable[DEFAULT_BACK_COLOR];
const QColor foreground = _display->_colorTable[DEFAULT_FORE_COLOR];
const Character *style = &_display->_image[_display->loc(cursorPos.x(), cursorPos.y())];
const QColor background = display->colorTable()[DEFAULT_BACK_COLOR];
const QColor foreground = display->colorTable()[DEFAULT_FORE_COLOR];
const Character *style = &image[display->loc(cursorPos.x(), cursorPos.y())];
drawBackground(painter, rect, background, true);
drawCursor(painter, rect, foreground, background, characterColor);
drawCharacters(painter, rect, _display->_inputMethodData.preeditString, style, characterColor);
drawCharacters(painter, rect, inputMethodData.preeditString, style, characterColor);
_display->_inputMethodData.previousPreeditRect = rect;
inputMethodData.previousPreeditRect = rect;
}
}

@ -20,6 +20,8 @@
#include "ScreenWindow.h"
#include "Enumeration.h"
#include "colorscheme/ColorSchemeWallpaper.h"
#include "profile/Profile.h"
#include "terminalDisplay/TerminalDisplay.h"
class QRect;
class QColor;
@ -34,55 +36,68 @@ namespace Konsole
class Character;
class TerminalDisplay;
class TerminalPainter
class TerminalPainter : public QObject
{
public:
explicit TerminalPainter(TerminalDisplay *display);
explicit TerminalPainter(QObject *parent = nullptr);
~TerminalPainter() = default;
void applyProfile(const Profile::Ptr &profile);
// -- Drawing helpers --
// divides the part of the display specified by 'rect' into
// fragments according to their colors and styles and calls
// drawTextFragment() or drawPrinterFriendlyTextFragment()
// to draw the fragments
void drawContents(QPainter &paint, const QRect &rect, bool PrinterFriendly);
void drawContents(Character *image, QPainter &paint, const QRect &rect, bool PrinterFriendly, int imageSize, bool bidiEnabled, bool &fixedFont,
QVector<LineProperty> lineProperties);
// draw a transparent rectangle over the line of the current match
void drawCurrentResultRect(QPainter &painter);
void drawCurrentResultRect(QPainter &painter, QRect searchResultRect);
// draw a thin highlight on the left of the screen for lines that have been scrolled into view
void highlightScrolledLines(QPainter& painter);
// compute which region need to be repainted for scrolled lines highlight
QRegion highlightScrolledLinesRegion(bool nothingChanged);
void highlightScrolledLines(QPainter& painter, QTimer *timer, QRect rect);
// draws a section of text, all the text in this section
// has a common color and style
void drawTextFragment(QPainter &painter, const QRect &rect, const QString &text,
const Character *style);
// compute which region need to be repainted for scrolled lines highlight
QRegion highlightScrolledLinesRegion(bool nothingChanged, QTimer *timer, int &previousScrollCount, QRect &rect, bool &needToClear, int HighlightScrolledLinesWidth);
void drawPrinterFriendlyTextFragment(QPainter &painter, const QRect &rect, const QString &text,
const Character *style);
// draws the background for a text fragment
// if useOpacitySetting is true then the color's alpha value will be set to
// the display's transparency (set with setOpacity()), otherwise the background
// will be drawn fully opaque
void drawBackground(QPainter &painter, const QRect &rect, const QColor &backgroundColor,
bool useOpacitySetting);
// draws the cursor character
void drawCursor(QPainter &painter, const QRect &rect, const QColor &foregroundColor,
const QColor &backgroundColor, QColor &characterColor);
// draws the characters or line graphics in a text fragment
void drawCharacters(QPainter &painter, const QRect &rect, const QString &text,
const Character *style, const QColor &characterColor);
// draws a string of line graphics
void drawLineCharString(QPainter &painter, int x, int y, const QString &str,
const Character *attributes);
// draws the preedit string for input methods
void drawInputMethodPreeditString(QPainter &painter, const QRect &rect);
void drawInputMethodPreeditString(QPainter &painter, const QRect &rect, TerminalDisplay::InputMethodData &inputMethodData, Character *image);
private:
// draws a string of line graphics
void drawLineCharString(TerminalDisplay *display, QPainter &painter, int x, int y, const QString &str, const Character *attributes);
// draws a section of text, all the text in this section
// has a common color and style
void drawTextFragment(QPainter &painter, const QRect &rect, const QString &text,
const Character *style, const ColorEntry *colorTable);
void drawPrinterFriendlyTextFragment(QPainter &painter, const QRect &rect, const QString &text,
const Character *style);
// cursor color. If it is invalid (by default) then the foreground
// color of the character under the cursor is used
QColor m_cursorColor;
TerminalDisplay *_display;
// cursor text color. If it is invalid (by default) then the background
// color of the character under the cursor is used
QColor m_cursorTextColor;
};
}

Loading…
Cancel
Save