diff --git a/src/SessionController.cpp b/src/SessionController.cpp --- a/src/SessionController.cpp +++ b/src/SessionController.cpp @@ -109,7 +109,7 @@ , _findPreviousAction(nullptr) , _interactionTimer(nullptr) , _searchStartLine(0) - , _prevSearchResultLine(0) + , _prevSearchResultLine(-1) , _codecAction(nullptr) , _switchProfileMenu(nullptr) , _webSearchMenu(nullptr) @@ -1161,7 +1161,6 @@ void SessionController::setSearchStartTo(int line) { _searchStartLine = line; - _prevSearchResultLine = line; } void SessionController::listenForScreenWindowUpdates() @@ -1179,6 +1178,7 @@ void SessionController::updateSearchFilter() { + _prevSearchResultLine = -1; if ((_searchFilter != nullptr) && (!_searchBar.isNull())) { _view->processFilters(); } @@ -1205,7 +1205,7 @@ return; } - if (showSearchBar && !_searchBar->isVisible()) { + if (showSearchBar && !_searchBar->isVisible() && _searchBar->searchText().isEmpty()) { setSearchStartToWindowCurrentLine(); } @@ -1214,6 +1214,9 @@ connect(_searchBar.data(), &Konsole::IncrementalSearchBar::searchChanged, this, &Konsole::SessionController::searchTextChanged); connect(_searchBar.data(), &Konsole::IncrementalSearchBar::searchReturnPressed, this, &Konsole::SessionController::findPreviousInHistory); connect(_searchBar.data(), &Konsole::IncrementalSearchBar::searchShiftPlusReturnPressed, this, &Konsole::SessionController::findNextInHistory); + if ((!_view.isNull()) && (_view->screenWindow() != nullptr)) { + _view->screenWindow()->setCurrentResultLine(_prevSearchResultLine); + } } else { disconnect(_searchBar.data(), &Konsole::IncrementalSearchBar::searchChanged, this, &Konsole::SessionController::searchTextChanged); @@ -1297,13 +1300,12 @@ return; } - _searchText = text; - - if (text.isEmpty()) { - _view->screenWindow()->clearSelection(); - _view->screenWindow()->scrollTo(_searchStartLine); + if (_searchText.isEmpty()) { + setSearchStartToWindowCurrentLine(); } + _searchText = text; + // update search. this is called even when the text is // empty to clear the view's filters beginSearch(text , reverseSearchChecked() ? Enum::BackwardsSearch : Enum::ForwardsSearch); @@ -1333,8 +1335,8 @@ } } + if (!regExp.pattern().isEmpty()) { - _view->screenWindow()->setCurrentResultLine(-1); auto task = new SearchHistoryTask(this); connect(task, &Konsole::SearchHistoryTask::completed, this, &Konsole::SessionController::searchCompleted); @@ -1346,6 +1348,7 @@ task->addScreenWindow(_session , _view->screenWindow()); task->execute(); } else if (text.isEmpty()) { + _view->screenWindow()->setCurrentResultLine(-1); searchCompleted(false); } diff --git a/src/TerminalDisplay.h b/src/TerminalDisplay.h --- a/src/TerminalDisplay.h +++ b/src/TerminalDisplay.h @@ -828,8 +828,6 @@ // drawTextFragment() or drawPrinterFriendlyTextFragment() // to draw the fragments void drawContents(QPainter &painter, const QRect &rect); - // draw a transparent rectangle over the line of the current match - void drawCurrentResultRect(QPainter &painter); // 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, @@ -921,6 +919,9 @@ int loc(int x, int y) const; + // Calculate the rectangle where search results are indicated + QRect calculateSearchResultRect() const; + // the window onto the terminal screen which this display // is currently showing. QPointer _screenWindow; diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -1384,6 +1384,16 @@ _filterUpdateRequired = false; } +inline QRect TerminalDisplay::calculateSearchResultRect() const +{ + const int searchLine = _screenWindow->currentResultLine() - _screenWindow->currentLine(); + QRect resultRect = imageToWidget(QRect(0, searchLine, _columns, 1)) + .adjusted(0, -_fontHeight/3, 0, _fontHeight/3); + resultRect.setLeft(0); + resultRect.setRight(contentsRect().width()); + return resultRect; +} + void TerminalDisplay::updateImage() { if (_screenWindow.isNull()) { @@ -1557,8 +1567,7 @@ // De-highlight previous result region dirtyRegion |= _searchResultRect; // Highlight new result region - dirtyRegion |= QRect(0, _contentRect.top() + (_screenWindow->currentResultLine() - _screenWindow->currentLine()) * _fontHeight, - _columns * _fontWidth, _fontHeight); + dirtyRegion |= calculateSearchResultRect(); } _screenWindow->resetScrollCount(); @@ -1624,11 +1633,39 @@ foreach(const QRect & rect, dirtyImageRegion.rects()) { drawContents(paint, rect); } - drawCurrentResultRect(paint); + drawInputMethodPreeditString(paint, preeditRect()); + + // Shade out above and below current search result line + bool drawSearchResults = (_screenWindow->currentResultLine() != -1); + if (drawSearchResults) { + _searchResultRect = calculateSearchResultRect(); + + QColor shadeColor(0, 0, 0, 192); + + // Shade area above result + paint.fillRect(0, 0, contentsRect().width(), _searchResultRect.top(), shadeColor); + // Shade area below results + paint.fillRect(0, _searchResultRect.bottom() + 1, contentsRect().width(), contentsRect().height(), shadeColor); + // Lightly shade line with results + shadeColor.setAlpha(120); + paint.fillRect(_searchResultRect, shadeColor); + } else { + _searchResultRect = QRect(); + } + paintFilters(paint); - const bool drawDimmed = _dimWhenInactive && !hasFocus(); + // We need to draw these indicators after the highlighted search results + // from paintFilters because the lines potentially overlap some results + if (drawSearchResults) { + paint.setPen(QPen(QColor(255, 255, 255, 64), QFontMetricsF(paint.fontMetrics()).lineWidth())); + const qreal lineOffset = paint.pen().widthF()/2.; + paint.drawLine(QLineF(_searchResultRect.topLeft(), _searchResultRect.topRight()).translated(0, lineOffset)); + paint.drawLine(QLineF(_searchResultRect.bottomLeft(), _searchResultRect.bottomRight()).translated(0, 1 - lineOffset)); + } + + const bool drawDimmed = _dimWhenInactive && !hasFocus() && !drawSearchResults; const QColor dimColor(0, 0, 0, 128); foreach(const QRect & rect, (pe->region() & contentsRect()).rects()) { if (drawDimmed) { @@ -1788,11 +1825,8 @@ // moving the mouse outside a link could still leave it underlined // because the check below for the position of the cursor // finds it on the border of the target area - QRect r; - r.setCoords(startColumn * _fontWidth + _contentRect.left(), - line * _fontHeight + _contentRect.top(), - endColumn * _fontWidth + _contentRect.left() - 1, - (line + 1)*_fontHeight + _contentRect.top() - 1); + QRect r(startColumn, line, endColumn - startColumn, 1); + r = imageToWidget(r); // Underline link hotspots if (spot->type() == Filter::HotSpot::Link) { QFontMetrics metrics(font()); @@ -1807,13 +1841,12 @@ r.right() , underlinePos); } - // Marker hotspots simply have a transparent rectangular shape - // drawn on top of them + // Search results get repainted to make them stand out } else if (spot->type() == Filter::HotSpot::Marker) { - //TODO - Do not use a hardcoded color for this - const bool isCurrentResultLine = (_screenWindow->currentResultLine() == (spot->startLine() + _screenWindow->currentLine())); - QColor color = isCurrentResultLine ? QColor(255, 255, 0, 120) : QColor(255, 0, 0, 120); - painter.fillRect(r, color); + painter.setBrush(getBackgroundColor()); + painter.setPen(Qt::transparent); + painter.drawRoundedRect(r.x(), r.y(), r.width(), r.height(), 3, 3); + drawContents(painter, widgetToImage(r)); } } } @@ -2009,17 +2042,6 @@ } } -void TerminalDisplay::drawCurrentResultRect(QPainter& painter) -{ - if(_screenWindow->currentResultLine() == -1) { - return; - } - - _searchResultRect.setRect(0, _contentRect.top() + (_screenWindow->currentResultLine() - _screenWindow->currentLine()) * _fontHeight, - _columns * _fontWidth, _fontHeight); - painter.fillRect(_searchResultRect, QColor(0, 0, 255, 80)); -} - QRect TerminalDisplay::imageToWidget(const QRect& imageArea) const { QRect result;