MauiKit Image Tools

code/modules/editor/src/controls/ImageEditor.qml
1import QtQuick
2import QtQuick.Controls
3import QtQuick.Layouts
4import QtQuick.Effects
5
6import org.mauikit.controls as Maui
7import org.mauikit.imagetools.editor as ITE
8
9import "private" as Private
10
11
12/**
13 * @inherit org::mauikit::controls::Page
14 * @brief A control with different tools for editingan image
15 *
16 */
17Maui.Page
19 id: control
20
21 property url url
22
23 readonly property bool ready : String(control.url).length
24
25 readonly property alias editor : imageDoc
26
27 signal saved()
28 signal savedAs(string url)
29 signal canceled()
30
32 {
33 id: _cancelDialog
34 message: i18n("Are you sure you wanna cancel all the edits?")
35 standardButtons: Dialog.Yes | Dialog.Cancel
36
37 onAccepted:
38 {
39 imageDoc.cancel()
40 control.canceled()
41 }
42
43 onRejected: close()
44 }
45
46 headBar.visible: control.ready
47 headBar.background: null
48 headBar.leftContent: Button
49 {
50 icon.name: "go-previous"
51 Maui.Controls.status : imageDoc.edited ? Maui.Controls.Negative : Maui.Controls.Normal
52 text: i18n("Cancel")
53 onClicked:
54 {
55 if(imageDoc.edited)
56 _cancelDialog.open()
57 else
58 control.canceled()
59 }
60 }
61
62 headBar.rightContent: [
63
64 ToolButton
65 {
66 icon.name: "document-save-as"
67 enabled: imageDoc.edited
68 onClicked:
69 {
70 imageDoc.saveAs()
71 control.savedAs()
72 }
73 },
74
75 Button
76 {
77 text: "Save"
78 enabled: imageDoc.edited
79 Maui.Controls.status : imageDoc.edited ? Maui.Controls.Positive : Maui.Controls.Normal
80
81 onClicked:
82 {
83 imageDoc.save()
84 control.saved()
85 }
86 }
87 ]
88
89 ITE.ImageItem
90 {
91 id: editImage
92 readonly property real ratioX: editImage.paintedWidth / editImage.nativeWidth;
93 readonly property real ratioY: editImage.paintedHeight / editImage.nativeHeight;
94
95 fillMode: Image.PreserveAspectFit
96 image: imageDoc.image
97 anchors.fill: parent
98
99 rotation: _transBar.rotationSlider.value
100
101 ITE.ImageDocument
102 {
103 id: imageDoc
104 path: control.url
105 }
106
107 ITE.SelectionTool
108 {
109 id: selectionTool
110 width: editImage.paintedWidth
111 height: editImage.paintedHeight
112 x: editImage.horizontalPadding
113 y: editImage.verticalPadding
114 ITE.CropBackground
115 {
116 anchors.fill: parent
117 z: -1
118 insideX: selectionTool.selectionX
119 insideY: selectionTool.selectionY
120 insideWidth: selectionTool.selectionWidth
121 insideHeight: selectionTool.selectionHeight
122 }
123 Connections {
124 target: selectionTool.selectionArea
125 function onDoubleClicked() {
126 control.crop()
127 }
128 }
129 }
130
131 onImageChanged:
132 {
133 selectionTool.selectionX = 0
134 selectionTool.selectionY = 0
135 selectionTool.selectionWidth = Qt.binding(() => selectionTool.width)
136 selectionTool.selectionHeight = Qt.binding(() => selectionTool.height)
137 }
138 }
139
140 Canvas
141 {
142 visible: _transfromAction.checked
143 opacity: 0.15
144 anchors.fill : parent
145 property int wgrid: control.width / 20
146 onPaint: {
147 var ctx = getContext("2d")
148 ctx.lineWidth = 0.5
149 ctx.strokeStyle = Maui.Theme.textColor
150 ctx.beginPath()
151 var nrows = height/wgrid;
152 for(var i=0; i < nrows+1; i++){
153 ctx.moveTo(0, wgrid*i);
154 ctx.lineTo(width, wgrid*i);
155 }
156
157 var ncols = width/wgrid
158 for(var j=0; j < ncols+1; j++){
159 ctx.moveTo(wgrid*j, 0);
160 ctx.lineTo(wgrid*j, height);
161 }
162 ctx.closePath()
163 ctx.stroke()
164 }
165 }
166
167 Action
168 {
169 id: _colorsAction
170 icon.name: "color-mode-black-white"
171 text: i18nd("mauikitimagetools","Color")
172 checked: _actionsBarLoader.currentIndex === 0
173 onTriggered: _actionsBarLoader.currentIndex = 0
174 }
175
176 Action
177 {
178 id: _transfromAction
179 icon.name: "dialog-transform"
180 text: i18nd("mauikitimagetools","Transform")
181 checked: _actionsBarLoader.currentIndex === 1
182 onTriggered: _actionsBarLoader.currentIndex = 1
183 }
184
185 Action
186 {
187 id: _layerAction
188 icon.name: "layer-new"
189 text: i18nd("mauikitimagetools","Layer")
190 checked: _actionsBarLoader.currentIndex === 3
191 onTriggered: _actionsBarLoader.currentIndex = 3
192 }
193
194 Action
195 {
196 id: _filterAction
197 icon.name: "image-auto-adjust"
198 text: i18nd("mauikitimagetools","Filters")
199 checked: _actionsBarLoader.currentIndex === 2
200 onTriggered: _actionsBarLoader.currentIndex = 2
201 }
202
203 Loader
204 {
205 id: _actionsBarLoader
206 property int currentIndex : 1
207 // active: settings.showActionsBar
208 visible: status == Loader.Ready
209 asynchronous: true
210 anchors.bottom: parent.bottom
211 anchors.horizontalCenter: parent.horizontalCenter
212 anchors.margins: Maui.Style.space.big
213
214 sourceComponent: Pane
215 {
216 id: _pane
217 Maui.Theme.colorSet: Maui.Theme.Complementary
218 Maui.Theme.inherit: false
219
220 // x: control.width - width - Maui.Style.space.big
221 // y: control.height - height - Maui.Style.space.big
222 background: Rectangle
223 {
224 radius: Maui.Style.radiusV
225 color: Maui.Theme.backgroundColor
226
227 layer.enabled: GraphicsInfo.api !== GraphicsInfo.Software
228 layer.effect: MultiEffect
229 {
230 autoPaddingEnabled: true
231 shadowEnabled: true
232 shadowColor: "#000000"
233 }
234 }
235
236 ScaleAnimator on scale
237 {
238 from: 0
239 to: 1
240 duration: Maui.Style.units.longDuration
241 running: visible
242 easing.type: Easing.OutInQuad
243 }
244
245 OpacityAnimator on opacity
246 {
247 from: 0
248 to: 1
249 duration: Maui.Style.units.longDuration
250 running: visible
251 }
252
253 contentItem: RowLayout
254 {
255 spacing: Maui.Style.defaultSpacing
256
257 ToolButton
258 {
259 icon.name: "edit-undo"
260 Layout.alignment: Qt.AlignVCenter
261 onClicked: imageDoc.undo()
262 checkable: false
263 enabled:imageDoc.edited
264 }
265
266 Item{}
267
268 Repeater
269 {
270 model: [_colorsAction, _transfromAction, _layerAction, _filterAction]
271
272 ToolButton
273 {
274 action: modelData
275 display: ToolButton.IconOnly
276 flat: false
277 }
278 }
279
280 Item{}
281
282 ToolButton
283 {
284 // text: i18nd("mauikitimagetools","Accept")
285 icon.name: "dialog-apply"
286 onClicked: imageDoc.applyChanges()
287 enabled: !imageDoc.changesApplied
288
289 }
290
291 }
292
293 DragHandler
294 {
295 target: _pane
296 // target: _actionsBarLoader
297 // grabPermissions: PointerHandler.TakeOverForbidden | PointerHandler.CanTakeOverFromAnything
298 xAxis.maximum: control.width - _pane.width
299 xAxis.minimum: 0
300
301 yAxis.enabled : false
302
303 onActiveChanged:
304 {
305 if(!active)
306 {
307 console.log(centroid.position, centroid.scenePosition, centroid.velocity.x)
308
309 let pos = centroid.velocity.x
310 _pane.x = Qt.binding(()=> { return pos < 0 ? Maui.Style.space.big : control.width - _pane.width - Maui.Style.space.big })
311 _pane.y = Qt.binding(()=> { return control.height - _pane.height - Maui.Style.space.big })
312 }
313 }
314 }
315 }
316 }
317
318 footBar.visible: false
319 footerColumn: [
320
321 Private.TransformationBar
322 {
323 id: _transBar
324 visible: _actionsBarLoader.currentIndex === 1 && control.ready
325 width: parent.width
326 },
327
328 Private.ColourBar
329 {
330 id: _colourBar
331 visible: _actionsBarLoader.currentIndex === 0 && control.ready
332 width: parent.width
333 },
334
335 RowLayout
336 {
337 id: _filtersBar
338 visible: _actionsBarLoader.currentIndex === 2 && control.ready
339 width: parent.width
340
341 Row
342 {
343 Layout.alignment: Qt.AlignHCenter
344
345 Button
346 {
347 text: "b&w"
348 checkable: true
349 checked: false
350 onClicked:
351 {
352 if(checked)
353 {
354 editor.toGray()
355 editor.apply()
356 }else
357 {
358 editor.undo()
359 }
360 }
361 }
362
363 Button
364 {
365 text: "sketch"
366 onClicked: editor.toSketch();
367 }
368
369 Button
370 {
371 text: "vignette"
372 onClicked: editor.addVignette();
373 }
374 }
375
376 }
377
378 ]
379
380 function selectionToolRect()
381 {
382 return Qt.rect(selectionTool.selectionX / editImage.ratioX,
383 selectionTool.selectionY / editImage.ratioY,
384 selectionTool.selectionWidth / editImage.ratioX,
385 selectionTool.selectionHeight / editImage.ratioY);
386 }
387
388 function crop()
389 {
390 console.log("CROP")
391 imageDoc.crop(selectionTool.selectionX / editImage.ratioX,
392 selectionTool.selectionY / editImage.ratioY,
393 selectionTool.selectionWidth / editImage.ratioX,
394 selectionTool.selectionHeight / editImage.ratioY);
395 }
396}
bool visible
Q_SCRIPTABLE CaptureState status()
QString i18nd(const char *domain, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QString path(const QString &relativePath)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 25 2025 11:51:53 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.