From c7ff01164974c49e563aac4cb3c95a5914f12c92 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 7 Apr 2022 21:33:26 +0300 Subject: [PATCH] feat(StatusImageCropPanel): Add image crop editor panel component New QML component StatusQ.Components.StatusImageCropPanel that extends on StatusImageCrop with simper interface and extra features Features: - Minimizes drawing with Canvas to the crop window - Adds user interactions: pan, zoom - Zoom slider for zooming, beside the mouse scroll action - Optional checker pattern for background for the user to have a visual feedback on the transparent areas or image margins fixes: #5401 updates: #5118 --- doc/src/images/eg-StatusImageCrop.png | Bin 0 -> 45538 bytes .../Components/StatusImageCropPanel.qml | 283 ++++++++++++++++++ src/StatusQ/Components/qmldir | 1 + 3 files changed, 284 insertions(+) create mode 100644 doc/src/images/eg-StatusImageCrop.png create mode 100644 src/StatusQ/Components/StatusImageCropPanel.qml diff --git a/doc/src/images/eg-StatusImageCrop.png b/doc/src/images/eg-StatusImageCrop.png new file mode 100644 index 0000000000000000000000000000000000000000..328657c608d020bf5094ebba51988209599509a9 GIT binary patch literal 45538 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 literal 0 HcmV?d00001 diff --git a/src/StatusQ/Components/StatusImageCropPanel.qml b/src/StatusQ/Components/StatusImageCropPanel.qml new file mode 100644 index 00000000..63548de5 --- /dev/null +++ b/src/StatusQ/Components/StatusImageCropPanel.qml @@ -0,0 +1,283 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Controls 0.1 + +/*! + \qmltype StatusImageCropPanel + \inherits Item + \inqmlmodule StatusQ.Components + \since StatusQ.Components 0.1 + \brief Draw a crop-window onto an image and allows manipulating the position of the crop-window. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-item.html}{Item}. + + Adds mouse pan and zoom functionality on top of StatusImageCrop functionality. Also adds small + practical features and optimizes drawing by minimizing StatusImageCrop area + + \sa StatusImageCrop for more details + + Example of how to use it: + + \qml + StatusImageCropPanel { + width: 400 + height: 200 + source: "qrc:/demoapp/data/logo-test-image.png" + windowStyle: StatusImageCrop.WindowStyle.Rectangular + Component.onCompleted: setCropRect(Qt.rect(10, 0, sourceSize.width - 20, sourceSize.height)) + } + \endqml + + For a list of components available see StatusQ. +*/ +Item { + id: root + + implicitWidth: mainLayout.implicitWidth + implicitHeight: mainLayout.implicitHeight + + /*! + \qmlproperty real StatusImageCrop::aspectRatio + Initial aspect-ratio of the crop-window + */ + property real aspectRatio: 1 + /*! + \qmlproperty bool StatusImageCrop::interactive + If true allows user to interact with the image. Set to false for previewing existing crop-data + */ + property bool interactive: true + /*! + \qmlproperty bool StatusImageCrop::margins + Space to keep around the control borders and crop area + */ + property int margins: 10 + + /*! + \qmlproperty url StatusImageCropPanel::source + \sa StatusImageCrop::source + */ + /*required*/ property alias source: cropEditor.source + + /*! + \qmlproperty WindowStyle StatusImageCropPanel::windowStyle + \sa StatusImageCrop::windowStyle + */ + property alias windowStyle: cropEditor.windowStyle + /*! + \qmlproperty int StatusImageCropPanel::radius + \sa StatusImageCrop::radius + */ + property alias radius: cropEditor.radius + /*! + \qmlproperty color StatusImageCropPanel::wallColor + \sa StatusImageCrop::wallColor + */ + property alias wallColor: cropEditor.wallColor + /*! + \qmlproperty real StatusImageCropPanel::wallTransparency + \sa StatusImageCrop::wallTransparency + */ + property alias wallTransparency: cropEditor.wallTransparency + /*! + \qmlproperty rect StatusImageCropPanel::cropRect + \sa StatusImageCrop::cropRect + */ + property alias cropRect: cropEditor.cropRect + /*! + \qmlproperty rect StatusImageCropPanel::cropRect + \sa StatusImageCrop::cropRect + */ + readonly property alias cropWindow: cropEditor.cropWindow + /*! + \qmlproperty real StatusImageCrop::scrollZoomFactor + How fast is image scaled (zoomed) when using mouse scroll + */ + property real scrollZoomFactor: 0.5 + /*! + \qmlproperty bool StatusImageCropPanel::enableCheckers + Shows helper guiding checkers pattern where image is not covering + */ + property bool enableCheckers: root.interactive + /*! + \qmlproperty size StatusImageCropPanel::sourceSize + \sa StatusImageCrop::sourceSize + */ + property alias sourceSize: cropEditor.sourceSize + + /* + \qmlmethod StatusImageCropPanel::setCropRect(rect) + \sa StatusImageCrop::cropRect + */ + function setCropRect(newRect) { + cropEditor.setCropRect(newRect) + aspectRatio = cropEditor.aspectRatio + } + + QtObject { + id: d + + function updateAspectRatio(newAR) { + // Keep width and adjust height + const eW = cropEditor.cropRect.width + const w = (eW <= 0) ? cropEditor.sourceSize.width : eW + const h = w/newAR + const c = (eW <= 0) + ? Qt.point(cropEditor.sourceSize.width/2, cropEditor.sourceSize.height/2) + : Qt.point(cropEditor.cropRect.x + w/2, cropEditor.cropRect.y + cropEditor.cropRect.height/2) + const nR = Qt.rect(c.x - w/2, c.y-h/2, w, h) + cropEditor.setCropRect(nR) + } + } + + Component.onCompleted: d.updateAspectRatio(root.aspectRatio) + onAspectRatioChanged: d.updateAspectRatio(root.aspectRatio) + onSourceSizeChanged: d.updateAspectRatio(root.aspectRatio) + + ColumnLayout { + id: mainLayout + + anchors.fill: parent + + Item { + id: cropSpaceItem + + Layout.fillWidth: true + Layout.fillHeight: true + + clip: true + + Rectangle { + id: leftOverlay + anchors.left: parent.left + anchors.top: parent.top + anchors.right: cropEditor.left + anchors.bottom: parent.bottom + color: wallColor + opacity: wallTransparency + z: cropEditor.z + 1 + } + Rectangle { + id: topOverlay + anchors.left: leftOverlay.right + anchors.top: parent.top + anchors.right: rightOverlay.left + anchors.bottom: cropEditor.top + color: wallColor + opacity: wallTransparency + z: cropEditor.z + 1 + } + + StatusImageCrop { + id: cropEditor + anchors.centerIn: parent + width: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height * aspectRatio : cropSpaceItem.width - root.margins * 2 + height: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height - root.margins * 2 : cropSpaceItem.width / aspectRatio + } + + Rectangle { + id: rightOverlay + anchors.left: cropEditor.right + anchors.top: parent.top + anchors.right: parent.right + anchors.bottom: parent.bottom + color: wallColor + opacity: wallTransparency + z: cropEditor.z + 1 + } + + Rectangle { + id: bottomOverlay + anchors.left: leftOverlay.right + anchors.top: cropEditor.bottom + anchors.right: rightOverlay.left + anchors.bottom: parent.bottom + color: wallColor + opacity: wallTransparency + z: cropEditor.z + 1 + } + + // Checkers + Canvas { + visible: root.enableCheckers + anchors.fill: parent + onPaint: { + var ctx = getContext("2d") + for(let xI = 0; xI < Math.ceil(width/10); xI++) { + for(let yI = 0; yI < Math.ceil(height/10); yI++) { + ctx.fillStyle = (xI % 2) === (yI % 2) ? "#FFFFFE" : "#DBDBDB" + ctx.fillRect(xI * 10, yI * 10, 10, 10) + } + } + } + z: cropEditor.z - 1 + } + + // Drag and zoom + MouseArea { + anchors.fill: parent + + enabled: root.interactive + + property var lastDragPoint: null + onReleased: lastDragPoint = null + + onMouseXChanged: updateDrag(Qt.point(mouse.x, mouse.y)) + onMouseYChanged: updateDrag(Qt.point(mouse.x, mouse.y)) + + onWheel: { + const delta = wheel.angleDelta.y / 120 + cropEditor.setCropRect(cropEditor.getZoomRect(cropEditor.zoomScale + delta * root.scrollZoomFactor)) + } + + function moveRect(r /*rect*/, delta /*real*/) { + return Qt.rect(r.x + delta.x, r.y + delta.y, r.width, r.height) + } + + function scaleSize(sz /*size*/, s /*size*/) { + return Qt.point(sz.width * s, sz.height * s) + } + + function updateDrag(p) { + let delta = (lastDragPoint ? Qt.size(lastDragPoint.x - p.x, lastDragPoint.y - p.y) : Qt.size(0, 0)) + delta = scaleSize(delta, 1/cropEditor.scrToImgScale) + cropEditor.setCropRect(moveRect(cropEditor.cropRect, delta)) + lastDragPoint = p + } + } + } + + RowLayout { + visible: root.interactive + + StatusIcon { + icon: "remove-circle" + + Layout.preferredWidth: 20 + Layout.preferredHeight: 20 + } + StatusSlider { + Layout.fillWidth: true + Layout.preferredHeight: 5 + Layout.topMargin: 20 + Layout.bottomMargin: 25 + Layout.alignment: Qt.AlignVCenter + + enabled: root.interactive + + from: 1 + value: cropEditor.zoomScale + live: false + onMoved: cropEditor.setCropRect(cropEditor.getZoomRect(valueAt(visualPosition))) + + to: 10 + } + StatusIcon { + icon: "add-circle" + + Layout.preferredWidth: 20 + Layout.preferredHeight: 20 + } + } + } +} + diff --git a/src/StatusQ/Components/qmldir b/src/StatusQ/Components/qmldir index 973bb377..8eedf75f 100644 --- a/src/StatusQ/Components/qmldir +++ b/src/StatusQ/Components/qmldir @@ -32,3 +32,4 @@ StatusMessageDetails 0.1 StatusMessageDetails.qml StatusTagSelector 0.1 StatusTagSelector.qml StatusToastMessage 0.1 StatusToastMessage.qml StatusWizardStepper 0.1 StatusWizardStepper.qml +StatusImageCropPanel 0.1 StatusImageCropPanel.qml