gui: use TapHandler for double-click pair selection
MouseArea's onDoubleClicked doesn't fire when placed on a TextEdit with selectByMouse:true — the TextEdit's internal mouse handling consumes the events. TapHandler coexists with TextEdit's mouse handling and reliably receives double-tap events. Double-click on a bracket or quote delimiter now selects the content between the matching pair. Quotes use parity to decide opener/closer direction. Falls back to word selection when no delimiter is adjacent. Works in chat blocks (mainTextEdit, textComponent) and prompt textarea.
This commit is contained in:
parent
840723de3b
commit
8147b3885f
|
|
@ -193,14 +193,10 @@ Column {
|
|||
// Fast path: single TextEdit for the concatenated HTML.
|
||||
// Diagrams are handled separately via the segments list.
|
||||
// Editable for scratchpad use - changes are local only, not persisted.
|
||||
Item {
|
||||
width: root.width
|
||||
height: mainTextEdit.height
|
||||
visible: !hasDiagrams()
|
||||
|
||||
TextEdit {
|
||||
id: mainTextEdit
|
||||
width: parent.width
|
||||
width: root.width
|
||||
visible: !hasDiagrams()
|
||||
text: root.blockRenderedHtml
|
||||
textFormat: Text.RichText
|
||||
selectByMouse: true
|
||||
|
|
@ -210,35 +206,26 @@ Column {
|
|||
font.pointSize: theme.fontSize > 0 ? theme.fontSize : 12
|
||||
selectionColor: theme.highlightColor
|
||||
selectedTextColor: theme.highlightedTextColor
|
||||
|
||||
// Double-click: bracket/quote pair or word select
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onDoubleTapped: function(eventPoint, button) {
|
||||
var pos = eventPoint.position
|
||||
if (!TextSelection.selectBracketPair(mainTextEdit, pos.x, pos.y)) {
|
||||
TextSelection.selectWordAt(mainTextEdit, pos.x, pos.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Acme-style mouse handling: B2=execute, B3=plumb
|
||||
// B1+B2=cut, B1+B3=paste (chord detection)
|
||||
// Double-click on bracket: select text between matching pair
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||
z: 1
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
// Delimiter under cursor: select the pair.
|
||||
// Otherwise select the word ourselves (the overlay
|
||||
// swallows the event, so TextEdit won't do it).
|
||||
if (!TextSelection.selectBracketPair(mainTextEdit, mouse.x, mouse.y)) {
|
||||
TextSelection.selectWordAt(mainTextEdit, mouse.x, mouse.y)
|
||||
}
|
||||
mouse.accepted = true
|
||||
}
|
||||
}
|
||||
acceptedButtons: Qt.MiddleButton | Qt.RightButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
onPressed: function(mouse) {
|
||||
// Left button single clicks pass through to TextEdit for selection
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
mouse.accepted = false
|
||||
return
|
||||
}
|
||||
|
||||
if (mouse.buttons & Qt.LeftButton) {
|
||||
if (mouse.button === Qt.MiddleButton) {
|
||||
mainTextEdit.cut()
|
||||
|
|
@ -261,7 +248,6 @@ Column {
|
|||
if (sel && sel.trim() !== "") {
|
||||
plumber.plumb(sel.trim(), sessionCwd())
|
||||
} else {
|
||||
// No selection - expand word and highlight it
|
||||
selectAndPlumb(mainTextEdit, mouse.x, mouse.y)
|
||||
}
|
||||
}
|
||||
|
|
@ -401,29 +387,25 @@ Column {
|
|||
selectionColor: theme.highlightColor
|
||||
selectedTextColor: theme.highlightedTextColor
|
||||
|
||||
// Acme-style mouse handling with chord support
|
||||
// Double-click: bracket/quote pair or word select
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onDoubleTapped: function(eventPoint, button) {
|
||||
var pos = eventPoint.position
|
||||
if (!TextSelection.selectBracketPair(textEdit, pos.x, pos.y)) {
|
||||
TextSelection.selectWordAt(textEdit, pos.x, pos.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Acme-style mouse handling: B2=execute, B3=plumb
|
||||
// B1+B2=cut, B1+B3=paste (chord detection)
|
||||
// Double-click on bracket: select text between matching pair
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||
acceptedButtons: Qt.MiddleButton | Qt.RightButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (!TextSelection.selectBracketPair(textEdit, mouse.x, mouse.y)) {
|
||||
TextSelection.selectWordAt(textEdit, mouse.x, mouse.y)
|
||||
}
|
||||
mouse.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: function(mouse) {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
mouse.accepted = false
|
||||
return
|
||||
}
|
||||
|
||||
if (mouse.buttons & Qt.LeftButton) {
|
||||
if (mouse.button === Qt.MiddleButton) {
|
||||
textEdit.cut()
|
||||
|
|
@ -441,7 +423,6 @@ Column {
|
|||
}
|
||||
mouse.accepted = true
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
// B3: Plumb selection or word under cursor
|
||||
if (plumber.available()) {
|
||||
var sel = textEdit.selectedText
|
||||
if (sel && sel.trim() !== "") {
|
||||
|
|
|
|||
|
|
@ -467,11 +467,21 @@ Item {
|
|||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
// Double-click: bracket/quote pair or word select
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onDoubleTapped: function(eventPoint, button) {
|
||||
var pos = eventPoint.position
|
||||
if (!TextSelection.selectBracketPair(promptInput, pos.x, pos.y)) {
|
||||
TextSelection.selectWordAt(promptInput, pos.x, pos.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Acme-style mouse chording overlay
|
||||
// B1 double-click = bracket/quote pair or word select
|
||||
// B2 = execute selection
|
||||
// B3 = plumb selection / context menu
|
||||
// B1+B2 = cut (snarf)
|
||||
|
|
@ -479,67 +489,43 @@ Item {
|
|||
MouseArea {
|
||||
id: chordArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||
acceptedButtons: Qt.MiddleButton | Qt.RightButton
|
||||
propagateComposedEvents: true
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
// Track if B1 (left) is currently held for chord detection
|
||||
property bool leftHeld: false
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
// Map coordinates from chordArea to promptInput
|
||||
var mappedPos = chordArea.mapToItem(promptInput, mouse.x, mouse.y)
|
||||
if (!TextSelection.selectBracketPair(promptInput, mappedPos.x, mappedPos.y)) {
|
||||
TextSelection.selectWordAt(promptInput, mappedPos.x, mappedPos.y)
|
||||
}
|
||||
mouse.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: function(mouse) {
|
||||
// Left button single clicks pass through to TextArea for selection
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
mouse.accepted = false
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this is a chord (B1 already held)
|
||||
if (mouse.buttons & Qt.LeftButton) {
|
||||
leftHeld = true
|
||||
if (mouse.button === Qt.MiddleButton) {
|
||||
// B1+B2 = cut
|
||||
promptInput.cut()
|
||||
mouse.accepted = true
|
||||
return
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
// B1+B3 = paste
|
||||
promptInput.paste()
|
||||
mouse.accepted = true
|
||||
return
|
||||
}
|
||||
}
|
||||
leftHeld = false
|
||||
mouse.accepted = false // Let it propagate for non-chord
|
||||
mouse.accepted = false
|
||||
}
|
||||
|
||||
onClicked: function(mouse) {
|
||||
// Only handle non-chord clicks
|
||||
if (leftHeld) {
|
||||
leftHeld = false
|
||||
return
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.MiddleButton) {
|
||||
// B2: Execute selection as prompt
|
||||
var sel = promptInput.selectedText
|
||||
if (sel && sel.trim() !== "") {
|
||||
ollie.submit(sel.trim())
|
||||
} else {
|
||||
// No selection - ignore
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
// B3: Plumb selection or word under cursor
|
||||
if (!plumber.available()) return
|
||||
var sel = promptInput.selectedText
|
||||
if (sel && sel.trim() !== "") {
|
||||
|
|
|
|||
Loading…
Reference in New Issue