Add image viewer keybinds
This commit is contained in:
parent
0cd2678797
commit
acd02a67a0
3
TODO.md
3
TODO.md
|
@ -1,7 +1,8 @@
|
|||
# TODO
|
||||
|
||||
- Image viewer:
|
||||
- open externally in context menu in timeline thumbnail
|
||||
- fix width
|
||||
- open externally in context menu in timeline thumbnail, also button
|
||||
- hflickable support kinetic scrolling disabler and speed/decel settings
|
||||
- keyboard controls
|
||||
|
||||
|
|
|
@ -378,6 +378,30 @@ class UISettings(JSONDataFile):
|
|||
|
||||
"refreshDevices": ["Alt+R", "F5"],
|
||||
"signOutCheckedOrAllDevices": ["Alt+S", "Delete"],
|
||||
|
||||
"imageViewer": {
|
||||
"panLeft": ["H", "Left", "Alt+H", "Alt+Left"],
|
||||
"panDown": ["J", "Down", "Alt+J", "Alt+Down"],
|
||||
"panUp": ["K", "Up", "Alt+K", "Alt+Up"],
|
||||
"panRight": ["L", "Right", "Alt+L", "Alt+Right"],
|
||||
|
||||
"zoomOut": ["Z", "-", "Ctrl+-"],
|
||||
"zoomIn": ["Shift+Z", "+", "Ctrl++"],
|
||||
"zoomReset": ["Alt+Z", "=", "Ctrl+="],
|
||||
|
||||
"rotateLeft": ["R"],
|
||||
"rotateRight": ["Shift+R"],
|
||||
"rotateReset": ["Alt+R"],
|
||||
|
||||
"previousSpeed": ["S"],
|
||||
"nextSpeed": ["Shift+S"],
|
||||
"resetSpeed": ["Alt+S"],
|
||||
|
||||
"pause": ["Space"],
|
||||
"expand": ["E"],
|
||||
"fullScreen": ["F", "F11", "Alt+Return", "Alt+Enter"],
|
||||
"close": ["X", "Q"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
18
src/gui/Popups/HPopupShortcut.qml
Normal file
18
src/gui/Popups/HPopupShortcut.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import "../Base"
|
||||
|
||||
HShortcut {
|
||||
enabled: active
|
||||
|
||||
onSequencesChanged: check()
|
||||
onSequenceChanged: check()
|
||||
|
||||
function check() {
|
||||
if (sequences.includes("Escape") || sequence === "Escape")
|
||||
console.warn(
|
||||
qsTr("%1: assigning Escape to a popup action causes conflicts")
|
||||
.arg(sequence || JSON.stringify(sequences))
|
||||
)
|
||||
}
|
||||
}
|
|
@ -2,53 +2,97 @@
|
|||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Window 2.12
|
||||
import ".."
|
||||
import "../../Base"
|
||||
|
||||
HFlow {
|
||||
property HPopup viewer
|
||||
|
||||
readonly property real calculatedWidth:
|
||||
(closeButton.implicitWidth * visibleChildren.length) + theme.spacing
|
||||
(close.implicitWidth * visibleChildren.length) + theme.spacing
|
||||
|
||||
|
||||
HButton {
|
||||
id: playButton
|
||||
id: pause
|
||||
icon.name: viewer.imagesPaused ? "image-play" : "image-pause"
|
||||
toolTip.text: viewer.imagesPaused ? qsTr("Play") : qsTr("Pause")
|
||||
onClicked: viewer.imagesPaused = ! viewer.imagesPaused
|
||||
visible: viewer.isAnimated
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.pause
|
||||
onActivated: pause.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
HButton {
|
||||
text: qsTr("%1x").arg(utils.round(viewer.imagesSpeed))
|
||||
label.font.pixelSize: theme.fontSize.big
|
||||
height: playButton.height
|
||||
height: pause.height
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
toolTip.text: qsTr("Change speed")
|
||||
onClicked: speedMenu.popup()
|
||||
visible: viewer.isAnimated
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.previousSpeed
|
||||
onActivated: viewer.imagesSpeed = viewer.availableSpeeds[Math.min(
|
||||
viewer.availableSpeeds.indexOf(viewer.imagesSpeed) + 1,
|
||||
viewer.availableSpeeds.length - 1,
|
||||
)]
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.nextSpeed
|
||||
onActivated: viewer.imagesSpeed = viewer.availableSpeeds[Math.max(
|
||||
viewer.availableSpeeds.indexOf(viewer.imagesSpeed) - 1, 0,
|
||||
)]
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.resetSpeed
|
||||
onActivated: viewer.imagesSpeed = 1
|
||||
}
|
||||
}
|
||||
|
||||
HButton {
|
||||
id: rotateLeft
|
||||
icon.name: "image-rotate-left"
|
||||
toolTip.text: qsTr("Rotate left")
|
||||
autoRepeat: true
|
||||
autoRepeatDelay: 20
|
||||
autoRepeatInterval: theme.animationDuration * 3
|
||||
onPressed: viewer.animatedRotationTarget -= 45
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.rotateLeft
|
||||
onActivated: viewer.animatedRotationTarget -= 45
|
||||
}
|
||||
}
|
||||
|
||||
HButton {
|
||||
id: rotateRight
|
||||
icon.name: "image-rotate-right"
|
||||
toolTip.text: qsTr("Rotate right")
|
||||
autoRepeat: true
|
||||
autoRepeatDelay: 20
|
||||
autoRepeatInterval: theme.animationDuration * 3
|
||||
onPressed: viewer.animatedRotationTarget += 45
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.rotateRight
|
||||
onActivated: viewer.animatedRotationTarget += 45
|
||||
}
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.rotateReset
|
||||
onActivated: viewer.animatedRotationTarget = 0
|
||||
}
|
||||
|
||||
HButton {
|
||||
id: expand
|
||||
icon.name: "image-alt-scale-mode"
|
||||
toolTip.text:
|
||||
viewer.imageLargerThanWindow ?
|
||||
|
@ -57,21 +101,37 @@ HFlow {
|
|||
|
||||
checked: viewer.alternateScaling
|
||||
onClicked: viewer.alternateScaling = ! viewer.alternateScaling
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.expand
|
||||
onActivated: expand.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
HButton {
|
||||
id: fullScreen
|
||||
icon.name: "image-fullscreen"
|
||||
toolTip.text: qsTr("Fullscreen")
|
||||
checked: window.visibility === Window.FullScreen
|
||||
onClicked: viewer.toggleFullScreen()
|
||||
visible: Qt.application.supportsMultipleWindows
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.fullScreen
|
||||
onActivated: fullScreen.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
HButton {
|
||||
id: closeButton // always visible
|
||||
id: close // always visible
|
||||
icon.name: "image-close"
|
||||
toolTip.text: qsTr("Close")
|
||||
onClicked: viewer.close()
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.close
|
||||
onActivated: close.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
HMenu {
|
||||
|
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import ".."
|
||||
import "../.."
|
||||
import "../../Base"
|
||||
|
||||
HFlickable {
|
||||
id: flickable
|
||||
|
||||
property HPopup viewer
|
||||
|
||||
readonly property alias thumbnail: thumbnail
|
||||
|
@ -47,6 +51,41 @@ HFlickable {
|
|||
}
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.panLeft
|
||||
onActivated: utils.flickPages(flickable, -0.2, true, 5)
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.panRight
|
||||
onActivated: utils.flickPages(flickable, 0.2, true, 5)
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.panUp
|
||||
onActivated: utils.flickPages(flickable, -0.2, false, 5)
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.panDown
|
||||
onActivated: utils.flickPages(flickable, 0.2, false, 5)
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.zoomOut
|
||||
onActivated: thumbnail.scale = Math.max(0.1, thumbnail.scale - 0.2)
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.zoomIn
|
||||
onActivated: thumbnail.scale = Math.min(10, thumbnail.scale + 0.2)
|
||||
}
|
||||
|
||||
HPopupShortcut {
|
||||
sequences: window.settings.keys.imageViewer.zoomReset
|
||||
onActivated: resetScaleAnimation.start()
|
||||
}
|
||||
|
||||
HMxcImage {
|
||||
id: thumbnail
|
||||
anchors.centerIn: parent
|
||||
|
|
|
@ -415,29 +415,37 @@ QtObject {
|
|||
}
|
||||
|
||||
|
||||
function flickPages(flickable, pages) {
|
||||
function flickPages(flickable, pages, horizontal=false, multiplier=8) {
|
||||
// Adapt velocity and deceleration for the number of pages to flick.
|
||||
// If this is a repeated flicking, flick faster than a single flick.
|
||||
if (! flickable.interactive) return
|
||||
|
||||
const futureVelocity = -flickable.height * pages
|
||||
const currentVelocity = -flickable.verticalVelocity
|
||||
const futureVelocity =
|
||||
(horizontal ? -flickable.width : -flickable.height) * pages
|
||||
|
||||
const currentVelocity =
|
||||
horizontal ?
|
||||
-flickable.horizontalVelocity :
|
||||
-flickable.verticalVelocity
|
||||
|
||||
const goFaster =
|
||||
(futureVelocity < 0 && currentVelocity < futureVelocity / 2) ||
|
||||
(futureVelocity > 0 && currentVelocity > futureVelocity / 2)
|
||||
|
||||
const normalDecel = flickable.flickDeceleration
|
||||
const fastMultiply = pages && 8 / (1 - Math.log10(Math.abs(pages)))
|
||||
const magicNumber = 2.5
|
||||
const normalDecel = flickable.flickDeceleration
|
||||
const fastMultiply =
|
||||
pages && multiplier / (1 - Math.log10(Math.abs(pages)))
|
||||
|
||||
flickable.flickDeceleration = Math.max(
|
||||
goFaster ? normalDecel : -Infinity,
|
||||
Math.abs(normalDecel * magicNumber * pages),
|
||||
)
|
||||
|
||||
flickable.flick(
|
||||
0, futureVelocity * magicNumber * (goFaster ? fastMultiply : 1),
|
||||
)
|
||||
const flick =
|
||||
futureVelocity * magicNumber * (goFaster ? fastMultiply : 1)
|
||||
|
||||
horizontal ? flickable.flick(flick, 0) : flickable.flick(0, flick)
|
||||
|
||||
flickable.flickDeceleration = normalDecel
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user