Add context menu for text fields and areas
This commit is contained in:
parent
657b700fcd
commit
612ded755a
|
@ -93,6 +93,8 @@ TextArea {
|
||||||
event.modifiers & Qt.MetaModifier
|
event.modifiers & Qt.MetaModifier
|
||||||
) event.accepted = true
|
) event.accepted = true
|
||||||
|
|
||||||
|
Keys.onMenuPressed: contextMenu.spawn(false)
|
||||||
|
|
||||||
// Prevent leaking arrow presses to parent elements when the carret is at
|
// Prevent leaking arrow presses to parent elements when the carret is at
|
||||||
// the beginning or end of the text
|
// the beginning or end of the text
|
||||||
Keys.onLeftPressed: event.accepted = cursorPosition === 0 && ! selectedText
|
Keys.onLeftPressed: event.accepted = cursorPosition === 0 && ! selectedText
|
||||||
|
@ -145,4 +147,17 @@ TextArea {
|
||||||
|
|
||||||
Behavior on opacity { HNumberAnimation {} }
|
Behavior on opacity { HNumberAnimation {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen
|
||||||
|
onTapped: contextMenu.spawn()
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedPointerTypes: PointerDevice.Finger | PointerDevice.Pen
|
||||||
|
onLongPressed: contextMenu.spawn()
|
||||||
|
}
|
||||||
|
|
||||||
|
HTextContextMenu { id: contextMenu }
|
||||||
}
|
}
|
||||||
|
|
73
src/gui/Base/HTextContextMenu.qml
Normal file
73
src/gui/Base/HTextContextMenu.qml
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
|
||||||
|
HMenu {
|
||||||
|
property Item control: parent // HTextField or HTextArea
|
||||||
|
|
||||||
|
property bool hadPersistentSelection: false // TODO: use a Qt 5.15 Binding
|
||||||
|
|
||||||
|
|
||||||
|
function spawn(atMousePosition=true) {
|
||||||
|
hadPersistentSelection = control.persistentSelection
|
||||||
|
control.persistentSelection = true
|
||||||
|
|
||||||
|
atMousePosition ?
|
||||||
|
popup() :
|
||||||
|
popup(
|
||||||
|
control.cursorRectangle.right,
|
||||||
|
control.cursorRectangle.bottom + theme.spacing / 4,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onClosed: control.persistentSelection = hadPersistentSelection
|
||||||
|
Component.onDestruction:
|
||||||
|
control.persistentSelection = hadPersistentSelection
|
||||||
|
|
||||||
|
|
||||||
|
HMenuItem {
|
||||||
|
icon.name: "undo"
|
||||||
|
text: qsTr("Undo")
|
||||||
|
enabled: control.canUndo
|
||||||
|
onTriggered: control.undo()
|
||||||
|
}
|
||||||
|
|
||||||
|
HMenuItem {
|
||||||
|
icon.name: "redo"
|
||||||
|
text: qsTr("Redo")
|
||||||
|
enabled: control.canRedo
|
||||||
|
onTriggered: control.redo()
|
||||||
|
}
|
||||||
|
|
||||||
|
HMenuSeparator {}
|
||||||
|
|
||||||
|
HMenuItem {
|
||||||
|
icon.name: "cut-text"
|
||||||
|
text: qsTr("Cut")
|
||||||
|
enabled: control.selectedText
|
||||||
|
onTriggered: control.cut()
|
||||||
|
}
|
||||||
|
|
||||||
|
HMenuItem {
|
||||||
|
icon.name: "copy-text"
|
||||||
|
text: qsTr("Copy")
|
||||||
|
enabled: control.selectedText
|
||||||
|
onTriggered: control.copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
HMenuItem {
|
||||||
|
icon.name: "paste-text"
|
||||||
|
text: qsTr("Paste")
|
||||||
|
enabled: control.canPaste
|
||||||
|
onTriggered: control.paste()
|
||||||
|
}
|
||||||
|
|
||||||
|
HMenuSeparator {}
|
||||||
|
|
||||||
|
HMenuItem {
|
||||||
|
icon.name: "select-all-text"
|
||||||
|
text: qsTr("Select all")
|
||||||
|
onTriggered: control.selectAll()
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,8 @@ TextField {
|
||||||
event.modifiers & Qt.MetaModifier
|
event.modifiers & Qt.MetaModifier
|
||||||
) event.accepted = true
|
) event.accepted = true
|
||||||
|
|
||||||
|
Keys.onMenuPressed: contextMenu.spawn(false)
|
||||||
|
|
||||||
// Prevent leaking arrow presses to parent elements when the carret is at
|
// Prevent leaking arrow presses to parent elements when the carret is at
|
||||||
// the beginning or end of the text
|
// the beginning or end of the text
|
||||||
Keys.onLeftPressed: event.accepted = cursorPosition === 0 && ! selectedText
|
Keys.onLeftPressed: event.accepted = cursorPosition === 0 && ! selectedText
|
||||||
|
@ -143,4 +145,17 @@ TextField {
|
||||||
|
|
||||||
Behavior on opacity { HNumberAnimation {} }
|
Behavior on opacity { HNumberAnimation {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen
|
||||||
|
onTapped: contextMenu.spawn()
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedPointerTypes: PointerDevice.Finger | PointerDevice.Pen
|
||||||
|
onLongPressed: contextMenu.spawn()
|
||||||
|
}
|
||||||
|
|
||||||
|
HTextContextMenu { id: contextMenu }
|
||||||
}
|
}
|
||||||
|
|
3
src/icons/thin/cut-text.svg
Normal file
3
src/icons/thin/cut-text.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m12.026 14.116c-3.475 1.673-7.504 3.619-8.484 4.09-1.848.889-3.542-1.445-3.542-1.445l8.761-4.226zm7.93 6.884c-.686 0-1.393-.154-2.064-.479-1.943-.941-2.953-3.001-2.498-4.854.26-1.057-.296-1.201-1.145-1.612l-14.189-6.866s1.7-2.329 3.546-1.436c1.134.549 5.689 2.747 9.614 4.651l.985-.474c.85-.409 1.406-.552 1.149-1.609-.451-1.855.564-3.913 2.51-4.848.669-.321 1.373-.473 2.054-.473 2.311 0 4.045 1.696 4.045 3.801 0 1.582-.986 3.156-2.613 3.973-1.625.816-2.765.18-4.38.965l-.504.245.552.27c1.613.789 2.754.156 4.377.976 1.624.819 2.605 2.392 2.605 3.97 0 2.108-1.739 3.8-4.044 3.8zm-2.555-12.815c.489 1.022 1.876 1.378 3.092.793 1.217-.584 1.809-1.893 1.321-2.916-.489-1.022-1.876-1.379-3.093-.794s-1.808 1.894-1.32 2.917zm-3.643 3.625c0-.414-.335-.75-.75-.75-.414 0-.75.336-.75.75s.336.75.75.75.75-.336.75-.75zm6.777 3.213c-1.215-.588-2.604-.236-3.095.786s.098 2.332 1.313 2.919c1.215.588 2.603.235 3.094-.787.492-1.021-.097-2.33-1.312-2.918z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
3
src/icons/thin/paste-text.svg
Normal file
3
src/icons/thin/paste-text.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m16 10c3.469 0 2 4 2 4s4-1.594 4 2v6h-10v-12zm.827-2h-6.827v16h14v-8.842c0-2.392-4.011-7.158-7.173-7.158zm-8.827 12h-6v-16h4l2.102 2h3.898l2-2h4v2.145c.656.143 1.327.391 2 .754v-4.899h-3c-1.229 0-2.18-1.084-3-2h-8c-.82.916-1.771 2-3 2h-3v20h8zm2-18c.553 0 1 .448 1 1s-.447 1-1 1-1-.448-1-1 .447-1 1-1zm4 18h6v-1h-6zm0-2h6v-1h-6zm0-2h6v-1h-6z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 449 B |
3
src/icons/thin/redo.svg
Normal file
3
src/icons/thin/redo.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m6.974 22.957c-10.957-11.421 2.326-20.865 10.384-13.309l-2.464 2.352h9.106v-8.947l-2.232 2.229c-14.794-13.203-31.51 7.051-14.794 17.675z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 244 B |
3
src/icons/thin/select-all-text.svg
Normal file
3
src/icons/thin/select-all-text.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m11 23v-2h-4v2zm8-20h3v2h2v-4h-5zm-19 14h2v-4h-2zm0-6h2v-4h-2zm2-6v-2h3v-2h-5v4zm22 2h-2v4h2zm0 6h-2v4h2zm-2 6v2h-3v2h5v-4zm-17 2h-3v-2h-2v4h5zm12 2v-2h-4v2zm-6-20v-2h-4v2zm6 0v-2h-4v2z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 293 B |
3
src/icons/thin/undo.svg
Normal file
3
src/icons/thin/undo.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m17.026 22.957c10.957-11.421-2.326-20.865-10.384-13.309l2.464 2.352h-9.106v-8.947l2.232 2.229c14.794-13.203 31.51 7.051 14.794 17.675z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 242 B |
Loading…
Reference in New Issue
Block a user