diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,6 +89,7 @@ ExtendedCharTable.cpp TerminalDisplay.cpp TerminalDisplayAccessible.cpp + TerminalHeaderBar.cpp LineBlockCharacters.cpp ViewContainer.cpp ViewManager.cpp diff --git a/src/IncrementalSearchBar.cpp b/src/IncrementalSearchBar.cpp --- a/src/IncrementalSearchBar.cpp +++ b/src/IncrementalSearchBar.cpp @@ -239,10 +239,9 @@ void IncrementalSearchBar::correctPosition(const QSize &parentSize) { - const auto width = geometry().width(); - const auto height = geometry().height(); - const auto x = parentSize.width() - width; - setGeometry(x, 0, width, height); + const auto x = parentSize.width() - width(); + const auto y = parentSize.height(); + setGeometry(x, 0 + y, width(), height()); } void IncrementalSearchBar::keyPressEvent(QKeyEvent *event) diff --git a/src/TerminalDisplay.h b/src/TerminalDisplay.h --- a/src/TerminalDisplay.h +++ b/src/TerminalDisplay.h @@ -34,6 +34,7 @@ #include "Enumeration.h" #include "ScrollState.h" #include "Profile.h" +#include "TerminalHeaderBar.h" class QDrag; class QDragEnterEvent; @@ -293,6 +294,10 @@ return font(); } + TerminalHeaderBar *headerBar() const + { + return _headerBar; + } /** * Sets the font used to draw the display. Has no effect if @p font * is larger than the size of the display itself. @@ -845,7 +850,7 @@ ScrollState _scrollWheelState; IncrementalSearchBar *_searchBar; - + TerminalHeaderBar *_headerBar; QRect _searchResultRect; friend class TerminalDisplayAccessible; }; diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -483,6 +483,7 @@ , _dimWhenInactive(false) , _scrollWheelState(ScrollState()) , _searchBar(new IncrementalSearchBar(this)) + , _headerBar(new TerminalHeaderBar(this)) , _searchResultRect(QRect()) { // terminal applications are not designed with Right-To-Left in mind, @@ -533,21 +534,13 @@ setAttribute(Qt::WA_OpaquePaintEvent); // Add the stretch item once, the KMessageWidgets are inserted at index 0. + _verticalLayout->addWidget(_headerBar); _verticalLayout->addStretch(); _verticalLayout->setSpacing(0); - + _verticalLayout->setMargin(0); setLayout(_verticalLayout); - // Take the scrollbar into account and add a margin to the layout. Without the timer the scrollbar width - // is garbage. - QTimer::singleShot(0, this, [this]() { - const int scrollBarWidth = _scrollBar->isVisible() ? geometry().intersected(_scrollBar->geometry()).width() : 0; - _verticalLayout->setContentsMargins(0, 0, scrollBarWidth, 0); - }); - new AutoScrollHandler(this); - - #ifndef QT_NO_ACCESSIBILITY QAccessible::installFactory(Konsole::accessibleInterfaceFactory); #endif @@ -1766,7 +1759,7 @@ Q_ASSERT(!_textBlinking); _showUrlHint = false; - + _headerBar->terminalFocusOut(); emit focusLost(); } @@ -1781,7 +1774,7 @@ if (_allowBlinkingText && _hasTextBlinker) { _blinkTextTimer->start(); } - + _headerBar->terminalFocusIn(); emit focusGained(); } @@ -1793,6 +1786,7 @@ // TODO: Optimize to only repaint the areas of the widget where there is // blinking text rather than repainting the whole widget. + _headerBar->terminalFocusOut(); update(); } @@ -1827,7 +1821,9 @@ void TerminalDisplay::resizeEvent(QResizeEvent *event) { const auto width = event->size().width() - _scrollBar->geometry().width(); - _searchBar->correctPosition(QSize(width, event->size().height())); + const auto headerHeight = _headerBar->isVisible() ? _headerBar->height() : 0; + + _searchBar->correctPosition(QSize(width, headerHeight)); if (contentsRect().isValid()) { updateImageSize(); } @@ -1901,22 +1897,32 @@ void TerminalDisplay::calcGeometry() { - _scrollBar->resize(_scrollBar->sizeHint().width(), contentsRect().height()); + const auto headerHeight = _headerBar->isVisible() ? _headerBar->height() : 0; + + _scrollBar->resize( + _scrollBar->sizeHint().width(), // width + contentsRect().height() - headerHeight // height + ); + _contentRect = contentsRect().adjusted(_margin, _margin, -_margin, -_margin); switch (_scrollbarLocation) { case Enum::ScrollBarHidden : break; case Enum::ScrollBarLeft : _contentRect.setLeft(_contentRect.left() + _scrollBar->width()); - _scrollBar->move(contentsRect().topLeft()); + _scrollBar->move(contentsRect().left(), + contentsRect().top() + headerHeight); break; case Enum::ScrollBarRight: _contentRect.setRight(_contentRect.right() - _scrollBar->width()); - _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width() - 1, 0)); + _scrollBar->move(contentsRect().right() - _scrollBar->width() - 1, + contentsRect().top() + headerHeight); break; } + _contentRect.setTop(_contentRect.top() + headerHeight); + // ensure that display is always at least one column wide _columns = qMax(1, _contentRect.width() / _fontWidth); _usedColumns = qMin(_usedColumns, _columns); @@ -3388,7 +3394,7 @@ widget->setFocusProxy(this); widget->setCursor(Qt::ArrowCursor); - _verticalLayout->insertWidget(0, widget); + _verticalLayout->insertWidget(1, widget); return widget; } @@ -3773,6 +3779,7 @@ void TerminalDisplay::setSessionController(SessionController* controller) { _sessionController = controller; + _headerBar->finishHeaderSetup(controller); } SessionController* TerminalDisplay::sessionController() diff --git a/src/TerminalHeaderBar.h b/src/TerminalHeaderBar.h new file mode 100644 --- /dev/null +++ b/src/TerminalHeaderBar.h @@ -0,0 +1,39 @@ +#ifndef TERMINAL_HEADER_BAR_H +#define TERMINAL_HEADER_BAR_H + +#include + +class QLabel; +class QToolButton; +class QBoxLayout; +namespace Konsole { + class TerminalDisplay; + class ViewProperties; + +class TerminalHeaderBar : public QWidget { + Q_OBJECT +public: + // TODO: Verify if the terminalDisplay is needed, or some other thing like SessionController. + TerminalHeaderBar(QWidget *parent = nullptr); + void finishHeaderSetup(ViewProperties *properties); + + void terminalFocusIn(); + void terminalFocusOut(); + +Q_SIGNALS: + void requestToggleExpansion(); + +private: + void addSpacer(); + QBoxLayout *m_boxLayout; + TerminalDisplay *m_terminalDisplay; + QLabel *m_terminalTitle; + QLabel *m_terminalIcon; + QLabel *m_terminalActivity; // Bell icon. + QToolButton *m_closeBtn; + QToolButton *m_toggleExpandedMode; +}; + +} // namespace Konsole + +#endif diff --git a/src/TerminalHeaderBar.cpp b/src/TerminalHeaderBar.cpp new file mode 100644 --- /dev/null +++ b/src/TerminalHeaderBar.cpp @@ -0,0 +1,91 @@ +#include "TerminalHeaderBar.h" + +#include "TerminalDisplay.h" +#include "SessionController.h" +#include "ViewProperties.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Konsole { + +TerminalHeaderBar::TerminalHeaderBar(QWidget *parent) + : QWidget(parent) +{ + m_closeBtn = new QToolButton(this); + m_closeBtn->setIcon(QIcon::fromTheme(QStringLiteral("tab-close"))); + m_closeBtn->setToolTip(i18nc("@action:itooltip", "Close terminal")); + m_closeBtn->setText(i18nc("@action:itooltip", "Close terminal")); + m_closeBtn->setObjectName(QStringLiteral("close-terminal-button")); + m_closeBtn->setAutoRaise(true); + + m_toggleExpandedMode = new QToolButton(this); + m_toggleExpandedMode->setIcon(QIcon::fromTheme(QStringLiteral("format-font-size-more"))); // fake 'expand' icon. VDG input? + m_toggleExpandedMode->setAutoRaise(true); + + m_terminalTitle = new QLabel(this); + m_terminalIcon = new QLabel(this); + m_terminalActivity = new QLabel(this); + + m_boxLayout = new QBoxLayout(QBoxLayout::LeftToRight); + m_boxLayout->setSpacing(0); + m_boxLayout->setMargin(0); + + // Layout Setup + m_boxLayout->addStretch(); + m_boxLayout->addWidget(m_terminalIcon); + m_boxLayout->addWidget(m_terminalTitle); + m_boxLayout->addWidget(m_terminalActivity); + m_boxLayout->addStretch(); + m_boxLayout->addWidget(m_toggleExpandedMode); + m_boxLayout->addWidget(m_closeBtn); + setLayout(m_boxLayout); + + setAutoFillBackground(true); +} + +// Hack untill I can detangle the creation of the TerminalViews +void TerminalHeaderBar::finishHeaderSetup(ViewProperties *properties) +{ + //TODO: Fix ViewProperties signals. + connect(properties, &Konsole::ViewProperties::titleChanged, this, + [this, properties]{ + m_terminalTitle->setText(properties->title()); + }); + + connect(m_closeBtn, &QToolButton::clicked, this, [properties]{ + auto controller = qobject_cast(properties); + controller->closeSession(); + }); + + connect(properties, &Konsole::ViewProperties::iconChanged, this, [this, properties] { + m_terminalIcon->setPixmap(properties->icon().pixmap(QSize(22,22))); + }); + + connect(properties, &Konsole::ViewProperties::activity, this, [this]{ + m_terminalActivity->setPixmap(QPixmap()); + }); + + connect(m_toggleExpandedMode, &QToolButton::clicked, + this, &TerminalHeaderBar::requestToggleExpansion); +} + +void TerminalHeaderBar::terminalFocusIn() +{ + m_terminalTitle->setEnabled(true); +} + +void TerminalHeaderBar::terminalFocusOut() +{ + // TODO: Don't focusOut if searchBar is enabled. + m_terminalTitle->setEnabled(false); +} + +} diff --git a/src/ViewContainer.h b/src/ViewContainer.h --- a/src/ViewContainer.h +++ b/src/ViewContainer.h @@ -137,8 +137,7 @@ void setNavigationVisibility(ViewManager::NavigationVisibility navigationVisibility); void moveTabToWindow(int index, QWidget *window); - void maximizeCurrentTerminal(); - void restoreOtherTerminals(); + void toggleMaximizeCurrentTerminal(); /* return the widget(int index) casted to TerminalDisplay* * * The only thing that this class holds are TerminalDisplays, so diff --git a/src/ViewContainer.cpp b/src/ViewContainer.cpp --- a/src/ViewContainer.cpp +++ b/src/ViewContainer.cpp @@ -556,14 +556,9 @@ } } -void TabbedViewContainer::maximizeCurrentTerminal() +void TabbedViewContainer::toggleMaximizeCurrentTerminal() { - activeViewSplitter()->maximizeCurrentTerminal(); -} - -void TabbedViewContainer::restoreOtherTerminals() -{ - activeViewSplitter()->restoreOtherTerminals(); + activeViewSplitter()->toggleMaximizeCurrentTerminal(); } void TabbedViewContainer::moveTabLeft() diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -229,14 +229,7 @@ action = new QAction(i18nc("@action Shortcut entry", "Maximize current Terminal"), this); collection->addAction(QStringLiteral("maximize-current-terminal"), action); collection->setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_E); - connect(action, &QAction::triggered, _viewContainer, &TabbedViewContainer::maximizeCurrentTerminal); - _multiSplitterOnlyActions << action; - _viewContainer->addAction(action); - - action = new QAction(i18nc("@action Shortcut entry", "Restore other terminals"), this); - collection->addAction(QStringLiteral("restore-other-terminals"), action); - collection->setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_Minus); - connect(action, &QAction::triggered, _viewContainer, &TabbedViewContainer::restoreOtherTerminals); + connect(action, &QAction::triggered, _viewContainer, &TabbedViewContainer::toggleMaximizeCurrentTerminal); _multiSplitterOnlyActions << action; _viewContainer->addAction(action); @@ -478,7 +471,7 @@ auto *toplevelSplitter = splitter->getToplevelSplitter(); - toplevelSplitter->restoreOtherTerminals(); + toplevelSplitter->handleMinimizeMaximize(false); view->deleteLater(); @@ -776,7 +769,8 @@ { auto display = new TerminalDisplay(nullptr); display->setRandomSeed(session->sessionId() * 31); - + connect(display->headerBar(), &TerminalHeaderBar::requestToggleExpansion, + _viewContainer, &TabbedViewContainer::toggleMaximizeCurrentTerminal); return display; } diff --git a/src/ViewSplitter.h b/src/ViewSplitter.h --- a/src/ViewSplitter.h +++ b/src/ViewSplitter.h @@ -91,11 +91,7 @@ /** Makes the current TerminalDisplay expanded to 100% of the view */ - void maximizeCurrentTerminal(); - - /** Restore the sizes of the terminals. - */ - void restoreOtherTerminals(); + void toggleMaximizeCurrentTerminal(); void handleMinimizeMaximize(bool maximize); @@ -128,6 +124,7 @@ void childEvent(QChildEvent* event) override; private: void updateSizes(); + bool m_terminalMaximized = false; }; } #endif //VIEWSPLITTER_H diff --git a/src/ViewSplitter.cpp b/src/ViewSplitter.cpp --- a/src/ViewSplitter.cpp +++ b/src/ViewSplitter.cpp @@ -124,6 +124,15 @@ deleteLater(); } } + + auto terminals = getToplevelSplitter()->findChildren(); + if (terminals.size() == 1) { + terminals.at(0)->headerBar()->setVisible(false); + } else { + for(auto terminal : terminals) { + terminal->headerBar()->setVisible(true); + } + } } void ViewSplitter::handleFocusDirection(Qt::Orientation orientation, int direction) @@ -150,13 +159,17 @@ if (TerminalDisplay* terminal = qobject_cast(child)) { terminal->setFocus(Qt::OtherFocusReason); - } else if (qobject_cast(child)) { - auto scrollbarTerminal = qobject_cast(child->parent()); - scrollbarTerminal->setFocus(Qt::OtherFocusReason); } else if (qobject_cast(child)) { auto targetSplitter = qobject_cast(child->parent()); auto splitterTerminal = qobject_cast(targetSplitter->widget(0)); splitterTerminal->setFocus(Qt::OtherFocusReason); + } else if (qobject_cast(child)) { + TerminalDisplay *terminalParent = nullptr; + while(!terminalParent) { + terminalParent = qobject_cast(child->parentWidget()); + child = child->parentWidget(); + } + terminalParent->setFocus(Qt::OtherFocusReason); } } @@ -186,14 +199,10 @@ return focusedWidget ? focusedWidget : findChild(); } -void ViewSplitter::maximizeCurrentTerminal() -{ - handleMinimizeMaximize(true); -} - -void ViewSplitter::restoreOtherTerminals() +void ViewSplitter::toggleMaximizeCurrentTerminal() { - handleMinimizeMaximize(false); + m_terminalMaximized = !m_terminalMaximized; + handleMinimizeMaximize(m_terminalMaximized); } void ViewSplitter::handleMinimizeMaximize(bool maximize)