diff options
author | mae <qt-info@nokia.com> | 2009-12-01 14:47:10 +0100 |
---|---|---|
committer | mae <qt-info@nokia.com> | 2009-12-01 14:47:40 +0100 |
commit | e2a899e354ce579597feed2d79d9df9cdc3daf57 (patch) | |
tree | a2ba8f4082131fbc17dd034d44f30ec56005b094 /src/plugins | |
parent | c4737c1fdf5ab3d950adaa5002367797c993ed37 (diff) | |
download | qt-creator-e2a899e354ce579597feed2d79d9df9cdc3daf57.tar.gz |
improved search result selection with over and underlay
done with thorbjorn
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/texteditor/basetexteditor.cpp | 52 | ||||
-rw-r--r-- | src/plugins/texteditor/basetexteditor_p.h | 6 | ||||
-rw-r--r-- | src/plugins/texteditor/displaysettings.cpp | 4 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditoroverlay.cpp | 155 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditoroverlay.h | 18 |
5 files changed, 195 insertions, 40 deletions
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 2a20ed857c..3a8c5e9437 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -177,6 +177,7 @@ BaseTextEditor::BaseTextEditor(QWidget *parent) d->m_overlay = new TextEditorOverlay(this); d->m_searchResultOverlay = new TextEditorOverlay(this); + d->m_searchResultUnderlay = new TextEditorOverlay(this); d->setupDocumentSignals(d->m_document); d->setupDocumentSignals(d->m_document); @@ -230,6 +231,10 @@ BaseTextEditor::BaseTextEditor(QWidget *parent) slotCursorPositionChanged(); setFrameStyle(QFrame::NoFrame); + d->m_delayedUpdateTimer = new QTimer(this); + d->m_delayedUpdateTimer->setSingleShot(true); + connect(d->m_delayedUpdateTimer, SIGNAL(timeout()), viewport(), SLOT(update())); + connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)), this, SLOT(currentEditorChanged(Core::IEditor*))); } @@ -1822,7 +1827,9 @@ QTextBlock BaseTextEditor::collapsedBlockAt(const QPoint &pos, QRect *box) const return QTextBlock(); } -void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block) +void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block, + TextEditorOverlay *overlay, + QVector<QTextLayout::FormatRange> *selections ) { if (m_searchExpr.isEmpty()) return; @@ -1843,9 +1850,19 @@ void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block) if (m_findScope.isNull() || (block.position() + idx >= m_findScope.selectionStart() && block.position() + idx + l <= m_findScope.selectionEnd())) { - m_searchResultOverlay->addOverlaySelection(block.position() + idx, - block.position() + idx + l, - m_searchResultFormat.background().color()); + if (selections) { + QTextLayout::FormatRange selection; + selection.start = idx; + selection.length = l; + selection.format = m_searchResultFormat; + selections->append(selection); + } + + overlay->addOverlaySelection(block.position() + idx, + block.position() + idx + l, + m_searchResultFormat.background().color().darker(120), + QColor()); + } } } @@ -2075,6 +2092,8 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) QPen cursor_pen; d->m_searchResultOverlay->clear(); + d->m_searchResultUnderlay->clear(); + while (block.isValid()) { QRectF r = blockBoundingRect(block).translated(offset); @@ -2169,7 +2188,9 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) selections.append(o); } } - d->highlightSearchResults(block); + + d->highlightSearchResults(block, d->m_searchResultUnderlay, &selections); + d->m_searchResultOverlay->m_selections.append(d->m_searchResultUnderlay->m_selections); selections += prioritySelections; bool drawCursor = ((editable || true) // we want the cursor in read-only mode @@ -2191,6 +2212,12 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) } } + if (d->m_searchResultUnderlay && !d->m_searchExpr.isEmpty()) { + d->m_searchResultUnderlay->fill(&painter, + d->m_searchResultFormat.background().color(), + e->rect()); + d->m_searchResultUnderlay->clear(); + } layout->draw(&painter, offset, selections, er); @@ -2208,6 +2235,9 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) cursor_pen = painter.pen(); } + } else if (r.bottom() >= er.top()-10 && r.top() <= er.bottom()+10) { + // search result overlays can cover adjacent blocks + d->highlightSearchResults(block, d->m_searchResultOverlay); } offset.ry() += r.height(); @@ -2421,11 +2451,13 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) painter.drawLine(QPointF(lineX, 0), QPointF(lineX, viewport()->height())); } - if (d->m_searchResultOverlay) - d->m_searchResultOverlay->paint(&painter, e->rect()); - if (d->m_overlay && d->m_overlay->isVisible()) d->m_overlay->paint(&painter, e->rect()); + + if (d->m_searchResultOverlay && !d->m_searchExpr.isEmpty()) + d->m_searchResultOverlay->paint(&painter, e->rect()); +// d->m_searchResultOverlay->paintInverted(&painter, e->rect(), d->m_searchResultFormat.background().color()); + // draw the cursor last, on top of everything @@ -3934,9 +3966,9 @@ void BaseTextEditor::highlightSearchResults(const QString &txt, Find::IFindSuppo d->m_searchExpr.setCaseSensitivity((findFlags & Find::IFindSupport::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); d->m_findFlags = findFlags; - viewport()->update(); -} + d->m_delayedUpdateTimer->start(10); +} void BaseTextEditor::setFindScope(const QTextCursor &scope) { diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index f7c7ed3a6b..39bb0dfedb 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -189,6 +189,7 @@ public: TextEditorOverlay *m_overlay; TextEditorOverlay *m_searchResultOverlay; + TextEditorOverlay *m_searchResultUnderlay; QBasicTimer collapsedBlockTimer; int visibleCollapsedBlockNumber; @@ -222,7 +223,10 @@ public: QTextCharFormat m_searchScopeFormat; QTextCharFormat m_currentLineFormat; QTextCharFormat m_currentLineNumberFormat; - void highlightSearchResults(const QTextBlock &block); + void highlightSearchResults(const QTextBlock &block, + TextEditorOverlay *overlay, + QVector<QTextLayout::FormatRange> *selections = 0); + QTimer *m_delayedUpdateTimer; BaseTextEditorEditable *m_editable; diff --git a/src/plugins/texteditor/displaysettings.cpp b/src/plugins/texteditor/displaysettings.cpp index 0906a9016f..aca646ccf9 100644 --- a/src/plugins/texteditor/displaysettings.cpp +++ b/src/plugins/texteditor/displaysettings.cpp @@ -40,7 +40,7 @@ static const char * const showWrapColumnKey = "ShowWrapColumn"; static const char * const wrapColumnKey = "WrapColumn"; static const char * const visualizeWhitespaceKey = "VisualizeWhitespace"; static const char * const displayFoldingMarkersKey = "DisplayFoldingMarkers"; -static const char * const highlightCurrentLineKey = "HighlightCurrentLineKey"; +static const char * const highlightCurrentLineKey = "HighlightCurrentLine2Key"; static const char * const highlightBlocksKey = "HighlightBlocksKey"; static const char * const animateMatchingParenthesesKey= "AnimateMatchingParenthesesKey"; static const char * const mouseNavigationKey = "MouseNavigation"; @@ -56,7 +56,7 @@ DisplaySettings::DisplaySettings() : m_wrapColumn(80), m_visualizeWhitespace(false), m_displayFoldingMarkers(true), - m_highlightCurrentLine(true), + m_highlightCurrentLine(false), m_highlightBlocks(false), m_animateMatchingParentheses(true), m_mouseNavigation(true), diff --git a/src/plugins/texteditor/texteditoroverlay.cpp b/src/plugins/texteditor/texteditoroverlay.cpp index 9b76385efc..1e3065ca3e 100644 --- a/src/plugins/texteditor/texteditoroverlay.cpp +++ b/src/plugins/texteditor/texteditoroverlay.cpp @@ -36,7 +36,8 @@ void TextEditorOverlay::clear() update(); } -void TextEditorOverlay::addOverlaySelection(int begin, int end, const QColor &color, bool lockSize) +void TextEditorOverlay::addOverlaySelection(int begin, int end, + const QColor &fg, const QColor &bg, bool lockSize) { if (end < begin) return; @@ -44,7 +45,8 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end, const QColor &co QTextDocument *document = m_editor->document(); OverlaySelection selection; - selection.m_color = color; + selection.m_fg = fg; + selection.m_bg = bg; selection.m_cursor_begin = QTextCursor(document); selection.m_cursor_begin.setPosition(begin); @@ -60,9 +62,10 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end, const QColor &co } -void TextEditorOverlay::addOverlaySelection(const QTextCursor &cursor, const QColor &color, bool lockSize) +void TextEditorOverlay::addOverlaySelection(const QTextCursor &cursor, + const QColor &fg, const QColor &bg, bool lockSize) { - addOverlaySelection(cursor.selectionStart(), cursor.selectionEnd(), color, lockSize); + addOverlaySelection(cursor.selectionStart(), cursor.selectionEnd(), fg, bg, lockSize); } QRect TextEditorOverlay::rect() const @@ -70,20 +73,21 @@ QRect TextEditorOverlay::rect() const return m_viewport->rect(); } -void TextEditorOverlay::paintSelection(QPainter *painter, const QTextCursor &begin, const QTextCursor &end, const QColor &color) +QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, const QTextCursor &end, + const QRect &clip) { if (begin.isNull() || end.isNull() || begin.position() > end.position()) - return; + return QPainterPath(); QPointF offset = m_editor->contentOffset(); QRect viewportRect = rect(); QTextDocument *document = m_editor->document(); - if (m_editor->blockBoundingGeometry(begin.block()).translated(offset).top() > viewportRect.bottom() + 10 - || m_editor->blockBoundingGeometry(end.block()).translated(offset).bottom() < viewportRect.top() - 10 + if (m_editor->blockBoundingGeometry(begin.block()).translated(offset).top() > clip.bottom() + 10 + || m_editor->blockBoundingGeometry(end.block()).translated(offset).bottom() < clip.top() - 10 ) - return; // nothing of the selection is visible + return QPainterPath(); // nothing of the selection is visible QTextBlock block = begin.block(); @@ -154,7 +158,7 @@ void TextEditorOverlay::paintSelection(QPainter *painter, const QTextCursor &beg if (selection.isEmpty()) - return; + return QPainterPath(); QVector<QPointF> points; @@ -224,34 +228,60 @@ void TextEditorOverlay::paintSelection(QPainter *painter, const QTextCursor &beg previous = points.at(i); } path.closeSubpath(); + path.translate(offset); + return path; +} + +void TextEditorOverlay::paintSelection(QPainter *painter, const QTextCursor &begin, const QTextCursor &end, + const QColor &fg, const QColor &bg) +{ + if (begin.isNull() || end.isNull() || begin.position() > end.position()) + return; + + QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect()); painter->save(); - QColor penColor = color; + QColor penColor = fg; penColor.setAlpha(220); QPen pen(penColor, m_borderWidth); painter->translate(-.5, -.5); - path.translate(offset); QRectF pathRect = path.controlPointRect(); - QLinearGradient linearGrad(pathRect.topLeft(), pathRect.bottomLeft()); - QColor col1 = color.lighter(150); - col1.setAlpha(20); - QColor col2 = color; - col2.setAlpha(80); - linearGrad.setColorAt(0, col1); - linearGrad.setColorAt(1, col2); - QBrush brush(linearGrad); - + if (bg.isValid()) { + QLinearGradient linearGrad(pathRect.topLeft(), pathRect.bottomLeft()); + QColor col1 = fg.lighter(150); + col1.setAlpha(20); + QColor col2 = fg; + col2.setAlpha(80); + linearGrad.setColorAt(0, col1); + linearGrad.setColorAt(1, col2); + painter->setBrush(QBrush(linearGrad)); + } else { + painter->setBrush(QBrush()); + } painter->setRenderHint(QPainter::Antialiasing); pen.setJoinStyle(Qt::RoundJoin); painter->setPen(pen); - painter->setBrush(brush); painter->drawPath(path); painter->restore(); } +void TextEditorOverlay::fillSelection(QPainter *painter, const QTextCursor &begin, const QTextCursor &end, + const QColor &color) +{ + if (begin.isNull() || end.isNull() || begin.position() > end.position()) + return; + + QPainterPath path = createSelectionPath(begin, end, m_editor->viewport()->rect()); + + painter->save(); + painter->translate(-.5, -.5); + painter->setRenderHint(QPainter::Antialiasing); + painter->fillPath(path, color); + painter->restore(); +} void TextEditorOverlay::paint(QPainter *painter, const QRect &clip) { @@ -266,10 +296,89 @@ void TextEditorOverlay::paint(QPainter *painter, const QRect &clip) paintSelection(painter, selection.m_cursor_begin, selection.m_cursor_end, - selection.m_color + selection.m_fg, + selection.m_bg + ); + } +} + +void TextEditorOverlay::fill(QPainter *painter, const QColor &color, const QRect &clip) +{ + Q_UNUSED(clip); + for (int i = 0; i < m_selections.size(); ++i) { + const OverlaySelection &selection = m_selections.at(i); + if (selection.m_fixedLength >= 0 + && selection.m_cursor_end.position() - selection.m_cursor_begin.position() + != selection.m_fixedLength) + continue; + + fillSelection(painter, + selection.m_cursor_begin, + selection.m_cursor_end, + color ); } } +void TextEditorOverlay::paintInverted(QPainter *painter, const QRect &clip, const QColor &color) +{ + QPainterPath path; + for (int i = 0; i < m_selections.size(); ++i) { + const OverlaySelection &selection = m_selections.at(i); + if (selection.m_fixedLength >= 0 + && selection.m_cursor_end.position() - selection.m_cursor_begin.position() + != selection.m_fixedLength) + continue; + path.addPath(createSelectionPath(selection.m_cursor_begin, selection.m_cursor_end, clip)); + } + + QRect viewportRect = m_editor->viewport()->rect(); + QColor background = Qt::black; + background.setAlpha(30); + + if (path.isEmpty()) { + painter->fillRect(viewportRect, background); + return; + } + +// QPainterPath all; +// all.addRect(viewportRect); +// QPainterPath inversion = all.subtracted(path); + + painter->save(); + QColor penColor = color; + penColor.setAlpha(220); + QPen pen(penColor, m_borderWidth); + QColor brush = color; + brush.setAlpha(30); + painter->translate(-.5, -.5); + +// painter->setRenderHint(QPainter::Antialiasing); + //pen.setJoinStyle(Qt::RoundJoin); + painter->setPen(pen); + painter->setBrush(QBrush()); + painter->drawPath(path); + + painter->translate(.5, .5); + + QPixmap shadow(clip.size()); + shadow.fill(background); + QPainter pmp(&shadow); + pmp.translate(-.5, -.5); + pmp.setRenderHint(QPainter::Antialiasing); + pmp.setCompositionMode(QPainter::CompositionMode_Source); + path.translate(-clip.topLeft()); + pen.setColor(Qt::transparent); + pmp.setPen(pen); + pmp.setBrush(Qt::transparent); + pmp.drawPath(path); + pmp.end(); + + painter->drawPixmap(clip.topLeft(), shadow); + +// painter->fillPath(inversion, background); + painter->restore(); +} + diff --git a/src/plugins/texteditor/texteditoroverlay.h b/src/plugins/texteditor/texteditoroverlay.h index 6516b69bca..7983677643 100644 --- a/src/plugins/texteditor/texteditoroverlay.h +++ b/src/plugins/texteditor/texteditoroverlay.h @@ -11,7 +11,8 @@ struct TEXTEDITOR_EXPORT OverlaySelection { OverlaySelection():m_fixedLength(-1){} QTextCursor m_cursor_begin; QTextCursor m_cursor_end; - QColor m_color; + QColor m_fg; + QColor m_bg; int m_fixedLength; }; @@ -21,7 +22,9 @@ Q_OBJECT BaseTextEditor *m_editor; QWidget *m_viewport; +public: QList<OverlaySelection> m_selections; +private: bool m_visible; int m_borderWidth; @@ -31,6 +34,9 @@ public: QRect rect() const; void paint(QPainter *painter, const QRect &clip); + void fill(QPainter *painter, const QColor &color, const QRect &clip); + + void paintInverted(QPainter *painter, const QRect &clip, const QColor &color); bool isVisible() const { return m_visible; } void setVisible(bool b); @@ -40,13 +46,17 @@ public: void update(); void clear(); - void addOverlaySelection(const QTextCursor &cursor, const QColor &color, bool lockSize = false); - void addOverlaySelection(int begin, int end, const QColor &color, bool lockSize = false); + void addOverlaySelection(const QTextCursor &cursor, const QColor &fg, const QColor &bg, bool lockSize = false); + void addOverlaySelection(int begin, int end, const QColor &fg, const QColor &bg, bool lockSize = false); inline bool isEmpty() const { return m_selections.isEmpty(); } private: - void paintSelection(QPainter *painter, const QTextCursor &begin, const QTextCursor &end, const QColor &color); + QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip); + void paintSelection(QPainter *painter, const QTextCursor &begin, const QTextCursor &end, + const QColor &fg, const QColor &bg); + void fillSelection(QPainter *painter, const QTextCursor &begin, const QTextCursor &end, + const QColor &color); }; |