From ba86414ddf0b4176561fc8626d4ef8b63271cb6f Mon Sep 17 00:00:00 2001 From: miruka Date: Thu, 26 Mar 2020 23:24:37 -0400 Subject: [PATCH] Implement shift+click/A-B message selection --- TODO.md | 1 - src/gui/Base/HListView.qml | 13 +++++++++++ src/gui/Pages/Chat/Timeline/EventContent.qml | 22 ++++++++++++++++++- src/gui/Pages/Chat/Timeline/EventDelegate.qml | 17 +++++++++++--- src/gui/Pages/Chat/Timeline/EventImage.qml | 9 ++++++++ src/gui/Utils.qml | 20 +++++++++++++++++ src/icons/thin/select-until-here.svg | 3 +++ 7 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 src/icons/thin/select-until-here.svg diff --git a/TODO.md b/TODO.md index eb517cf8..88bcee26 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,6 @@ - Long-press-drag to select multiple messages on touch - Drag to select multiple messages on non-touch -- Shift+click to select everything in between - Drag-scrolling in room pane a tiny bit activates the delegates diff --git a/src/gui/Base/HListView.qml b/src/gui/Base/HListView.qml index a8699156..105b0aed 100644 --- a/src/gui/Base/HListView.qml +++ b/src/gui/Base/HListView.qml @@ -64,22 +64,35 @@ ListView { } } + onSelectedCountChanged: if (! selectedCount) lastCheckedDelegateIndex = 0 + property bool allowDragging: true property alias cursorShape: mouseArea.cursorShape property int currentItemHeight: currentItem ? currentItem.height : 0 + property var checkedDelegates: ({}) + property int lastCheckedDelegateIndex: 0 property int selectedCount: Object.keys(checkedDelegates).length function delegatesChecked(...indices) { + print( indices) for (const i of indices) { const model = listView.model.get(i) checkedDelegates[model.id] = model } + + lastCheckedDelegateIndex = indices.slice(-1)[0] + checkedDelegatesChanged() } + function delegatesFromLastToHereChecked(here) { + const indices = utils.range(lastCheckedDelegateIndex, here) + eventList.delegatesChecked(...indices) + } + function delegatesUnchecked(...indices) { for (const i of indices) { const model = listView.model.get(i) diff --git a/src/gui/Pages/Chat/Timeline/EventContent.qml b/src/gui/Pages/Chat/Timeline/EventContent.qml index 3f14feea..47fc2696 100644 --- a/src/gui/Pages/Chat/Timeline/EventContent.qml +++ b/src/gui/Pages/Chat/Timeline/EventContent.qml @@ -183,6 +183,7 @@ HRowLayout { PointHandler { id: mousePointHandler acceptedButtons: Qt.LeftButton + acceptedModifiers: Qt.NoModifier acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Eraser @@ -206,6 +207,24 @@ HRowLayout { property bool checkedNow: false } + PointHandler { + id: mouseShiftPointHandler + acceptedButtons: Qt.LeftButton + acceptedModifiers: Qt.ShiftModifier + acceptedPointerTypes: + PointerDevice.GenericPointer | PointerDevice.Eraser + + onActiveChanged: { + if (active && + ! eventDelegate.checked && + (! parent.hoveredLink || + ! parent.enableLinkActivation)) { + + eventList.delegatesFromLastToHereChecked(model.index) + } + } + } + TapHandler { id: touchTapHandler acceptedButtons: Qt.LeftButton @@ -234,7 +253,8 @@ HRowLayout { z: -100 color: eventDelegate.checked && ! contentLabel.selectedText && - ! mousePointHandler.active ? + ! mousePointHandler.active && + ! mouseShiftPointHandler.active ? theme.chat.message.checkedBackground : isOwn? diff --git a/src/gui/Pages/Chat/Timeline/EventDelegate.qml b/src/gui/Pages/Chat/Timeline/EventDelegate.qml index 151eea9c..187e4488 100644 --- a/src/gui/Pages/Chat/Timeline/EventDelegate.qml +++ b/src/gui/Pages/Chat/Timeline/EventDelegate.qml @@ -57,8 +57,6 @@ HColumnLayout { combine ? theme.spacing / (compact ? 4 : 2) : theme.spacing * (compact ? 1 : 2) - readonly property alias leftTapHandler: leftTapHandler - // Needed because of eventList's MouseArea which steals the // HSelectableLabel's MouseArea hover events onCursorShapeChanged: eventList.cursorShape = cursorShape @@ -114,11 +112,17 @@ HColumnLayout { } TapHandler { - id: leftTapHandler acceptedButtons: Qt.LeftButton + acceptedModifiers: Qt.NoModifier onTapped: toggleChecked() } + TapHandler { + acceptedButtons: Qt.LeftButton + acceptedModifiers: Qt.ShiftModifier + onTapped: eventList.delegatesFromLastToHereChecked(model.index) + } + TapHandler { acceptedButtons: Qt.RightButton acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen @@ -151,6 +155,13 @@ HColumnLayout { onTriggered: eventList.checkedDelegates = {} } + HMenuItem { + visible: model.index !== 0 + icon.name: "select-until-here" + text: qsTr("Select until here") + onTriggered: eventList.delegatesFromLastToHereChecked(model.index) + } + HMenuItem { id: copyMedia icon.name: "copy-link" diff --git a/src/gui/Pages/Chat/Timeline/EventImage.qml b/src/gui/Pages/Chat/Timeline/EventImage.qml index d2b6c795..230b46cb 100644 --- a/src/gui/Pages/Chat/Timeline/EventImage.qml +++ b/src/gui/Pages/Chat/Timeline/EventImage.qml @@ -83,6 +83,7 @@ HMxcImage { TapHandler { + acceptedModifiers: Qt.NoModifier onTapped: eventList.selectedCount ? eventDelegate.toggleChecked() : getOpenUrl(Qt.openUrlExternally) @@ -90,6 +91,14 @@ HMxcImage { gesturePolicy: TapHandler.ReleaseWithinBounds } + TapHandler { + acceptedModifiers: Qt.ShiftModifier + onTapped: + eventList.delegatesFromLastToHereChecked(singleMediaInfo.index) + + gesturePolicy: TapHandler.ReleaseWithinBounds + } + HoverHandler { id: hover onHoveredChanged: { diff --git a/src/gui/Utils.qml b/src/gui/Utils.qml index e1eeafc9..3d7f5b8b 100644 --- a/src/gui/Utils.qml +++ b/src/gui/Utils.qml @@ -83,6 +83,26 @@ QtObject { } + function range(startOrEnd, end=null, ) { + // range(3) → [0, 1, 2, 3] + // range(3, 6) → [3, 4, 5, 6] + // range(3, -1) → [3, 2, 1, 0, -1] + + const numbers = [] + let realStart = end ? startOrEnd : 0 + let realEnd = end ? end : startOrEnd + + if (realEnd < realStart) + for (let i = realStart; i >= realEnd; i--) + numbers.push(i) + else + for (let i = realStart; i <= realEnd; i++) + numbers.push(i) + + return numbers + } + + function isEmptyObject(obj) { return Object.entries(obj).length === 0 && obj.constructor === Object } diff --git a/src/icons/thin/select-until-here.svg b/src/icons/thin/select-until-here.svg new file mode 100644 index 00000000..f6064c93 --- /dev/null +++ b/src/icons/thin/select-until-here.svg @@ -0,0 +1,3 @@ + + +