diff --git a/Helpers/Picker.qml b/Helpers/Picker.qml index 4519fe7..a2f5c4f 100755 --- a/Helpers/Picker.qml +++ b/Helpers/Picker.qml @@ -129,22 +129,22 @@ Item { Behavior on rsx { enabled: !selectArea.pressed && root.mode === "select" - ExAnim {} + Anim {} } Behavior on rsy { enabled: !selectArea.pressed && root.mode === "select" - ExAnim {} + Anim {} } Behavior on sh { enabled: !selectArea.pressed && root.mode === "select" - ExAnim {} + Anim {} } Behavior on sw { enabled: !selectArea.pressed && root.mode === "select" - ExAnim {} + Anim {} } Behavior on opacity { Anim { @@ -236,19 +236,19 @@ Item { to: 0 } - ExAnim { + Anim { properties: "rsx,rsy" target: root to: 0 } - ExAnim { + Anim { property: "sw" target: root to: root.screen.width } - ExAnim { + Anim { property: "sh" target: root to: root.screen.height @@ -286,6 +286,7 @@ Item { anchors.fill: parent inkColor: root.inkColor layer.enabled: true + selection: selectionRect tool: root.mode === "edit" && root.tool !== "move" ? root.tool : "none" layer.effect: MultiEffect { @@ -297,7 +298,7 @@ Item { } } - Rectangle { + CustomRect { id: overlay anchors.fill: parent @@ -334,12 +335,11 @@ Item { } } - Rectangle { + CustomRect { id: border border.color: Colors.palette.m3primary border.width: root.realBorderWidth - color: "transparent" implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2 implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2 radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0 @@ -355,10 +355,13 @@ Item { SelectionHandles { id: handles + border: root.realBorderWidth selH: root.sh selW: root.sw selX: root.rsx selY: root.rsy + selection: selectionRect + tool: root.tool visible: root.mode === "edit" && root.tool === "move" onBoundsChanged: (x, y, w, h) => { @@ -396,6 +399,4 @@ Item { onToolSelected: t => root.tool = t onUndoRequested: annotations.undo() } - - component ExAnim: Anim {} } diff --git a/Helpers/Picker/AnnotationCanvas.qml b/Helpers/Picker/AnnotationCanvas.qml index 7ff98b0..32e251f 100755 --- a/Helpers/Picker/AnnotationCanvas.qml +++ b/Helpers/Picker/AnnotationCanvas.qml @@ -8,13 +8,13 @@ Item { property color inkColor: "#ff3b30" property real inkWidth: 4 + required property Rectangle selection property string tool: "none" signal changed function clearAll() { - committedCanvas.clear(); - previewCanvas.clear(); + canvas.clear(); changed(); } @@ -54,89 +54,82 @@ Item { } function undo() { - committedCanvas.undoLastGroup(); + canvas.undoLastGroup(); changed(); } anchors.fill: parent StrokeCanvas { - id: committedCanvas + id: canvas anchors.fill: parent penColor: root.inkColor penWidth: root.inkWidth } - StrokeCanvas { - id: previewCanvas - - anchors.fill: parent - penColor: root.inkColor - penWidth: root.inkWidth - } - - PointHandler { + MouseArea { id: drawHandler property real startX property real startY - property bool started: false acceptedButtons: Qt.LeftButton | Qt.RightButton + anchors.fill: parent + cursorShape: undefined enabled: root.tool !== "none" + hoverEnabled: true - onActiveChanged: { - if (active) + onPositionChanged: e => { + const x = e.x; + const y = e.y; + + canvas.hoverPoint = Qt.point(x, y); + + if (!pressed) return; if (root.tool === "pen") { - committedCanvas.endStroke(); - } else if (started) { - const pts = root.sampleShape(root.tool, startX, startY, point.position.x, point.position.y); - if (pts.length > 0) { - committedCanvas.beginStroke(pts[0][0], pts[0][1], true); - for (let i = 1; i < pts.length; i++) - committedCanvas.appendPoint(pts[i][0], pts[i][1]); - committedCanvas.endStroke(); - } - previewCanvas.clear(); - } - started = false; - root.changed(); - } - onPointChanged: { - if (!active) + canvas.appendPoint(x, y); return; + } - if (point.pressedButtons & Qt.RightButton) { - root.clearAll(); - return; + const pts = root.sampleShape(root.tool, startX, startY, x, y); + if (pts.length > 0) { + canvas.beginStroke(pts[0][0], pts[0][1], true); + for (let i = 1; i < pts.length; i++) + canvas.appendPoint(pts[i][0], pts[i][1]); } + } + onPressed: e => { + if (e.button & Qt.LeftButton) { + startX = e.x; + startY = e.y; + canvas.beginStroke(e.x, e.y); + } else if (e.button & Qt.RightButton) { + root.clearAll(); + } + } + onPressedChanged: if (!pressed) + canvas.endStroke() + } + + HoverHandler { + cursorShape: { + if (root.tool === "none") + return undefined; const x = point.position.x; const y = point.position.y; + const withinXWidth = x > root.selection.x && x < root.selection.x + root.selection.implicitWidth; + const withinYHeight = y > root.selection.y && y < root.selection.y + root.selection.implicitHeight; - if (root.tool === "pen") { - if (!started) { - started = true; - committedCanvas.beginStroke(x, y); - return; - } - committedCanvas.appendPoint(x, y); - return; - } - - if (!started) { - started = true; - startX = point.pressPosition.x; - startY = point.pressPosition.y; - } - const pts = root.sampleShape(root.tool, startX, startY, x, y); - if (pts.length > 0) { - previewCanvas.beginStroke(pts[0][0], pts[0][1], true); - for (let i = 1; i < pts.length; i++) - previewCanvas.appendPoint(pts[i][0], pts[i][1]); + if (withinXWidth && withinYHeight) { + canvas.showHover(x, y); + return Qt.BlankCursor; + } else { + canvas.hideHover(); + return undefined; } } } diff --git a/Helpers/Picker/SelectionHandles.qml b/Helpers/Picker/SelectionHandles.qml index eca4b0f..d79ae71 100755 --- a/Helpers/Picker/SelectionHandles.qml +++ b/Helpers/Picker/SelectionHandles.qml @@ -5,6 +5,7 @@ import QtQuick Item { id: root + required property int border property color handleBorder: "#3584e4" property color handleFill: "white" property real hs: 12 @@ -13,6 +14,8 @@ Item { required property real selW required property real selX required property real selY + required property Rectangle selection + required property string tool signal boundsChanged(x: real, y: real, w: real, h: real) signal dragFinished @@ -29,6 +32,7 @@ Item { property real accumX: 0 property real accumY: 0 + cursorShape: undefined target: null onActiveChanged: { @@ -45,51 +49,63 @@ Item { } } + HoverHandler { + cursorShape: { + if (root.tool !== "move") + return undefined; + + if (moveHandler.centroid.pressedButtons & Qt.LeftButton) + return Qt.ClosedHandCursor; + else + return Qt.OpenHandCursor; + } + } + Handle { edge: "tl" - x: -root.hs / 2 - y: -root.hs / 2 + x: -(root.hs + root.border) / 2 + y: -(root.hs + root.border) / 2 } Handle { edge: "t" x: root.width / 2 - root.hs / 2 - y: -root.hs / 2 + y: -(root.hs + root.border) / 2 } Handle { edge: "tr" - x: root.width - root.hs / 2 - y: -root.hs / 2 + x: root.width - root.hs / 2 + root.border / 2 + y: -(root.hs + root.border) / 2 } Handle { edge: "r" - x: root.width - root.hs / 2 + x: root.width - root.hs / 2 + root.border / 2 y: root.height / 2 - root.hs / 2 } Handle { edge: "br" - x: root.width - root.hs / 2 - y: root.height - root.hs / 2 + x: root.width - root.hs / 2 + root.border / 2 + y: root.height - root.hs / 2 + root.border / 2 } Handle { edge: "b" x: root.width / 2 - root.hs / 2 - y: root.height - root.hs / 2 + y: root.height - root.hs / 2 + root.border / 2 } Handle { edge: "bl" - x: -root.hs / 2 - y: root.height - root.hs / 2 + x: -(root.hs + root.border) / 2 + y: root.height - root.hs / 2 + root.border / 2 } Handle { edge: "l" - x: -root.hs / 2 + x: -(root.hs + root.border) / 2 y: root.height / 2 - root.hs / 2 } diff --git a/Plugins/ZShell/Internal/strokecanvasrenderer.cpp b/Plugins/ZShell/Internal/strokecanvasrenderer.cpp index 3a77d76..c109728 100644 --- a/Plugins/ZShell/Internal/strokecanvasrenderer.cpp +++ b/Plugins/ZShell/Internal/strokecanvasrenderer.cpp @@ -1,6 +1,7 @@ #include "strokecanvasrenderer.hpp" #include "strokecanvasitem.hpp" #include +#include namespace ZShell::internal { @@ -148,14 +149,27 @@ void StrokeCanvasRenderer::synchronizeData(QCanvasPainterItem* item) { m_penColor = canvas->m_penColor; m_penWidth = canvas->m_penWidth; - while (m_strokes.size() < canvas->m_strokes.size()) - m_strokes.append(canvas->m_strokes[m_strokes.size()]); + // Detect removed strokes: present in renderer but no longer in canvas + QSet canvasGroupIds; + for (const auto& stroke : canvas->m_strokes) + canvasGroupIds.insert(stroke.groupId); - if (canvas->m_strokes.isEmpty() && !m_strokes.isEmpty()) { - for (const auto& stroke : m_strokes) - if (stroke.groupId >= 0) - m_pendingGroupRemovals.append(stroke.groupId); - m_strokes.clear(); + for (int i = m_strokes.size() - 1; i >= 0; --i) { + if (!canvasGroupIds.contains(m_strokes[i].groupId)) { + if (m_strokes[i].groupId >= 0) + m_pendingGroupRemovals.append(m_strokes[i].groupId); + m_strokes.remove(i); + } + } + + // Detect added strokes: present in canvas but not yet in renderer + QSet rendererGroupIds; + for (const auto& stroke : m_strokes) + rendererGroupIds.insert(stroke.groupId); + + for (const auto& stroke : canvas->m_strokes) { + if (!rendererGroupIds.contains(stroke.groupId)) + m_strokes.append(stroke); } m_currentStroke = canvas->m_currentStroke;