Add image viewer keybinds

This commit is contained in:
miruka 2020-07-20 21:34:00 -04:00
parent 0cd2678797
commit acd02a67a0
6 changed files with 163 additions and 13 deletions

View File

@ -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

View File

@ -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"],
},
},
}

View 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))
)
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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
}