Warning, /graphics/koko/src/qml/EditorView.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 * SPDX-FileCopyrightText: 2017 Atul Sharma <atulsharma406@gmail.com>
0003 * SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu>
0004 *
0005 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007
0008 import QtQuick 2.15
0009 import QtQml 2.15
0010 import QtQuick.Templates 2.15 as T
0011 import QtQuick.Controls 2.15 as QQC2
0012 import QtQuick.Layouts 1.15
0013 import QtQuick.Dialogs 1.3
0014 import org.kde.kirigami 2.15 as Kirigami
0015 import org.kde.kquickimageeditor 1.0 as KQuickImageEditor
0016 import "./Dialog"
0017
0018 Kirigami.Page {
0019 id: root
0020
0021 property bool cropping: false
0022 property bool resizing: false
0023 property string imagePath
0024 property bool forceDiscard: false
0025
0026 signal imageEdited()
0027
0028 title: i18n("Edit")
0029
0030 leftPadding: 0
0031 rightPadding: 0
0032 topPadding: 0
0033 bottomPadding: 0
0034
0035 onBackRequested: (event) => {
0036 if (imageDoc.edited && !root.forceDiscard) {
0037 confirmDiscardingChangeDialog.visible = true;
0038 event.accepted = true;
0039 }
0040 }
0041
0042 function crop() {
0043 root.cropping = false
0044 imageDoc.crop(selectionTool.selectionX / editImage.ratioX,
0045 selectionTool.selectionY / editImage.ratioY,
0046 selectionTool.selectionWidth / editImage.ratioX,
0047 selectionTool.selectionHeight / editImage.ratioY);
0048 }
0049
0050 function resize() {
0051 const ratioX = editImage.paintedWidth / editImage.nativeWidth;
0052 const ratioY = editImage.paintedHeight / editImage.nativeHeight;
0053 root.resizing = false
0054 imageDoc.resize(selectionTool.selectionWidth / ratioX, selectionTool.selectionHeight / ratioY);
0055 }
0056
0057 actions {
0058 main: Kirigami.Action {
0059 id: saveAction
0060 visible: imageDoc.edited
0061 text: i18nc("@action:button Save image modification", "Save")
0062 icon.name: "document-save"
0063 onTriggered: {
0064 if (!imageDoc.save()) {
0065 msg.type = Kirigami.MessageType.Error
0066 msg.text = i18n("Unable to save file. Check if you have the correct permission to edit this file.")
0067 msg.visible = true;
0068 }
0069 root.imageEdited();
0070 applicationWindow().pageStack.layers.pop();
0071 }
0072 }
0073 left: Kirigami.Action {
0074 id: undoAction
0075 text: i18nc("@action:button Undo modification", "Undo")
0076 icon.name: "edit-undo"
0077 onTriggered: {
0078 if (imageDoc.edited) {
0079 imageDoc.undo();
0080 }
0081 }
0082 visible: imageDoc.edited
0083 }
0084 contextualActions: [
0085 Kirigami.Action {
0086 icon.name: root.cropping ? "dialog-cancel" : "transform-crop"
0087 text: root.cropping ? i18nc("@action:button", "Cancel") : i18nc("@action:button Crop an image", "Crop");
0088 onTriggered: root.cropping = !root.cropping;
0089 visible: !root.resizing
0090 },
0091 Kirigami.Action {
0092 icon.name: "dialog-ok"
0093 text: i18nc("@action:button Crop an image", "Crop");
0094 onTriggered: root.crop();
0095 visible: root.cropping
0096 },
0097 Kirigami.Action {
0098 icon.name: root.resizing ? "dialog-cancel" : "transform-scale"
0099 text: root.resizing ? i18nc("@action:button", "Cancel") : i18nc("@action:button Resize an image", "Resize");
0100 onTriggered: root.resizing = !root.resizing;
0101 visible: !root.cropping
0102 },
0103 Kirigami.Action {
0104 icon.name: "dialog-ok"
0105 text: i18nc("@action:button Resize an image", "Resize");
0106 onTriggered: root.resize();
0107 visible: root.resizing
0108 },
0109 Kirigami.Action {
0110 icon.name: "object-rotate-left"
0111 text: i18nc("@action:button Rotate an image to the left", "Rotate left");
0112 onTriggered: imageDoc.rotate(-90);
0113 visible: !root.cropping && !root.resizing
0114 },
0115 Kirigami.Action {
0116 icon.name: "object-rotate-right"
0117 text: i18nc("@action:button Rotate an image to the right", "Rotate right");
0118 onTriggered: imageDoc.rotate(90);
0119 visible: !root.cropping && !root.resizing
0120 },
0121 Kirigami.Action {
0122 icon.name: "object-flip-vertical"
0123 text: i18nc("@action:button Mirror an image vertically", "Flip");
0124 onTriggered: imageDoc.mirror(false, true);
0125 visible: !root.cropping && !root.resizing
0126 },
0127 Kirigami.Action {
0128 icon.name: "object-flip-horizontal"
0129 text: i18nc("@action:button Mirror an image horizontally", "Mirror");
0130 onTriggered: imageDoc.mirror(true, false);
0131 visible: !root.cropping && !root.resizing
0132 },
0133 Kirigami.Action {
0134 visible: root.resizing
0135 displayComponent: QQC2.ToolSeparator {
0136 leftPadding: Kirigami.Units.largeSpacing
0137 rightPadding: leftPadding
0138 }
0139 },
0140 Kirigami.Action {
0141 visible: root.resizing
0142 displayComponent: QQC2.Label {
0143 text: i18nc("@title:group for crop area size spinboxes", "Size:")
0144 }
0145 },
0146 Kirigami.Action {
0147 visible: root.resizing
0148 displayComponent: EditorSpinBox {
0149 minimumContentWidth: widthTextMetrics.width
0150 from: 1
0151 to: editImage.nativeWidth
0152 value: selectionTool.selectionWidth / editImage.ratioX
0153 onValueModified: selectionTool.selectionWidth = value * editImage.ratioX
0154 }
0155 },
0156 Kirigami.Action {
0157 visible: root.resizing
0158 displayComponent: EditorSpinBox {
0159 minimumContentWidth: heightTextMetrics.width
0160 from: 1
0161 to: editImage.nativeHeight
0162 value: selectionTool.selectionHeight / editImage.ratioY
0163 onValueModified: selectionTool.selectionHeight = value * editImage.ratioY
0164 }
0165 },
0166 Kirigami.Action {
0167 visible: root.resizing
0168 displayComponent: Item {
0169 implicitWidth: Kirigami.Units.largeSpacing
0170 }
0171 },
0172 Kirigami.Action {
0173 visible: root.resizing
0174 displayComponent: QQC2.Label {
0175 text: i18nc("@title:group for crop area position spinboxes", "Position:")
0176 }
0177 },
0178 Kirigami.Action {
0179 visible: root.resizing
0180 displayComponent: EditorSpinBox {
0181 minimumContentWidth: widthTextMetrics.width
0182 from: 0
0183 to: editImage.nativeWidth - (selectionTool.selectionWidth / editImage.ratioX)
0184 value: selectionTool.selectionX / editImage.ratioX
0185 onValueModified: selectionTool.selectionX = value * editImage.ratioX
0186 }
0187 },
0188 Kirigami.Action {
0189 visible: root.resizing
0190 displayComponent: EditorSpinBox {
0191 minimumContentWidth: heightTextMetrics.width
0192 from: 0
0193 to: editImage.nativeHeight - (selectionTool.selectionHeight / editImage.ratioY)
0194 value: selectionTool.selectionY / editImage.ratioY
0195 onValueModified: selectionTool.selectionY = value * editImage.ratioY
0196 }
0197 }
0198 ]
0199 }
0200
0201 ConfirmDiscardingChange {
0202 id: confirmDiscardingChangeDialog
0203 onDiscardChanges: {
0204 root.forceDiscard = true;
0205 applicationWindow().pageStack.layers.pop();
0206 }
0207 }
0208
0209 TextMetrics {
0210 id: widthTextMetrics
0211 text: editImage.nativeWidth.toLocaleString(root.locale, 'f', 0)
0212 }
0213
0214 TextMetrics {
0215 id: heightTextMetrics
0216 text: editImage.nativeHeight.toLocaleString(root.locale, 'f', 0)
0217 }
0218
0219 component EditorSpinBox : QQC2.SpinBox {
0220 id: control
0221 property real minimumContentWidth: 0
0222 contentItem: QQC2.TextField {
0223 id: textField
0224 implicitWidth: control.minimumContentWidth + leftPadding + rightPadding
0225 implicitHeight: Math.ceil(contentHeight) + topPadding + bottomPadding
0226 palette: control.palette
0227 leftPadding: control.spacing
0228 rightPadding: control.spacing
0229 topPadding: 0
0230 bottomPadding: 0
0231 text: control.displayText
0232 font: control.font
0233 color: Kirigami.Theme.textColor
0234 selectionColor: Kirigami.Theme.highlightColor
0235 selectedTextColor: Kirigami.Theme.highlightedTextColor
0236 horizontalAlignment: Qt.AlignHCenter
0237 verticalAlignment: Qt.AlignVCenter
0238 readOnly: !control.editable
0239 validator: control.validator
0240 inputMethodHints: control.inputMethodHints
0241 selectByMouse: true
0242 background: null
0243 }
0244 }
0245
0246 FileDialog {
0247 id: fileDialog
0248 title: i18n("Save As")
0249 folder: shortcuts.home
0250 selectMultiple: false
0251 selectExisting: false
0252 onAccepted: {
0253 if (imageDoc.saveAs(fileDialog.fileUrl)) {;
0254 imagePath = fileDialog.fileUrl;
0255 msg.type = Kirigami.MessageType.Information
0256 msg.text = i18n("You are now editing a new file.")
0257 msg.visible = true;
0258 } else {
0259 msg.type = Kirigami.MessageType.Error
0260 msg.text = i18n("Unable to save file. Check if you have the correct permission to edit this file.")
0261 msg.visible = true;
0262 }
0263 fileDialog.close()
0264 }
0265 onRejected: {
0266 fileDialog.close()
0267 }
0268 Component.onCompleted: visible = false
0269 }
0270
0271 KQuickImageEditor.ImageItem {
0272 id: editImage
0273 readonly property real ratioX: editImage.paintedWidth / editImage.nativeWidth;
0274 readonly property real ratioY: editImage.paintedHeight / editImage.nativeHeight;
0275
0276 // Assigning this to the contentItem and setting the padding causes weird positioning issues
0277 anchors.fill: parent
0278 anchors.margins: Kirigami.Units.gridUnit
0279 fillMode: KQuickImageEditor.ImageItem.PreserveAspectFit
0280 image: imageDoc.image
0281
0282 Shortcut {
0283 sequence: StandardKey.Undo
0284 onActivated: undoAction.trigger();
0285 }
0286
0287 Shortcut {
0288 sequences: [StandardKey.Save, "Enter"]
0289 onActivated: saveAction.trigger();
0290 }
0291
0292 Shortcut {
0293 sequence: StandardKey.SaveAs
0294 onActivated: saveAsAction.trigger();
0295 }
0296
0297 KQuickImageEditor.ImageDocument {
0298 id: imageDoc
0299 path: root.imagePath
0300 }
0301
0302 KQuickImageEditor.SelectionTool {
0303 id: selectionTool
0304 visible: root.cropping || root.resizing
0305 width: editImage.paintedWidth
0306 height: editImage.paintedHeight
0307 x: editImage.horizontalPadding
0308 y: editImage.verticalPadding
0309 KQuickImageEditor.CropBackground {
0310 anchors.fill: parent
0311 z: -1
0312 insideX: selectionTool.selectionX
0313 insideY: selectionTool.selectionY
0314 insideWidth: selectionTool.selectionWidth
0315 insideHeight: selectionTool.selectionHeight
0316 }
0317 Loader {
0318 active: root.resizing
0319 visible: root.resizing
0320 x: selectionTool.selectionX
0321 y: selectionTool.selectionY
0322 width: selectionTool.selectionWidth
0323 height: selectionTool.selectionHeight
0324 sourceComponent: KQuickImageEditor.ImageItem {
0325 anchors.fill: parent
0326 fillMode: KQuickImageEditor.ImageItem.Stretch
0327 image: imageDoc.image
0328 }
0329 }
0330 Connections {
0331 target: selectionTool.selectionArea
0332 function onDoubleClicked() {
0333 if (root.cropping) {
0334 root.crop()
0335 } else if (root.resizing) {
0336 root.resize()
0337 }
0338 }
0339 }
0340 }
0341 onImageChanged: {
0342 selectionTool.selectionX = 0
0343 selectionTool.selectionY = 0
0344 selectionTool.selectionWidth = Qt.binding(() => selectionTool.width)
0345 selectionTool.selectionHeight = Qt.binding(() => selectionTool.height)
0346 }
0347 }
0348
0349 footer: Kirigami.InlineMessage {
0350 id: msg
0351 type: Kirigami.MessageType.Error
0352 showCloseButton: true
0353 visible: false
0354 }
0355 }