diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,6 +92,7 @@ ExtendedCharTable.cpp TerminalDisplay.cpp TerminalDisplayAccessible.cpp + TerminalScrollBar.cpp ViewContainer.cpp ViewContainerTabBar.cpp ViewManager.cpp diff --git a/src/EditProfileDialog.cpp b/src/EditProfileDialog.cpp --- a/src/EditProfileDialog.cpp +++ b/src/EditProfileDialog.cpp @@ -60,6 +60,7 @@ #include "ShellCommand.h" #include "WindowSystemInfo.h" #include "Shortcut_p.h" +#include "TerminalScrollBar.h" using namespace Konsole; @@ -1276,9 +1277,9 @@ // setup scrollbar radio int scrollBarPosition = profile->property(Profile::ScrollBarPosition); - const auto positions = QVector{ {_ui->scrollBarHiddenButton, Enum::ScrollBarHidden, SLOT(hideScrollBar())}, - {_ui->scrollBarLeftButton, Enum::ScrollBarLeft, SLOT(showScrollBarLeft())}, - {_ui->scrollBarRightButton, Enum::ScrollBarRight, SLOT(showScrollBarRight())}}; + const auto positions = QVector{ {_ui->scrollBarHiddenButton, TerminalScrollBar::Position::Hidden, SLOT(hideScrollBar())}, + {_ui->scrollBarLeftButton, TerminalScrollBar::Position::Left, SLOT(showScrollBarLeft())}, + {_ui->scrollBarRightButton, TerminalScrollBar::Position::Right, SLOT(showScrollBarRight())}}; setupRadio(positions, scrollBarPosition); @@ -1319,17 +1320,17 @@ void EditProfileDialog::hideScrollBar() { - updateTempProfileProperty(Profile::ScrollBarPosition, Enum::ScrollBarHidden); + updateTempProfileProperty(Profile::ScrollBarPosition, TerminalScrollBar::Position::Hidden); } void EditProfileDialog::showScrollBarLeft() { - updateTempProfileProperty(Profile::ScrollBarPosition, Enum::ScrollBarLeft); + updateTempProfileProperty(Profile::ScrollBarPosition, TerminalScrollBar::Position::Left); } void EditProfileDialog::showScrollBarRight() { - updateTempProfileProperty(Profile::ScrollBarPosition, Enum::ScrollBarRight); + updateTempProfileProperty(Profile::ScrollBarPosition, TerminalScrollBar::Position::Right); } void EditProfileDialog::scrollFullPage() diff --git a/src/Enumeration.h b/src/Enumeration.h --- a/src/Enumeration.h +++ b/src/Enumeration.h @@ -50,19 +50,6 @@ UnlimitedHistory = 2 }; - /** - * This enum describes the positions where the terminal display's - * scroll bar may be placed. - */ - enum ScrollBarPositionEnum { - /** Show the scroll-bar on the left of the terminal display. */ - ScrollBarLeft = 0, - /** Show the scroll-bar on the right of the terminal display. */ - ScrollBarRight = 1, - /** Do not show the scroll-bar. */ - ScrollBarHidden = 2 - }; - /** * This enum describes the amount that Page Up/Down scroll by. */ diff --git a/src/Profile.cpp b/src/Profile.cpp --- a/src/Profile.cpp +++ b/src/Profile.cpp @@ -32,6 +32,7 @@ // Konsole #include "Enumeration.h" +#include "TerminalScrollBar.h" using namespace Konsole; @@ -181,7 +182,7 @@ setProperty(HistoryMode, Enum::FixedSizeHistory); setProperty(HistorySize, 1000); - setProperty(ScrollBarPosition, Enum::ScrollBarRight); + setProperty(ScrollBarPosition, TerminalScrollBar::Position::Right); setProperty(ScrollFullPage, false); setProperty(FlowControlEnabled, true); diff --git a/src/TerminalDisplay.h b/src/TerminalDisplay.h --- a/src/TerminalDisplay.h +++ b/src/TerminalDisplay.h @@ -33,6 +33,7 @@ #include "ColorScheme.h" #include "Enumeration.h" #include "ScrollState.h" +#include "TerminalScrollBar.h" class QDrag; class QDragEnterEvent; @@ -53,6 +54,8 @@ class FilterChain; class TerminalImageFilterChain; class SessionController; +class TerminalScrollBar; + /** * A widget which displays output from a terminal emulation and sends input keypresses and mouse activity * to the terminal. @@ -92,26 +95,17 @@ /** Sets the background picture */ void setWallpaper(ColorSchemeWallpaper::Ptr p); - /** - * Specifies whether the terminal display has a vertical scroll bar, and if so whether it - * is shown on the left or right side of the display. - */ - void setScrollBarPosition(Enum::ScrollBarPositionEnum position); - Enum::ScrollBarPositionEnum scrollBarPosition() const - { - return _scrollbarLocation; - } + TerminalScrollBar *scrollBar() const; - /** - * Sets the current position and range of the display's scroll bar. - * - * @param cursor The position of the scroll bar's thumb. - * @param slines The maximum value of the scroll bar. - */ - void setScroll(int cursor, int slines); + /** connected to the valueChange on the scrollBar */ + void scrollBarValueChanged(int value); + + /** connected to the positionChanged on the scrollBar */ + void scrollBarPositionChanged(TerminalScrollBar::Position position); void setScrollFullPage(bool fullPage); bool scrollFullPage() const; + void updateScrollBarPalette(); /** * Returns the display's filter chain. When the image for the display is updated, @@ -785,11 +779,9 @@ void inputMethodEvent(QInputMethodEvent *event) Q_DECL_OVERRIDE; QVariant inputMethodQuery(Qt::InputMethodQuery query) const Q_DECL_OVERRIDE; - void updateScrollBarPalette(); protected Q_SLOTS: - void scrollBarPositionChanged(int value); void blinkTextEvent(); void blinkCursorEvent(); @@ -964,8 +956,7 @@ bool _copyTextAsHTML; Enum::MiddleClickPasteModeEnum _middleClickPasteMode; - QScrollBar *_scrollBar; - Enum::ScrollBarPositionEnum _scrollbarLocation; + TerminalScrollBar *_scrollBar; bool _scrollFullPage; QString _wordCharacters; int _bellMode; @@ -1073,6 +1064,6 @@ int _timerId; }; -} +} #endif // TERMINALDISPLAY_H diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -396,7 +396,6 @@ , _copyTextAsHTML(true) , _middleClickPasteMode(Enum::PasteFromX11Selection) , _scrollBar(nullptr) - , _scrollbarLocation(Enum::ScrollBarRight) , _scrollFullPage(false) , _wordCharacters(QStringLiteral(":@-./_~")) , _bellMode(Enum::NotifyBell) @@ -446,13 +445,12 @@ _contentRect = QRect(_margin, _margin, 1, 1); // create scroll bar for scrolling output up and down - _scrollBar = new QScrollBar(this); + _scrollBar = new TerminalScrollBar(this); // set the scroll bar's slider to occupy the whole area of the scroll bar initially - setScroll(0, 0); - _scrollBar->setCursor(Qt::ArrowCursor); - connect(_scrollBar, &QScrollBar::valueChanged, this, &Konsole::TerminalDisplay::scrollBarPositionChanged); + _scrollBar->setScroll(0, 0); + connect(_scrollBar, &QScrollBar::valueChanged, this, &Konsole::TerminalDisplay::scrollBarValueChanged); connect(_scrollBar, &QScrollBar::sliderMoved, this, &Konsole::TerminalDisplay::viewScrolledByUser); - + connect(_scrollBar, &TerminalScrollBar::positionChanged, this, &Konsole::TerminalDisplay::scrollBarPositionChanged); // setup timers for blinking text _blinkTextTimer = new QTimer(this); _blinkTextTimer->setInterval(TEXT_BLINK_DELAY); @@ -520,6 +518,11 @@ _outputSuspendedMessageWidget = nullptr; } +TerminalScrollBar *TerminalDisplay::scrollBar() const +{ + return _scrollBar; +} + /* ------------------------------------------------------------------------- */ /* */ /* Display Operations */ @@ -1103,10 +1106,16 @@ // Set the QT_FLUSH_PAINT environment variable to '1' before starting the // application to monitor repainting. // + const int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->themeAwareWidth(); + const int SCROLLBAR_CONTENT_GAP = 1; QRect scrollRect; - scrollRect.setLeft(0); - scrollRect.setRight(width()); - + if (_scrollBar->position() == TerminalScrollBar::Position::Left) { + scrollRect.setLeft(scrollBarWidth + SCROLLBAR_CONTENT_GAP); + scrollRect.setRight(width()); + } else { + scrollRect.setLeft(0); + scrollRect.setRight(width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP); + } void* firstCharPos = &_image[ region.top() * _columns ]; void* lastCharPos = &_image[(region.top() + abs(lines)) * _columns ]; @@ -1238,7 +1247,7 @@ const int lines = _screenWindow->windowLines(); const int columns = _screenWindow->windowColumns(); - setScroll(_screenWindow->currentLine() , _screenWindow->lineCount()); + _scrollBar->setScroll(_screenWindow->currentLine() , _screenWindow->lineCount()); Q_ASSERT(_usedLines <= _lines); Q_ASSERT(_usedColumns <= _columns); @@ -2028,17 +2037,18 @@ void TerminalDisplay::calcGeometry() { - _scrollBar->resize(_scrollBar->sizeHint().width(), contentsRect().height()); _contentRect = contentsRect().adjusted(_margin, _margin, -_margin, -_margin); - switch (_scrollbarLocation) { - case Enum::ScrollBarHidden : + _scrollBar->fixGeometry(); + + switch (_scrollBar->position()) { + case TerminalScrollBar::Position::Hidden: break; - case Enum::ScrollBarLeft : - _scrollBar->move(contentsRect().topLeft()); + case TerminalScrollBar::Position::Left : + _contentRect.setLeft(_contentRect.left() + _scrollBar->themeAwareWidth()); break; - case Enum::ScrollBarRight: - _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width() - 1, 0)); + case TerminalScrollBar::Position::Right: + _contentRect.setRight(_contentRect.right() - _scrollBar->themeAwareWidth()); break; } @@ -2050,6 +2060,8 @@ _lines = qMax(1, _contentRect.height() / _fontHeight); _usedLines = qMin(_usedLines, _lines); + scrollBar()->setLines(_lines); + if(_centerContents) { QSize unusedPixels = _contentRect.size() - QSize(_columns * _fontWidth, _lines * _fontHeight); _contentRect.adjust(unusedPixels.width() / 2, unusedPixels.height() / 2, 0, 0); @@ -2059,10 +2071,11 @@ // calculate the needed size, this must be synced with calcGeometry() void TerminalDisplay::setSize(int columns, int lines) { + const int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->themeAwareWidth(); const int horizontalMargin = _margin * 2; const int verticalMargin = _margin * 2; - QSize newSize = QSize(horizontalMargin + (columns * _fontWidth) , + QSize newSize = QSize(horizontalMargin + scrollBarWidth + (columns * _fontWidth) , verticalMargin + (lines * _fontHeight)); if (newSize != size()) { @@ -2112,25 +2125,14 @@ /* */ /* ------------------------------------------------------------------------- */ -void TerminalDisplay::setScrollBarPosition(Enum::ScrollBarPositionEnum position) +void TerminalDisplay::scrollBarPositionChanged(TerminalScrollBar::Position position) { - if (_scrollbarLocation == position) { - return; - } - - if (position == Enum::ScrollBarHidden) { - _scrollBar->hide(); - } else if (_scrollBar->maximum() != 0) { - _scrollBar->show(); - } - - _scrollbarLocation = position; - + Q_UNUSED(position); propagateSize(); update(); } -void TerminalDisplay::scrollBarPositionChanged(int) +void TerminalDisplay::scrollBarValueChanged(int) { if (_screenWindow.isNull()) { return; @@ -2148,31 +2150,6 @@ updateImage(); } -void TerminalDisplay::setScroll(int cursor, int slines) -{ - // update _scrollBar if the range or value has changed, - // otherwise return - // - // setting the range or value of a _scrollBar will always trigger - // a repaint, so it should be avoided if it is not necessary - - if (_scrollBar->maximum() == 0 && _scrollBar->value() == cursor) { - // hide the scrollbar if it's not needed - _scrollBar->hide(); - return; - - } else if (_scrollbarLocation != Enum::ScrollBarHidden){ - _scrollBar->show(); - } - - disconnect(_scrollBar, &QScrollBar::valueChanged, this, &Konsole::TerminalDisplay::scrollBarPositionChanged); - _scrollBar->setRange(0, slines - _lines); - _scrollBar->setSingleStep(1); - _scrollBar->setPageStep(_lines); - _scrollBar->setValue(cursor); - connect(_scrollBar, &QScrollBar::valueChanged, this, &Konsole::TerminalDisplay::scrollBarPositionChanged); -} - void TerminalDisplay::setScrollFullPage(bool fullPage) { _scrollFullPage = fullPage; diff --git a/src/TerminalScrollBar.h b/src/TerminalScrollBar.h new file mode 100644 --- /dev/null +++ b/src/TerminalScrollBar.h @@ -0,0 +1,66 @@ +#ifndef TERMINALSCROLLBAR_H +#define TERMINALSCROLLBAR_H + +#include +#include "konsoleprivate_export.h" + +namespace Konsole +{ + +class KONSOLEPRIVATE_EXPORT TerminalScrollBar : public QScrollBar +{ + Q_OBJECT +public: + + /** + * This enum describes the positions where the terminal display's + * scroll bar may be placed. + */ + enum Position { + /** Show the scroll-bar on the left of the terminal display. */ + Left = 0, + /** Show the scroll-bar on the right of the terminal display. */ + Right = 1, + /** Do not show the scroll-bar. */ + Hidden = 2 + }; + + explicit TerminalScrollBar(QWidget *parent = 0); + + // The amount of lines that the scroll is displaying at maximum. + void setLines(int lines); + int lines() const; + void fixGeometry(); + + /** + * Sets the current position and range of the display's scroll bar. + * + * @param cursor The position of the scroll bar's thumb. + * @param slines The maximum value of the scroll bar. + */ + void setScroll(int cursor, int slines); + + /** + * Specifies whether the terminal display has a vertical scroll bar, and if so whether it + * is shown on the left or right side of the display. + */ + void setPosition(Position position); + Position position() const; + int themeAwareWidth() const; +protected: + /* trackign the style change event */ + void changeEvent(QEvent *event) override; + +Q_SIGNALS: + void positionChanged(Position position); + void linesChanged(int lines); + +private: + Position _position; + int _lines; + bool _canFloat; +}; + +} + +#endif diff --git a/src/TerminalScrollBar.cpp b/src/TerminalScrollBar.cpp new file mode 100644 --- /dev/null +++ b/src/TerminalScrollBar.cpp @@ -0,0 +1,92 @@ +#include "TerminalScrollBar.h" +#include +#include +#include + +namespace Konsole { + +TerminalScrollBar::TerminalScrollBar(QWidget *parent) + : QScrollBar(parent) + , _position(Right) + , _canFloat(false) +{ + _canFloat = qApp->style()->objectName() == QLatin1Literal("breeze"); + setCursor(Qt::ArrowCursor); +} + +void TerminalScrollBar::setLines(int lines) +{ + if (_lines == lines) { + return; + } + _lines = lines; + emit linesChanged(lines); +} + +void TerminalScrollBar::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::StyleChange) { + _canFloat = qApp->style()->objectName() == QLatin1Literal("breeze"); + parentWidget()->update(); + } +} + +void TerminalScrollBar::setPosition(Position position) +{ + if (_position == position) { + return; + } + + setVisible(position != Position::Hidden || maximum() != 0); + _position = position; + emit positionChanged(position); +} + +void TerminalScrollBar::fixGeometry() +{ + auto parentRect = parentWidget()->contentsRect(); + resize(sizeHint().width(), parentRect.height()); + + switch (_position) { + case Hidden : break; + case Left : + move(parentRect.topLeft()); + break; + case Right: + move(parentRect.topRight() - QPoint(width() - 1, 0)); + break; + } +} + +void TerminalScrollBar::setScroll(int cursor, int slines) +{ + if (maximum() == 0 && value() == cursor) { + // hide the scrollbar if it's not needed + hide(); + return; + } else if (_position != Position::Hidden) { + show(); + } + + setRange(0, slines - _lines); + setSingleStep(1); + setPageStep(_lines); + setValue(cursor); +} + +int TerminalScrollBar::themeAwareWidth() const +{ + return _canFloat ? 0 : width(); +} + +TerminalScrollBar::Position TerminalScrollBar::position() const +{ + return _position; +} + +int TerminalScrollBar::lines() const +{ + return _lines; +} + +} diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -856,7 +856,7 @@ view->setVTFont(profile->font()); // set scroll-bar position - view->setScrollBarPosition(Enum::ScrollBarPositionEnum(profile->property(Profile::ScrollBarPosition))); + view->scrollBar()->setPosition(TerminalScrollBar::Position(profile->property(Profile::ScrollBarPosition))); view->setScrollFullPage(profile->property(Profile::ScrollFullPage)); // show hint about terminal size after resizing diff --git a/src/autotests/TerminalTest.cpp b/src/autotests/TerminalTest.cpp --- a/src/autotests/TerminalTest.cpp +++ b/src/autotests/TerminalTest.cpp @@ -26,20 +26,21 @@ #include "../TerminalDisplay.h" #include "../CharacterColor.h" #include "../ColorScheme.h" +#include "../TerminalScrollBar.h" using namespace Konsole; void TerminalTest::testScrollBarPositions() { auto display = new TerminalDisplay(nullptr); // ScrollBar Positions - display->setScrollBarPosition(Enum::ScrollBarLeft); - QCOMPARE(display->scrollBarPosition(), Enum::ScrollBarLeft); - display->setScrollBarPosition(Enum::ScrollBarRight); - QCOMPARE(display->scrollBarPosition(), Enum::ScrollBarRight); - display->setScrollBarPosition(Enum::ScrollBarHidden); - QCOMPARE(display->scrollBarPosition(), Enum::ScrollBarHidden); + display->scrollBar()->setPosition(TerminalScrollBar::Position::Left); + QCOMPARE(display->scrollBar()->position(), TerminalScrollBar::Position::Left); + display->scrollBar()->setPosition(TerminalScrollBar::Position::Right); + QCOMPARE(display->scrollBar()->position(), TerminalScrollBar::Position::Right); + display->scrollBar()->setPosition(TerminalScrollBar::Position::Hidden); + QCOMPARE(display->scrollBar()->position(), TerminalScrollBar::Position::Hidden); delete display; }