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 # TODO
- Image viewer: - 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 - hflickable support kinetic scrolling disabler and speed/decel settings
- keyboard controls - keyboard controls

View File

@ -378,6 +378,30 @@ class UISettings(JSONDataFile):
"refreshDevices": ["Alt+R", "F5"], "refreshDevices": ["Alt+R", "F5"],
"signOutCheckedOrAllDevices": ["Alt+S", "Delete"], "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 2.12
import QtQuick.Window 2.12 import QtQuick.Window 2.12
import ".."
import "../../Base" import "../../Base"
HFlow { HFlow {
property HPopup viewer property HPopup viewer
readonly property real calculatedWidth: readonly property real calculatedWidth:
(closeButton.implicitWidth * visibleChildren.length) + theme.spacing (close.implicitWidth * visibleChildren.length) + theme.spacing
HButton { HButton {
id: playButton id: pause
icon.name: viewer.imagesPaused ? "image-play" : "image-pause" icon.name: viewer.imagesPaused ? "image-play" : "image-pause"
toolTip.text: viewer.imagesPaused ? qsTr("Play") : qsTr("Pause") toolTip.text: viewer.imagesPaused ? qsTr("Play") : qsTr("Pause")
onClicked: viewer.imagesPaused = ! viewer.imagesPaused onClicked: viewer.imagesPaused = ! viewer.imagesPaused
visible: viewer.isAnimated visible: viewer.isAnimated
HPopupShortcut {
sequences: window.settings.keys.imageViewer.pause
onActivated: pause.clicked()
}
} }
HButton { HButton {
text: qsTr("%1x").arg(utils.round(viewer.imagesSpeed)) text: qsTr("%1x").arg(utils.round(viewer.imagesSpeed))
label.font.pixelSize: theme.fontSize.big label.font.pixelSize: theme.fontSize.big
height: playButton.height height: pause.height
topPadding: 0 topPadding: 0
bottomPadding: 0 bottomPadding: 0
toolTip.text: qsTr("Change speed") toolTip.text: qsTr("Change speed")
onClicked: speedMenu.popup() onClicked: speedMenu.popup()
visible: viewer.isAnimated 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 { HButton {
id: rotateLeft
icon.name: "image-rotate-left" icon.name: "image-rotate-left"
toolTip.text: qsTr("Rotate left") toolTip.text: qsTr("Rotate left")
autoRepeat: true autoRepeat: true
autoRepeatDelay: 20 autoRepeatDelay: 20
autoRepeatInterval: theme.animationDuration * 3 autoRepeatInterval: theme.animationDuration * 3
onPressed: viewer.animatedRotationTarget -= 45 onPressed: viewer.animatedRotationTarget -= 45
HPopupShortcut {
sequences: window.settings.keys.imageViewer.rotateLeft
onActivated: viewer.animatedRotationTarget -= 45
}
} }
HButton { HButton {
id: rotateRight
icon.name: "image-rotate-right" icon.name: "image-rotate-right"
toolTip.text: qsTr("Rotate right") toolTip.text: qsTr("Rotate right")
autoRepeat: true autoRepeat: true
autoRepeatDelay: 20 autoRepeatDelay: 20
autoRepeatInterval: theme.animationDuration * 3 autoRepeatInterval: theme.animationDuration * 3
onPressed: viewer.animatedRotationTarget += 45 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 { HButton {
id: expand
icon.name: "image-alt-scale-mode" icon.name: "image-alt-scale-mode"
toolTip.text: toolTip.text:
viewer.imageLargerThanWindow ? viewer.imageLargerThanWindow ?
@ -57,21 +101,37 @@ HFlow {
checked: viewer.alternateScaling checked: viewer.alternateScaling
onClicked: viewer.alternateScaling = ! viewer.alternateScaling onClicked: viewer.alternateScaling = ! viewer.alternateScaling
HPopupShortcut {
sequences: window.settings.keys.imageViewer.expand
onActivated: expand.clicked()
}
} }
HButton { HButton {
id: fullScreen
icon.name: "image-fullscreen" icon.name: "image-fullscreen"
toolTip.text: qsTr("Fullscreen") toolTip.text: qsTr("Fullscreen")
checked: window.visibility === Window.FullScreen checked: window.visibility === Window.FullScreen
onClicked: viewer.toggleFullScreen() onClicked: viewer.toggleFullScreen()
visible: Qt.application.supportsMultipleWindows visible: Qt.application.supportsMultipleWindows
HPopupShortcut {
sequences: window.settings.keys.imageViewer.fullScreen
onActivated: fullScreen.clicked()
}
} }
HButton { HButton {
id: closeButton // always visible id: close // always visible
icon.name: "image-close" icon.name: "image-close"
toolTip.text: qsTr("Close") toolTip.text: qsTr("Close")
onClicked: viewer.close() onClicked: viewer.close()
HPopupShortcut {
sequences: window.settings.keys.imageViewer.close
onActivated: close.clicked()
}
} }
HMenu { HMenu {

View File

@ -2,9 +2,13 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import ".."
import "../.."
import "../../Base" import "../../Base"
HFlickable { HFlickable {
id: flickable
property HPopup viewer property HPopup viewer
readonly property alias thumbnail: thumbnail 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 { HMxcImage {
id: thumbnail id: thumbnail
anchors.centerIn: parent 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. // Adapt velocity and deceleration for the number of pages to flick.
// If this is a repeated flicking, flick faster than a single flick. // If this is a repeated flicking, flick faster than a single flick.
if (! flickable.interactive) return if (! flickable.interactive) return
const futureVelocity = -flickable.height * pages const futureVelocity =
const currentVelocity = -flickable.verticalVelocity (horizontal ? -flickable.width : -flickable.height) * pages
const currentVelocity =
horizontal ?
-flickable.horizontalVelocity :
-flickable.verticalVelocity
const goFaster = const goFaster =
(futureVelocity < 0 && currentVelocity < futureVelocity / 2) || (futureVelocity < 0 && currentVelocity < futureVelocity / 2) ||
(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 magicNumber = 2.5
const normalDecel = flickable.flickDeceleration
const fastMultiply =
pages && multiplier / (1 - Math.log10(Math.abs(pages)))
flickable.flickDeceleration = Math.max( flickable.flickDeceleration = Math.max(
goFaster ? normalDecel : -Infinity, goFaster ? normalDecel : -Infinity,
Math.abs(normalDecel * magicNumber * pages), Math.abs(normalDecel * magicNumber * pages),
) )
flickable.flick( const flick =
0, futureVelocity * magicNumber * (goFaster ? fastMultiply : 1), futureVelocity * magicNumber * (goFaster ? fastMultiply : 1)
)
horizontal ? flickable.flick(flick, 0) : flickable.flick(0, flick)
flickable.flickDeceleration = normalDecel flickable.flickDeceleration = normalDecel
} }