From 2b054281eb33ba3870216aadc3b87bffc66709ef Mon Sep 17 00:00:00 2001 From: Rick Blommers Date: Fri, 20 Nov 2020 23:35:16 +0100 Subject: [PATCH 1/2] ref #114, Double-click + drag should end at word boundaries --- CHANGELOG.md | 1 + edbee-lib/edbee/commands/selectioncommand.h | 1 + edbee-lib/edbee/models/textrange.cpp | 18 +++++++++++++++++- edbee-lib/edbee/models/textrange.h | 2 ++ .../views/components/texteditorcomponent.cpp | 19 +++++++++++++++++-- .../views/components/texteditorcomponent.h | 1 + 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a86b95..48d67c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ edbee.lib: +- fix #114, Double-click + drag should end at word boundaries - #112, Workaround for missing Qt::endl in Qt 5.12 - Support for sticky-selection in replaceSelection methods. (Required for InpuMethod entry) - Improved TextEditorComponent::InputMethodEvent... It now support special chars entry like expected. (Option+e, e => ´ => é) diff --git a/edbee-lib/edbee/commands/selectioncommand.h b/edbee-lib/edbee/commands/selectioncommand.h index 8dda1be..c5ce726 100644 --- a/edbee-lib/edbee/commands/selectioncommand.h +++ b/edbee-lib/edbee/commands/selectioncommand.h @@ -25,6 +25,7 @@ class EDBEE_EXPORT SelectionCommand : public TextEditorCommand MoveCaretByWord, ///< moves the caret(s) by the given amount of words MoveCaretByLine, ///< moves the caret(s) by the given amount of lines MoveCaretByPage, ///< moves the caret(s) by the given amount of pages + MoveCaretToWordBoundary, ///< moves the caret to a line-boundary (<0 begin of line, >0 end of line) MoveCaretToLineBoundary, ///< moves the caret to a line-boundary (<0 begin of line, >0 end of line) MoveCaretToDocumentBegin, ///< moves the caret to the document start MoveCaretToDocumentEnd, ///< moves the caret to the document end diff --git a/edbee-lib/edbee/models/textrange.cpp b/edbee-lib/edbee/models/textrange.cpp index 362918d..7593364 100644 --- a/edbee-lib/edbee/models/textrange.cpp +++ b/edbee-lib/edbee/models/textrange.cpp @@ -7,6 +7,7 @@ #include "textdocument.h" #include "textrange.h" +#include "texteditorconfig.h" #include "edbee/debug.h" namespace edbee { @@ -244,6 +245,22 @@ void TextRange::moveCaretToLineBoundary(TextDocument* doc, int amount, const QSt setCaretBounded( doc, caret ); } +/// Moves the caret to a word boundary (used for word dragging selections) +void TextRange::moveCaretToWordBoundaryAtOffset(TextDocument *doc, int newOffset) +{ + TextEditorConfig* config = doc->config(); + + // changed offset + setCaret(newOffset); + // left direction + if( newOffset < anchor()) { + moveCaretByCharGroup(doc, -1, config->whitespaces(), config->charGroups()); + // right direction + } else { + moveCaretByCharGroup(doc, 1, config->whitespaces(), config->charGroups()); + } +} + /// Expands the selection range so it only consists of full lines /// amount specifies the amount (and the direction) of the expansions @@ -773,7 +790,6 @@ void TextRangeSetBase::toggleWordSelectionAt(int offset, const QString& whitespa selectWordAt( offset, whitespace, characterGroups ); } - /// This method moves the carets by character void TextRangeSetBase::moveCarets( int amount ) { diff --git a/edbee-lib/edbee/models/textrange.h b/edbee-lib/edbee/models/textrange.h index ccd4c7d..c2a80c3 100644 --- a/edbee-lib/edbee/models/textrange.h +++ b/edbee-lib/edbee/models/textrange.h @@ -74,6 +74,8 @@ class EDBEE_EXPORT TextRange { void moveAnchorUntilChar( TextDocument* doc, int amount, const QString& chars ); void moveCaretByCharGroup( TextDocument* doc, int amount, const QString& whitespace, const QStringList& characterGroups ); void moveCaretToLineBoundary( TextDocument* doc, int amount, const QString& whitespace ); + void moveCaretToWordBoundaryAtOffset( TextDocument* doc, int offset ); + void expandToFullLine( TextDocument* doc, int amount ); void deselectTrailingNewLine( TextDocument* doc ); diff --git a/edbee-lib/edbee/views/components/texteditorcomponent.cpp b/edbee-lib/edbee/views/components/texteditorcomponent.cpp index dd68fef..555297c 100644 --- a/edbee-lib/edbee/views/components/texteditorcomponent.cpp +++ b/edbee-lib/edbee/views/components/texteditorcomponent.cpp @@ -39,6 +39,7 @@ TextEditorComponent::TextEditorComponent(TextEditorController* controller, QWidg , caretTimer_(nullptr) , controllerRef_(controller) , textEditorRenderer_(nullptr) + , clickCount_(0) { textEditorRenderer_ = new TextEditorRenderer( controller->textRenderer()); @@ -401,6 +402,7 @@ void TextEditorComponent::mousePressEvent(QMouseEvent* event) int col = renderer->columnIndexForXpos( line, x ); if( event->button() == Qt::LeftButton ) { + clickCount_ = 1; if( event->modifiers()&Qt::ControlModifier ) { controller()->addCaretAt( line, col ); } else { @@ -441,11 +443,13 @@ void TextEditorComponent::mouseReleaseEvent(QMouseEvent *event) /// @param event the mouse double click that occured void TextEditorComponent::mouseDoubleClickEvent( QMouseEvent* event ) { + qlog_info() << "mouseDoubleClickEvent" << event; + static SelectionCommand selectWord( SelectionCommand::SelectWord ); if( event->button() == Qt::LeftButton ) { + clickCount_ = 2; if( event->modifiers()&Qt::ControlModifier ) { - // get the location of the double int x = event->x(); int y = event->y(); @@ -454,7 +458,7 @@ void TextEditorComponent::mouseDoubleClickEvent( QMouseEvent* event ) // add the word there SelectionCommand toggleWordSelectionAtCommand( SelectionCommand::ToggleWordSelectionAt, textDocument()->offsetFromLineAndColumn(line,col) ); - controller()->executeCommand( &toggleWordSelectionAtCommand ); + controller()->executeCommand( &toggleWordSelectionAtCommand ); } else { controller()->executeCommand( &selectWord ); } @@ -480,6 +484,17 @@ void TextEditorComponent::mouseMoveEvent(QMouseEvent* event ) if( line >= 0 ) { col = renderer->columnIndexForXpos( line, x ); } if( line < 0 ) { line = 0; } + if( clickCount_ == 2 ) { + TextRange range = textSelection()->range(0); // copy range + + int newOffset = textDocument()->offsetFromLineAndColumn(line, col); + range.moveCaretToWordBoundaryAtOffset(textDocument(), newOffset); + + controller()->moveCaretToOffset(range.caret(), true); + return; + } + + if( event->modifiers() & Qt::ControlModifier) { controller()->moveCaretTo( line, col, true, controller()->textSelection()->rangeCount() - 1 ); } else { diff --git a/edbee-lib/edbee/views/components/texteditorcomponent.h b/edbee-lib/edbee/views/components/texteditorcomponent.h index b46e310..b1796e4 100644 --- a/edbee-lib/edbee/views/components/texteditorcomponent.h +++ b/edbee-lib/edbee/views/components/texteditorcomponent.h @@ -86,6 +86,7 @@ public slots: TextEditorController* controllerRef_; ///< A reference to the controller TextEditorRenderer* textEditorRenderer_; /// A text-editor renderer + int clickCount_; ///< The number of clicks }; } // edbee From f4c1cca2d809be48ab6b79c3050b11100ce3a73a Mon Sep 17 00:00:00 2001 From: Rick Blommers Date: Sat, 21 Nov 2020 00:19:54 +0100 Subject: [PATCH 2/2] ref #115, basic Tripple-click support (TODO: still need to fix, anchor movement in controllers) --- CHANGELOG.md | 1 + edbee-lib/edbee/models/textrange.cpp | 23 +++++++++ edbee-lib/edbee/models/textrange.h | 1 + .../views/components/texteditorcomponent.cpp | 48 +++++++++++++++++-- .../views/components/texteditorcomponent.h | 4 +- edbee-test/edbee/models/textrangetest.cpp | 2 +- 6 files changed, 72 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48d67c9..b3645f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ edbee.lib: +- ref #115, basic Tripple-click support (TODO: still need to fix, anchor movement in controllers) - fix #114, Double-click + drag should end at word boundaries - #112, Workaround for missing Qt::endl in Qt 5.12 - Support for sticky-selection in replaceSelection methods. (Required for InpuMethod entry) diff --git a/edbee-lib/edbee/models/textrange.cpp b/edbee-lib/edbee/models/textrange.cpp index 7593364..3a67422 100644 --- a/edbee-lib/edbee/models/textrange.cpp +++ b/edbee-lib/edbee/models/textrange.cpp @@ -261,6 +261,29 @@ void TextRange::moveCaretToWordBoundaryAtOffset(TextDocument *doc, int newOffset } } +/// Moves the caret to a word boundary (used for word dragging selections) +void TextRange::moveCaretToLineBoundaryAtOffset(TextDocument *doc, int newOffset) +{ + TextEditorConfig* config = doc->config(); + + // changed offset + setCaret(newOffset); + + int firstLine = doc->lineFromOffset(min()); + int lastLine = doc->lineFromOffset(max()); + + int newLine = doc->lineFromOffset(newOffset); + + // left direction + if( newLine < lastLine ) { + this->caret_ = doc->offsetFromLine(newLine); + this->anchor_ = doc->offsetFromLine(lastLine+1); + // right direction + } else if( newLine > firstLine) { + this->anchor_ = doc->offsetFromLine(firstLine-1); + this->caret_ = doc->offsetFromLine(newLine+1); + } +} /// Expands the selection range so it only consists of full lines /// amount specifies the amount (and the direction) of the expansions diff --git a/edbee-lib/edbee/models/textrange.h b/edbee-lib/edbee/models/textrange.h index c2a80c3..fd0088e 100644 --- a/edbee-lib/edbee/models/textrange.h +++ b/edbee-lib/edbee/models/textrange.h @@ -75,6 +75,7 @@ class EDBEE_EXPORT TextRange { void moveCaretByCharGroup( TextDocument* doc, int amount, const QString& whitespace, const QStringList& characterGroups ); void moveCaretToLineBoundary( TextDocument* doc, int amount, const QString& whitespace ); void moveCaretToWordBoundaryAtOffset( TextDocument* doc, int offset ); + void moveCaretToLineBoundaryAtOffset( TextDocument* doc, int offset ); void expandToFullLine( TextDocument* doc, int amount ); diff --git a/edbee-lib/edbee/views/components/texteditorcomponent.cpp b/edbee-lib/edbee/views/components/texteditorcomponent.cpp index 555297c..d59b140 100644 --- a/edbee-lib/edbee/views/components/texteditorcomponent.cpp +++ b/edbee-lib/edbee/views/components/texteditorcomponent.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,9 @@ namespace edbee { +const qint64 TRIPLE_CLICK_DELAY_IN_MS = 250; // 0.25 seconds + + /// The default texteditor compenent constructor /// @param controller the active controller for this editor /// @param parent the parent QObject @@ -40,6 +44,7 @@ TextEditorComponent::TextEditorComponent(TextEditorController* controller, QWidg , controllerRef_(controller) , textEditorRenderer_(nullptr) , clickCount_(0) + , lastClickEvent_(0) { textEditorRenderer_ = new TextEditorRenderer( controller->textRenderer()); @@ -379,6 +384,19 @@ QVariant TextEditorComponent::inputMethodQuery( Qt::InputMethodQuery p ) const return QVariant(); } +/// registers a click event and modifies the clickcount and last-click moment +void TextEditorComponent::registerClickEvent() +{ + qint64 currentClickEvent = QDateTime::currentMSecsSinceEpoch(); + if( currentClickEvent - lastClickEvent_ <=TRIPLE_CLICK_DELAY_IN_MS ) { + clickCount_ += 1; + } else { + clickCount_ = 1; + } +// qlog_info() << "clickcount: " << clickCount_; + lastClickEvent_ = currentClickEvent; +} + /// A mouse press happens /// @@ -402,7 +420,17 @@ void TextEditorComponent::mousePressEvent(QMouseEvent* event) int col = renderer->columnIndexForXpos( line, x ); if( event->button() == Qt::LeftButton ) { - clickCount_ = 1; + qint64 currentClickEvent = QDateTime::currentMSecsSinceEpoch(); + registerClickEvent(); + if( clickCount_ > 1 ) { + if( clickCount_ == 3) { + TextRange range = textSelection()->range(0); + SelectionCommand toggleWordSelectionAtCommand( SelectionCommand::SelectFullLine, 0); + controller()->executeCommand( &toggleWordSelectionAtCommand ); + } + return; + } + if( event->modifiers()&Qt::ControlModifier ) { controller()->addCaretAt( line, col ); } else { @@ -443,11 +471,13 @@ void TextEditorComponent::mouseReleaseEvent(QMouseEvent *event) /// @param event the mouse double click that occured void TextEditorComponent::mouseDoubleClickEvent( QMouseEvent* event ) { - qlog_info() << "mouseDoubleClickEvent" << event; - static SelectionCommand selectWord( SelectionCommand::SelectWord ); if( event->button() == Qt::LeftButton ) { - clickCount_ = 2; + registerClickEvent(); + if( clickCount_ > 2 ) { + return; + } + if( event->modifiers()&Qt::ControlModifier ) { // get the location of the double @@ -485,11 +515,19 @@ void TextEditorComponent::mouseMoveEvent(QMouseEvent* event ) if( line < 0 ) { line = 0; } if( clickCount_ == 2 ) { - TextRange range = textSelection()->range(0); // copy range + TextRange range = textSelection()->range(0); int newOffset = textDocument()->offsetFromLineAndColumn(line, col); range.moveCaretToWordBoundaryAtOffset(textDocument(), newOffset); + controller()->moveCaretToOffset(range.caret(), true); + return; + } else if( clickCount_ == 3 ) { + TextRange range = textSelection()->range(0); // copy range + + int newOffset = textDocument()->offsetFromLineAndColumn(line, col); + range.moveCaretToLineBoundaryAtOffset(textDocument(), newOffset); + controller()->moveCaretToOffset(range.caret(), true); return; } diff --git a/edbee-lib/edbee/views/components/texteditorcomponent.h b/edbee-lib/edbee/views/components/texteditorcomponent.h index b1796e4..02676ee 100644 --- a/edbee-lib/edbee/views/components/texteditorcomponent.h +++ b/edbee-lib/edbee/views/components/texteditorcomponent.h @@ -55,6 +55,7 @@ class EDBEE_EXPORT TextEditorComponent : public QWidget virtual void keyReleaseEvent ( QKeyEvent* event ); void inputMethodEvent( QInputMethodEvent* m ); QVariant inputMethodQuery( Qt::InputMethodQuery p ) const; + void registerClickEvent(); virtual void mousePressEvent( QMouseEvent* event ); virtual void mouseReleaseEvent( QMouseEvent* event ); virtual void mouseDoubleClickEvent( QMouseEvent* event ); @@ -86,7 +87,8 @@ public slots: TextEditorController* controllerRef_; ///< A reference to the controller TextEditorRenderer* textEditorRenderer_; /// A text-editor renderer - int clickCount_; ///< The number of clicks + int clickCount_; ///< The number of clicks + qint64 lastClickEvent_; ///< Last click event time }; } // edbee diff --git a/edbee-test/edbee/models/textrangetest.cpp b/edbee-test/edbee/models/textrangetest.cpp index 6d4b648..f47dd5d 100644 --- a/edbee-test/edbee/models/textrangetest.cpp +++ b/edbee-test/edbee/models/textrangetest.cpp @@ -32,7 +32,7 @@ do { \ /// @param definition the definition. In the format anchor>caret,anchor>caret static void addRanges( TextRangeSet* sel, const QString& definition ) { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QStringList ranges = definition.split(",", Qt::SkipEmptyParts); #else QStringList ranges = definition.split(",", QString::SkipEmptyParts);