diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a86b95..b3645f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ 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) - 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..3a67422 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,45 @@ 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()); + } +} + +/// 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 @@ -773,7 +813,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..fd0088e 100644 --- a/edbee-lib/edbee/models/textrange.h +++ b/edbee-lib/edbee/models/textrange.h @@ -74,6 +74,9 @@ 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 moveCaretToLineBoundaryAtOffset( 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..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 @@ -39,6 +43,8 @@ TextEditorComponent::TextEditorComponent(TextEditorController* controller, QWidg , caretTimer_(nullptr) , controllerRef_(controller) , textEditorRenderer_(nullptr) + , clickCount_(0) + , lastClickEvent_(0) { textEditorRenderer_ = new TextEditorRenderer( controller->textRenderer()); @@ -378,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 /// @@ -401,6 +420,17 @@ void TextEditorComponent::mousePressEvent(QMouseEvent* event) int col = renderer->columnIndexForXpos( line, x ); if( event->button() == Qt::LeftButton ) { + 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,9 +473,13 @@ void TextEditorComponent::mouseDoubleClickEvent( QMouseEvent* event ) { static SelectionCommand selectWord( SelectionCommand::SelectWord ); if( event->button() == Qt::LeftButton ) { + registerClickEvent(); + if( clickCount_ > 2 ) { + return; + } - if( event->modifiers()&Qt::ControlModifier ) { + if( event->modifiers()&Qt::ControlModifier ) { // get the location of the double int x = event->x(); int y = event->y(); @@ -454,7 +488,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 +514,25 @@ 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); + + 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; + } + + 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..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,6 +87,8 @@ public slots: TextEditorController* controllerRef_; ///< A reference to the controller TextEditorRenderer* textEditorRenderer_; /// A text-editor renderer + 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);