Explorar el Código

Add pointer mode and deselect tools after placing text or images.

Prevents repeated add-text/image actions on canvas clicks by returning to a neutral selection state once content is placed.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 hace 1 mes
padre
commit
5075d96522
Se han modificado 1 ficheros con 59 adiciones y 10 borrados
  1. 59 10
      smart_printer/DrawPrintView.swift

+ 59 - 10
smart_printer/DrawPrintView.swift

@@ -13,10 +13,13 @@ enum DrawPrintService {
 
 // MARK: - Canvas Model
 
-enum CanvasTool: CaseIterable {
+enum CanvasTool {
+    case pointer
     case text
     case image
     case draw
+
+    static let toolbarTools: [CanvasTool] = [.text, .image, .draw]
 }
 
 struct CanvasStroke {
@@ -264,6 +267,7 @@ final class DrawPrintOverlayView: NSView, AppearanceRefreshable {
         guard panel.runModal() == .OK, let url = panel.url,
               let image = NSImage(contentsOf: url) else { return }
         canvasView.addImage(image, at: placement)
+        toolsPanel.setActiveTool(.pointer)
     }
 
     private func commitAddedText(_ text: String) {
@@ -276,6 +280,7 @@ final class DrawPrintOverlayView: NSView, AppearanceRefreshable {
         canvasContainer.layoutSubtreeIfNeeded()
         canvasView.layoutSubtreeIfNeeded()
         canvasView.addTextItem(text: text, at: placement)
+        toolsPanel.setActiveTool(.pointer)
 
         DispatchQueue.main.async { [weak self] in
             self?.hideAddTextPrompt(animated: false)
@@ -434,6 +439,8 @@ final class BlankCanvasView: NSView, AppearanceRefreshable {
     override func resetCursorRects() {
         let cursor: NSCursor
         switch activeTool {
+        case .pointer:
+            cursor = .arrow
         case .draw:
             cursor = .crosshair
         case .text:
@@ -451,7 +458,8 @@ final class BlankCanvasView: NSView, AppearanceRefreshable {
                 return hit
             }
         }
-        if activeTool == .text, editingTextID == nil, textIndex(at: point) != nil {
+        if (activeTool == .text || activeTool == .pointer),
+           editingTextID == nil, textIndex(at: point) != nil {
             return self
         }
         return super.hitTest(point)
@@ -492,7 +500,8 @@ final class BlankCanvasView: NSView, AppearanceRefreshable {
             item.image.draw(in: rect, from: .zero, operation: .sourceOver, fraction: 1)
         }
 
-        if activeTool == .text, let selectedID = selectedTextID,
+        if (activeTool == .text || activeTool == .pointer),
+           let selectedID = selectedTextID,
            let item = textItems.first(where: { $0.id == selectedID }),
            item.id != editingTextID {
             drawTextSelection(for: item)
@@ -544,6 +553,34 @@ final class BlankCanvasView: NSView, AppearanceRefreshable {
         }
 
         switch activeTool {
+        case .pointer:
+            if let index = textIndex(at: point) {
+                let id = textItems[index].id
+                selectedTextID = id
+                selectedImageID = nil
+                if event.clickCount >= 2 {
+                    beginEditingText(id: id)
+                } else {
+                    draggingTextID = id
+                    dragStartPoint = point
+                    dragStartOrigin = textItems[index].origin
+                    textDragSnapshotPushed = false
+                }
+            } else if let index = imageIndex(at: point) {
+                selectedImageID = imageItems[index].id
+                selectedTextID = nil
+                draggingImageID = imageItems[index].id
+                dragStartPoint = point
+                dragStartOrigin = imageItems[index].origin
+                imageDragSnapshotPushed = false
+            } else {
+                selectedTextID = nil
+                selectedImageID = nil
+                if editingTextID != nil {
+                    endEditingText()
+                }
+                needsDisplay = true
+            }
         case .draw:
             pushSnapshot()
             currentStroke = CanvasStroke(points: [point], color: drawColor, lineWidth: drawLineWidth)
@@ -581,7 +618,7 @@ final class BlankCanvasView: NSView, AppearanceRefreshable {
     override func mouseDragged(with event: NSEvent) {
         let point = convert(event.locationInWindow, from: nil)
 
-        if activeTool == .text,
+        if (activeTool == .text || activeTool == .pointer),
            let id = draggingTextID,
            let index = textItems.firstIndex(where: { $0.id == id }) {
             if !textDragSnapshotPushed {
@@ -599,7 +636,7 @@ final class BlankCanvasView: NSView, AppearanceRefreshable {
             return
         }
 
-        if activeTool == .image,
+        if (activeTool == .image || activeTool == .pointer),
            let id = draggingImageID,
            let index = imageItems.firstIndex(where: { $0.id == id }) {
             if !imageDragSnapshotPushed {
@@ -624,14 +661,14 @@ final class BlankCanvasView: NSView, AppearanceRefreshable {
     }
 
     override func mouseUp(with event: NSEvent) {
-        if activeTool == .text, draggingTextID != nil {
+        if (activeTool == .text || activeTool == .pointer), draggingTextID != nil {
             draggingTextID = nil
             textDragSnapshotPushed = false
             notifyUndoState()
             return
         }
 
-        if activeTool == .image, draggingImageID != nil {
+        if (activeTool == .image || activeTool == .pointer), draggingImageID != nil {
             draggingImageID = nil
             imageDragSnapshotPushed = false
             notifyUndoState()
@@ -932,6 +969,10 @@ final class CanvasToolsPanel: NSView, AppearanceRefreshable {
     @available(*, unavailable)
     required init?(coder: NSCoder) { nil }
 
+    func setActiveTool(_ tool: CanvasTool) {
+        selectTool(tool)
+    }
+
     func refreshAppearance() {
         layer?.backgroundColor = AppTheme.cardBackground.cgColor
         layer?.borderColor = AppTheme.paywallBorder.cgColor
@@ -955,7 +996,7 @@ final class CanvasToolsPanel: NSView, AppearanceRefreshable {
         subToolbar.layer?.cornerRadius = 20
         subToolbar.translatesAutoresizingMaskIntoConstraints = false
 
-        for tool in CanvasTool.allCases {
+        for tool in CanvasTool.toolbarTools {
             let button = CanvasToolButton(tool: tool)
             button.onClick = { [weak self] in self?.selectTool(tool) }
             toolButtons[tool] = button
@@ -983,7 +1024,11 @@ final class CanvasToolsPanel: NSView, AppearanceRefreshable {
 
     private func selectTool(_ tool: CanvasTool) {
         activeTool = tool
-        toolButtons.forEach { $0.value.setSelected($0.key == tool) }
+        if tool == .pointer {
+            toolButtons.values.forEach { $0.setSelected(false) }
+        } else {
+            toolButtons.forEach { $0.value.setSelected($0.key == tool) }
+        }
         onToolChanged?(tool)
         rebuildSubToolbar()
     }
@@ -997,6 +1042,8 @@ final class CanvasToolsPanel: NSView, AppearanceRefreshable {
         stack.translatesAutoresizingMaskIntoConstraints = false
 
         switch activeTool {
+        case .pointer:
+            break
         case .text:
             stack.addArrangedSubview(makeSubButton(symbol: "text.alignleft", action: { [weak self] in
                 self?.onTextAlignment?(.left)
@@ -1035,7 +1082,7 @@ final class CanvasToolsPanel: NSView, AppearanceRefreshable {
             stack.bottomAnchor.constraint(equalTo: subToolbar.bottomAnchor, constant: -6),
         ])
 
-        subToolbar.isHidden = activeTool == .image
+        subToolbar.isHidden = activeTool == .image || activeTool == .pointer
 
         let itemCount = max(stack.arrangedSubviews.count, 1)
         subToolbarHeight?.constant = 40
@@ -1582,6 +1629,7 @@ private final class CanvasToolButton: NSControl, AppearanceRefreshable {
 
         let symbol: String
         switch tool {
+        case .pointer: symbol = "arrow.up.left"
         case .text: symbol = "character.cursor.ibeam"
         case .image: symbol = "photo.on.rectangle.angled"
         case .draw: symbol = "paintbrush.pointed.fill"
@@ -1607,6 +1655,7 @@ private final class CanvasToolButton: NSControl, AppearanceRefreshable {
 
     private var toolLabel: String {
         switch tool {
+        case .pointer: return "Pointer"
         case .text: return "Text"
         case .image: return "Image"
         case .draw: return "Draw"