Split ImageViewer components
This commit is contained in:
parent
9444225afa
commit
66a44b5251
|
@ -366,7 +366,7 @@ Rectangle {
|
||||||
forLink || (isAnimated(event) ? "" : event.media_url)
|
forLink || (isAnimated(event) ? "" : event.media_url)
|
||||||
|
|
||||||
utils.makePopup(
|
utils.makePopup(
|
||||||
"Popups/ImageViewerPopup.qml",
|
"Popups/ImageViewerPopup/ImageViewerPopup.qml",
|
||||||
{
|
{
|
||||||
thumbnailTitle: getThumbnailTitle(event),
|
thumbnailTitle: getThumbnailTitle(event),
|
||||||
thumbnailMxc: event.thumbnail_url,
|
thumbnailMxc: event.thumbnail_url,
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
|
|
||||||
import QtQuick 2.12
|
|
||||||
import QtQuick.Controls 2.12
|
|
||||||
import QtQuick.Window 2.12
|
|
||||||
import "../Base"
|
|
||||||
|
|
||||||
HPopup {
|
|
||||||
id: popup
|
|
||||||
|
|
||||||
property alias thumbnailTitle: thumbnail.title
|
|
||||||
property alias thumbnailMxc: thumbnail.mxc
|
|
||||||
property alias thumbnailPath: thumbnail.cachedPath // optional
|
|
||||||
property alias thumbnailCryptDict: thumbnail.cryptDict
|
|
||||||
property alias fullTitle: full.title
|
|
||||||
property alias fullMxc: full.mxc
|
|
||||||
property alias fullCryptDict: full.cryptDict
|
|
||||||
property size overallSize
|
|
||||||
|
|
||||||
property bool alternateScaling: false
|
|
||||||
property bool activedFullScreen: false
|
|
||||||
|
|
||||||
readonly property bool imageLargerThanWindow:
|
|
||||||
overallSize.width > window.width || overallSize.height > window.height
|
|
||||||
|
|
||||||
readonly property bool imageEqualToWindow:
|
|
||||||
overallSize.width == window.width &&
|
|
||||||
overallSize.height == window.height
|
|
||||||
|
|
||||||
readonly property int paintedWidth:
|
|
||||||
full.status === Image.Ready ?
|
|
||||||
full.animatedPaintedWidth || full.paintedWidth :
|
|
||||||
thumbnail.animatedPaintedWidth || thumbnail.paintedWidth
|
|
||||||
|
|
||||||
readonly property int paintedHeight:
|
|
||||||
full.status === Image.Ready ?
|
|
||||||
full.animatedPaintedHeight || full.paintedHeight :
|
|
||||||
thumbnail.animatedPaintedHeight || thumbnail.paintedHeight
|
|
||||||
|
|
||||||
signal openExternallyRequested()
|
|
||||||
|
|
||||||
function showFullScreen() {
|
|
||||||
if (activedFullScreen) return
|
|
||||||
|
|
||||||
window.showFullScreen()
|
|
||||||
popup.activedFullScreen = true
|
|
||||||
if (! imageLargerThanWindow) popup.alternateScaling = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function exitFullScreen() {
|
|
||||||
if (! activedFullScreen) return
|
|
||||||
|
|
||||||
window.showNormal()
|
|
||||||
popup.activedFullScreen = false
|
|
||||||
if (! imageLargerThanWindow) popup.alternateScaling = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleFulLScreen() {
|
|
||||||
const isFull = window.visibility === Window.FullScreen
|
|
||||||
return isFull ? exitFullScreen() : showFullScreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
margins: 0
|
|
||||||
background: null
|
|
||||||
|
|
||||||
onAboutToHide: exitFullScreen()
|
|
||||||
|
|
||||||
HFlickable {
|
|
||||||
id: flickable
|
|
||||||
implicitWidth: window.width
|
|
||||||
implicitHeight: window.height
|
|
||||||
contentWidth:
|
|
||||||
Math.max(window.width, popup.paintedWidth * thumbnail.scale)
|
|
||||||
contentHeight:
|
|
||||||
Math.max(window.height, popup.paintedHeight * thumbnail.scale)
|
|
||||||
|
|
||||||
ScrollBar.vertical: null
|
|
||||||
|
|
||||||
TapHandler {
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
onTapped: popup.close()
|
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
onWheel: {
|
|
||||||
if (wheel.modifiers !== Qt.ControlModifier) {
|
|
||||||
wheel.accepted = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
wheel.accepted = true
|
|
||||||
const add = wheel.angleDelta.y / 120 / 5
|
|
||||||
thumbnail.scale = Math.max(
|
|
||||||
0.1, Math.min(10, thumbnail.scale + add),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HMxcImage {
|
|
||||||
id: thumbnail
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width:
|
|
||||||
popup.alternateScaling && popup.imageLargerThanWindow ?
|
|
||||||
popup.overallSize.width :
|
|
||||||
|
|
||||||
popup.alternateScaling ?
|
|
||||||
window.width :
|
|
||||||
|
|
||||||
Math.min(window.width, popup.overallSize.width)
|
|
||||||
|
|
||||||
height:
|
|
||||||
popup.alternateScaling && popup.imageLargerThanWindow ?
|
|
||||||
popup.overallSize.height :
|
|
||||||
|
|
||||||
popup.alternateScaling ?
|
|
||||||
window.height :
|
|
||||||
|
|
||||||
Math.min(window.height, popup.overallSize.height)
|
|
||||||
|
|
||||||
fillMode: HMxcImage.PreserveAspectFit
|
|
||||||
// Use only cachedPath if set, don't waste time refetching thumb
|
|
||||||
canUpdate: ! cachedPath
|
|
||||||
|
|
||||||
Behavior on width {
|
|
||||||
HNumberAnimation { overshoot: popup.alternateScaling? 2 : 3 }
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on height {
|
|
||||||
HNumberAnimation { overshoot: popup.alternateScaling? 2 : 3 }
|
|
||||||
}
|
|
||||||
|
|
||||||
Binding on showProgressBar {
|
|
||||||
value: false
|
|
||||||
when: ! thumbnail.show
|
|
||||||
}
|
|
||||||
|
|
||||||
HNumberAnimation {
|
|
||||||
id: resetScaleAnimation
|
|
||||||
target: thumbnail
|
|
||||||
property: "scale"
|
|
||||||
from: thumbnail.scale
|
|
||||||
to: 1
|
|
||||||
overshoot: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
// Timer to not disappear before full image is done rendering
|
|
||||||
interval: 1000
|
|
||||||
running: full.status === HMxcImage.Ready
|
|
||||||
onTriggered: thumbnail.show = false
|
|
||||||
}
|
|
||||||
|
|
||||||
HMxcImage {
|
|
||||||
id: full
|
|
||||||
anchors.fill: parent
|
|
||||||
thumbnail: false
|
|
||||||
fillMode: parent.fillMode
|
|
||||||
// Image never loads at 0 opacity or with visible: false
|
|
||||||
opacity: status === HMxcImage.Ready ? 1 : 0.01
|
|
||||||
|
|
||||||
Behavior on opacity { HNumberAnimation {} }
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: popup.paintedWidth
|
|
||||||
height: popup.paintedHeight
|
|
||||||
|
|
||||||
TapHandler {
|
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
|
||||||
onTapped: {
|
|
||||||
thumbnail.scale === 1 ?
|
|
||||||
popup.alternateScaling = ! popup.alternateScaling :
|
|
||||||
resetScaleAnimation.start()
|
|
||||||
}
|
|
||||||
onDoubleTapped: popup.toggleFulLScreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
TapHandler {
|
|
||||||
acceptedButtons: Qt.MiddleButton
|
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
|
||||||
onTapped: popup.openExternallyRequested()
|
|
||||||
}
|
|
||||||
|
|
||||||
TapHandler {
|
|
||||||
acceptedButtons: Qt.RightButton
|
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
|
||||||
onTapped: popup.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
81
src/gui/Popups/ImageViewerPopup/ImageViewerPopup.qml
Normal file
81
src/gui/Popups/ImageViewerPopup/ImageViewerPopup.qml
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import QtQuick.Window 2.12
|
||||||
|
import "../../Base"
|
||||||
|
|
||||||
|
HPopup {
|
||||||
|
id: popup
|
||||||
|
|
||||||
|
property string thumbnailTitle
|
||||||
|
property string thumbnailMxc
|
||||||
|
property string thumbnailPath: ""
|
||||||
|
property var thumbnailCryptDict
|
||||||
|
property string fullTitle
|
||||||
|
property string fullMxc
|
||||||
|
property var fullCryptDict
|
||||||
|
property size overallSize
|
||||||
|
|
||||||
|
property bool alternateScaling: false
|
||||||
|
property bool activedFullScreen: false
|
||||||
|
|
||||||
|
readonly property alias canvas: canvas
|
||||||
|
|
||||||
|
readonly property bool imageLargerThanWindow:
|
||||||
|
overallSize.width > window.width || overallSize.height > window.height
|
||||||
|
|
||||||
|
readonly property bool imageEqualToWindow:
|
||||||
|
overallSize.width == window.width &&
|
||||||
|
overallSize.height == window.height
|
||||||
|
|
||||||
|
readonly property int paintedWidth:
|
||||||
|
canvas.full.status === Image.Ready ?
|
||||||
|
canvas.full.animatedPaintedWidth || canvas.full.paintedWidth :
|
||||||
|
canvas.thumbnail.animatedPaintedWidth || canvas.thumbnail.paintedWidth
|
||||||
|
|
||||||
|
readonly property int paintedHeight:
|
||||||
|
canvas.full.status === Image.Ready ?
|
||||||
|
canvas.full.animatedPaintedHeight || canvas.full.paintedHeight :
|
||||||
|
canvas.thumbnail.animatedPaintedHeight || canvas.thumbnail.paintedHeight
|
||||||
|
|
||||||
|
signal openExternallyRequested()
|
||||||
|
|
||||||
|
function showFullScreen() {
|
||||||
|
if (activedFullScreen) return
|
||||||
|
|
||||||
|
window.showFullScreen()
|
||||||
|
popup.activedFullScreen = true
|
||||||
|
if (! imageLargerThanWindow) popup.alternateScaling = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitFullScreen() {
|
||||||
|
if (! activedFullScreen) return
|
||||||
|
|
||||||
|
window.showNormal()
|
||||||
|
popup.activedFullScreen = false
|
||||||
|
if (! imageLargerThanWindow) popup.alternateScaling = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFulLScreen() {
|
||||||
|
const isFull = window.visibility === Window.FullScreen
|
||||||
|
return isFull ? exitFullScreen() : showFullScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
margins: 0
|
||||||
|
background: null
|
||||||
|
|
||||||
|
onAboutToHide: exitFullScreen()
|
||||||
|
|
||||||
|
Item {
|
||||||
|
implicitWidth: window.width
|
||||||
|
implicitHeight: window.height
|
||||||
|
|
||||||
|
ViewerCanvas {
|
||||||
|
id: canvas
|
||||||
|
anchors.fill: parent
|
||||||
|
viewer: popup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
src/gui/Popups/ImageViewerPopup/ViewerCanvas.qml
Normal file
144
src/gui/Popups/ImageViewerPopup/ViewerCanvas.qml
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import "../../Base"
|
||||||
|
|
||||||
|
HFlickable {
|
||||||
|
property HPopup viewer
|
||||||
|
|
||||||
|
readonly property alias thumbnail: thumbnail
|
||||||
|
readonly property alias full: full
|
||||||
|
|
||||||
|
|
||||||
|
contentWidth:
|
||||||
|
Math.max(window.width, viewer.paintedWidth * thumbnail.scale)
|
||||||
|
contentHeight:
|
||||||
|
Math.max(window.height, viewer.paintedHeight * thumbnail.scale)
|
||||||
|
|
||||||
|
ScrollBar.vertical: null
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onTapped: viewer.close()
|
||||||
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
onWheel: {
|
||||||
|
if (wheel.modifiers !== Qt.ControlModifier) {
|
||||||
|
wheel.accepted = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wheel.accepted = true
|
||||||
|
const add = wheel.angleDelta.y / 120 / 5
|
||||||
|
thumbnail.scale = Math.max(
|
||||||
|
0.1, Math.min(10, thumbnail.scale + add),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HMxcImage {
|
||||||
|
id: thumbnail
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width:
|
||||||
|
viewer.alternateScaling && viewer.imageLargerThanWindow ?
|
||||||
|
viewer.overallSize.width :
|
||||||
|
|
||||||
|
viewer.alternateScaling ?
|
||||||
|
window.width :
|
||||||
|
|
||||||
|
Math.min(window.width, viewer.overallSize.width)
|
||||||
|
|
||||||
|
height:
|
||||||
|
viewer.alternateScaling && viewer.imageLargerThanWindow ?
|
||||||
|
viewer.overallSize.height :
|
||||||
|
|
||||||
|
viewer.alternateScaling ?
|
||||||
|
window.height :
|
||||||
|
|
||||||
|
Math.min(window.height, viewer.overallSize.height)
|
||||||
|
|
||||||
|
fillMode: HMxcImage.PreserveAspectFit
|
||||||
|
title: viewer.thumbnailTitle
|
||||||
|
mxc: viewer.thumbnailMxc
|
||||||
|
cachedPath: viewer.thumbnailPath
|
||||||
|
cryptDict: viewer.thumbnailCryptDict
|
||||||
|
// Use only cachedPath if set, don't waste time refetching thumb
|
||||||
|
canUpdate: ! cachedPath
|
||||||
|
|
||||||
|
Behavior on width {
|
||||||
|
HNumberAnimation { overshoot: viewer.alternateScaling? 2 : 3 }
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
HNumberAnimation { overshoot: viewer.alternateScaling? 2 : 3 }
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding on showProgressBar {
|
||||||
|
value: false
|
||||||
|
when: ! thumbnail.show
|
||||||
|
}
|
||||||
|
|
||||||
|
HNumberAnimation {
|
||||||
|
id: resetScaleAnimation
|
||||||
|
target: thumbnail
|
||||||
|
property: "scale"
|
||||||
|
from: thumbnail.scale
|
||||||
|
to: 1
|
||||||
|
overshoot: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
// Timer to not disappear before full image is done rendering
|
||||||
|
interval: 1000
|
||||||
|
running: full.status === HMxcImage.Ready
|
||||||
|
onTriggered: thumbnail.show = false
|
||||||
|
}
|
||||||
|
|
||||||
|
HMxcImage {
|
||||||
|
id: full
|
||||||
|
anchors.fill: parent
|
||||||
|
thumbnail: false
|
||||||
|
fillMode: parent.fillMode
|
||||||
|
title: viewer.fullTitle
|
||||||
|
mxc: viewer.fullMxc
|
||||||
|
cryptDict: viewer.fullCryptDict
|
||||||
|
// Image never loads at 0 opacity or with visible: false
|
||||||
|
opacity: status === HMxcImage.Ready ? 1 : 0.01
|
||||||
|
|
||||||
|
Behavior on opacity { HNumberAnimation {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: viewer.paintedWidth
|
||||||
|
height: viewer.paintedHeight
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
|
onTapped: {
|
||||||
|
thumbnail.scale === 1 ?
|
||||||
|
viewer.alternateScaling = ! viewer.alternateScaling :
|
||||||
|
resetScaleAnimation.start()
|
||||||
|
}
|
||||||
|
onDoubleTapped: viewer.toggleFulLScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.MiddleButton
|
||||||
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
|
onTapped: viewer.openExternallyRequested()
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
|
onTapped: viewer.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user