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 }