// SPDX-FileCopyrightText: 2023 James Graham // SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-GPL import QtQuick import QtQuick.Controls as QQC2 import QtQuick.Layouts import org.kde.kirigami as Kirigami Item { id: root /** * @brief The source for the image to be viewed. */ required property string source /** * @brief The size of the source image. * * This is used to calculate the maximum size of the content and temporary image. */ required property real sourceWidth /** * @brief The size of the source image. * * This is used to calculate the maximum size of the content and temporary image. */ required property real sourceHeight /** * @brief Source for the temporary content. * * Typically used when downloading the image to show a thumbnail or other * temporary image while the main image downloads. */ required property string tempSource /** * @brief The caption for the item. * * Typically set to the filename if no caption is available. * * @note Declared here so that parent components can access this parameter * when used as a listView delegate. */ required property string caption /** * @brief The delegate type for this item. * * @note Declared here so that parent components can access this parameter * when used as a listView delegate. */ readonly property int type: AlbumModelItem.Image /** * @brief The padding around the content image. * * The padding is factored in when calculating the maximum size of the content * image. */ property var padding: Kirigami.Units.largeSpacing /** * @brief Multiple by which the image is scaled. */ property var scaleFactor: 1 /** * @brief The angle by which the content image is rotated. * * The default orientation of the image is 0 degrees. */ property int rotationAngle: 0 /** * @brief Emitted when the background space around the content item is clicked. */ signal backgroundClicked() /** * @brief Emitted when the content image is right clicked. */ signal itemRightClicked() /** * @brief Start media playback. */ function play() { image.paused = false } /** * @brief Pause media playback. */ function pause() { image.paused = true } clip: true // AnimatedImage so we can handle GIFs. AnimatedImage { id: image property var rotationInsensitiveWidth: { if (sourceWidth > 0) { return Math.min(root.sourceWidth, root.width - root.padding * 2); } else { return Math.min(sourceSize.width, root.width - root.padding * 2); } } property var rotationInsensitiveHeight: { if (sourceHeight > 0) { return Math.min(root.sourceHeight, root.height - root.padding * 2) } else { return Math.min(sourceSize.height, root.height - root.padding * 2) } } anchors.centerIn: parent source: root.source width: root.rotationAngle % 180 === 0 ? rotationInsensitiveWidth : rotationInsensitiveHeight height: root.rotationAngle % 180 === 0 ? rotationInsensitiveHeight : rotationInsensitiveWidth fillMode: Image.PreserveAspectFit clip: true Behavior on width { NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic} } Behavior on height { NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic} } Image { id: tempImage anchors.centerIn: parent visible: source && status === Image.Ready && image.status !== Image.Ready width: root.sourceWidth > 0 || image.sourceSize.width > 0 ? root.sourceWidth : tempImage.sourceSize.width height: root.sourceHeight > 0 || image.sourceSize.height > 0 ? root.sourceHeight : tempImage.sourceSize.height source: root.tempSource } transform: [ Rotation { origin.x: image.width / 2 origin.y: image.height / 2 angle: root.rotationAngle Behavior on angle { RotationAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic} } }, Scale { origin.x: image.width / 2 origin.y: image.height / 2 xScale: root.scaleFactor yScale: root.scaleFactor Behavior on xScale { NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic} } Behavior on yScale { NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic} } } ] MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: root.itemRightClicked() } } QQC2.BusyIndicator { anchors.centerIn: parent visible: image.status !== Image.Ready && tempImage.status !== Image.Ready running: visible } MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton onClicked: root.backgroundClicked() } }