HShortcutHandler & HShortcut components
Provide more powerful shortcuts handling than what's available with QML's Shortcut component, notably being able to react differently to key presses, releases and auto-repeats.
This commit is contained in:
parent
3749d1e135
commit
8de26c11a1
|
@ -115,7 +115,7 @@ class UISettings(JSONConfigFile):
|
||||||
"theme": "Default.qpl",
|
"theme": "Default.qpl",
|
||||||
"writeAliases": {},
|
"writeAliases": {},
|
||||||
"keys": {
|
"keys": {
|
||||||
"reloadConfig": ["Alt+Shift+R"],
|
"reloadConfig": "Alt+Shift+R",
|
||||||
"scrollUp": ["Alt+Up", "Alt+K"],
|
"scrollUp": ["Alt+Up", "Alt+K"],
|
||||||
"scrollDown": ["Alt+Down", "Alt+J"],
|
"scrollDown": ["Alt+Down", "Alt+J"],
|
||||||
"focusSidePane": ["Alt+S", "Ctrl+S"],
|
"focusSidePane": ["Alt+S", "Ctrl+S"],
|
||||||
|
|
|
@ -26,5 +26,7 @@ ScrollView {
|
||||||
id: textAreaBackground
|
id: textAreaBackground
|
||||||
color: theme.controls.textArea.background
|
color: theme.controls.textArea.background
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keys.forwardTo: mainUI.shortcuts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/qml/Base/HShortcut.qml
Normal file
10
src/qml/Base/HShortcut.qml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import QtQuick 2.12
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
signal pressed(var event)
|
||||||
|
signal held(var event)
|
||||||
|
signal released(var event)
|
||||||
|
|
||||||
|
property bool enabled: true
|
||||||
|
property var sequences: "" // string or array of strings
|
||||||
|
}
|
56
src/qml/Base/HShortcutHandler.qml
Normal file
56
src/qml/Base/HShortcutHandler.qml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import QtQuick 2.12
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: shortcutHandler
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
let shortcut = match(event)
|
||||||
|
if (! shortcut) return
|
||||||
|
event.isAutoRepeat ? shortcut.held(event) : shortcut.pressed(event)
|
||||||
|
}
|
||||||
|
Keys.onReleased: {
|
||||||
|
let shortcut = match(event)
|
||||||
|
if (shortcut && ! event.isAutoRepeat) shortcut.released(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
readonly property var modifierDict: ({
|
||||||
|
Ctrl: Qt.ControlModifier,
|
||||||
|
Shift: Qt.ShiftModifier,
|
||||||
|
Alt: Qt.AltModifier,
|
||||||
|
Meta: Qt.MetaModifier,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function sequenceMatches(event, sequence) {
|
||||||
|
let [key, ...mods] = sequence.split("+").reverse()
|
||||||
|
|
||||||
|
key = key.charAt(0).toUpperCase() + key.slice(1)
|
||||||
|
|
||||||
|
if (event.key !== Qt["Key_" + key]) return false
|
||||||
|
|
||||||
|
for (let [name, code] of Object.entries(modifierDict)) {
|
||||||
|
if (mods.includes(name) && ! (event.modifiers & code)) return false
|
||||||
|
if (! mods.includes(name) && event.modifiers & code) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function match(event) {
|
||||||
|
for (let i = 0; i < shortcutHandler.resources.length; i++) {
|
||||||
|
let shortcut = shortcutHandler.resources[i]
|
||||||
|
|
||||||
|
if (! shortcut.enabled) continue
|
||||||
|
|
||||||
|
if (typeof(shortcut.sequences) == "string" &&
|
||||||
|
sequenceMatches(event, shortcut.sequences)) return shortcut
|
||||||
|
|
||||||
|
for (let i = 0; i < shortcut.sequences.length; i++) {
|
||||||
|
if (sequenceMatches(event, shortcut.sequences[i]))
|
||||||
|
return shortcut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,4 +28,5 @@ TextField {
|
||||||
}
|
}
|
||||||
|
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
Keys.forwardTo: mainUI.shortcuts
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +1,54 @@
|
||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
|
import "Base"
|
||||||
|
import "utils.js" as Utils
|
||||||
|
|
||||||
Item {
|
HShortcutHandler {
|
||||||
property Item flickTarget: Item {}
|
property Item flickTarget: Item {}
|
||||||
|
|
||||||
|
|
||||||
function smartVerticalFlick(baseVelocity, fastMultiply=3) {
|
HShortcut {
|
||||||
if (! flickTarget.interactive) { return }
|
enabled: debugMode
|
||||||
|
sequences: settings.keys.startDebugger
|
||||||
baseVelocity = -baseVelocity
|
onPressed: py.call("APP.pdb")
|
||||||
let vel = -flickTarget.verticalVelocity
|
|
||||||
let fast = (baseVelocity < 0 && vel < baseVelocity / 2) ||
|
|
||||||
(baseVelocity > 0 && vel > baseVelocity / 2)
|
|
||||||
|
|
||||||
flickTarget.flick(0, baseVelocity * (fast ? fastMultiply : 1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HShortcut {
|
||||||
Shortcut {
|
sequences: settings.keys.reloadConfig
|
||||||
sequences: settings.keys ? settings.keys.startDebugger : []
|
onPressed: py.loadSettings(() => { mainUI.pressAnimation.start() })
|
||||||
onActivated: if (debugMode) { py.call("APP.pdb") }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
HShortcut {
|
||||||
sequences: settings.keys ? settings.keys.reloadConfig : []
|
sequences: settings.keys.scrollUp
|
||||||
onActivated: py.loadSettings(() => { mainUI.pressAnimation.start() })
|
onPressed: Utils.smartVerticalFlick(flickTarget, -335)
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
HShortcut {
|
||||||
sequences: settings.keys ? settings.keys.scrollUp : []
|
sequences: settings.keys.scrollDown
|
||||||
onActivated: smartVerticalFlick(-335)
|
onPressed: Utils.smartVerticalFlick(flickTarget, 335)
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
HShortcut {
|
||||||
sequences: settings.keys ? settings.keys.scrollDown : []
|
sequences: settings.keys.focusSidePane
|
||||||
onActivated: smartVerticalFlick(335)
|
onPressed: mainUI.sidePane.setFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
HShortcut {
|
||||||
sequences: settings.keys ? settings.keys.focusSidePane : []
|
sequences: settings.keys.clearRoomFilter
|
||||||
onActivated: mainUI.sidePane.setFocus()
|
onPressed: mainUI.sidePane.paneToolBar.roomFilter = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
HShortcut {
|
||||||
sequences: settings.keys ? settings.keys.clearRoomFilter : []
|
sequences: settings.keys.goToPreviousRoom
|
||||||
onActivated: mainUI.sidePane.paneToolBar.roomFilter = ""
|
onPressed: mainUI.sidePane.accountRoomList.previous()
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
HShortcut {
|
||||||
sequences: settings.keys ? settings.keys.goToPreviousRoom : []
|
sequences: settings.keys.goToNextRoom
|
||||||
onActivated: mainUI.sidePane.accountRoomList.previous()
|
onPressed: mainUI.sidePane.accountRoomList.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
HShortcut {
|
||||||
sequences: settings.keys ? settings.keys.goToNextRoom : []
|
sequences: settings.keys.toggleCollapseAccount
|
||||||
onActivated: mainUI.sidePane.accountRoomList.next()
|
onPressed: mainUI.sidePane.accountRoomList.toggleCollapseAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequences: settings.keys ? settings.keys.toggleCollapseAccount : []
|
|
||||||
onActivated: mainUI.sidePane.accountRoomList.toggleCollapseAccount()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Shortcut {
|
|
||||||
sequence: "Ctrl+-"
|
|
||||||
onActivated: theme.fontScale = Math.max(0.1, theme.fontScale - 0.1)
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: "Ctrl++"
|
|
||||||
onActivated: theme.fontScale = Math.min(10, theme.fontScale + 0.1)
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: "Ctrl+="
|
|
||||||
onActivated: theme.fontScale = 1.0
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ HRectangle {
|
||||||
color: theme.ui.background
|
color: theme.ui.background
|
||||||
Component.onCompleted: window.mainUI = mainUI
|
Component.onCompleted: window.mainUI = mainUI
|
||||||
|
|
||||||
|
property alias shortcuts: shortcuts
|
||||||
property alias sidePane: sidePane
|
property alias sidePane: sidePane
|
||||||
property alias pageLoader: pageLoader
|
property alias pageLoader: pageLoader
|
||||||
property alias pressAnimation: _pressAnimation
|
property alias pressAnimation: _pressAnimation
|
||||||
|
@ -28,6 +29,9 @@ HRectangle {
|
||||||
(modelSources["Account"] || []).length > 0 ||
|
(modelSources["Account"] || []).length > 0 ||
|
||||||
py.startupAnyAccountsSaved
|
py.startupAnyAccountsSaved
|
||||||
|
|
||||||
|
|
||||||
|
Shortcuts { id: shortcuts }
|
||||||
|
|
||||||
HImage {
|
HImage {
|
||||||
id: mainUIBackground
|
id: mainUIBackground
|
||||||
visible: Boolean(Qt.resolvedUrl(source))
|
visible: Boolean(Qt.resolvedUrl(source))
|
||||||
|
|
|
@ -27,8 +27,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
property var theme: null
|
property var theme: null
|
||||||
|
|
||||||
Shortcuts { id: shortcuts}
|
Python { id: py }
|
||||||
Python { id: py }
|
|
||||||
|
|
||||||
HLoader {
|
HLoader {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
@ -162,3 +162,15 @@ function getItem(array, mainKey, value) {
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function smartVerticalFlick(flickTarget, baseVelocity, fastMultiply=3) {
|
||||||
|
if (! flickTarget.interactive) { return }
|
||||||
|
|
||||||
|
baseVelocity = -baseVelocity
|
||||||
|
let vel = -flickTarget.verticalVelocity
|
||||||
|
let fast = (baseVelocity < 0 && vel < baseVelocity / 2) ||
|
||||||
|
(baseVelocity > 0 && vel > baseVelocity / 2)
|
||||||
|
|
||||||
|
flickTarget.flick(0, baseVelocity * (fast ? fastMultiply : 1))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user