Просмотр исходного кода

Fix Add Text dialog placeholder alignment with the text cursor.

Draw the placeholder inside the text view at the insertion point rect so it shares the same layout as the caret.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 месяц назад
Родитель
Сommit
99c6a3ec51
1 измененных файлов с 44 добавлено и 14 удалено
  1. 44 14
      smart_printer/DrawPrintView.swift

+ 44 - 14
smart_printer/DrawPrintView.swift

@@ -1087,7 +1087,43 @@ final class CanvasToolsPanel: NSView, AppearanceRefreshable {
     }
     }
 }
 }
 
 
+private final class PlaceholderTextView: NSTextView {
+    var placeholderString = ""
+
+    var placeholderColor: NSColor = AppTheme.textSecondary {
+        didSet { needsDisplay = true }
+    }
+
+    override func draw(_ dirtyRect: NSRect) {
+        super.draw(dirtyRect)
+        guard string.isEmpty, !placeholderString.isEmpty else { return }
+
+        let attributes: [NSAttributedString.Key: Any] = [
+            .font: font ?? AppTheme.regularFont(size: 20),
+            .foregroundColor: placeholderColor,
+        ]
+        let rect = firstRect(forCharacterRange: NSRange(location: 0, length: 0), actualRange: nil)
+        (placeholderString as NSString).draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes)
+    }
+
+    override func becomeFirstResponder() -> Bool {
+        let becameFirstResponder = super.becomeFirstResponder()
+        if becameFirstResponder { needsDisplay = true }
+        return becameFirstResponder
+    }
+
+    override func resignFirstResponder() -> Bool {
+        let resignedFirstResponder = super.resignFirstResponder()
+        if resignedFirstResponder { needsDisplay = true }
+        return resignedFirstResponder
+    }
+}
+
 private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextViewDelegate {
 private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextViewDelegate {
+    private static let inputFontSize: CGFloat = 20
+    private static let inputTextInset = NSSize(width: 16, height: 14)
+    private static let inputLineFragmentPadding: CGFloat = 5
+
     var onAdd: ((String) -> Void)?
     var onAdd: ((String) -> Void)?
     var onCancel: (() -> Void)?
     var onCancel: (() -> Void)?
 
 
@@ -1095,8 +1131,7 @@ private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextView
     private let cardView = NSView()
     private let cardView = NSView()
     private let titleLabel = NSTextField(labelWithString: "Add Text")
     private let titleLabel = NSTextField(labelWithString: "Add Text")
     private let inputScrollView = NSScrollView()
     private let inputScrollView = NSScrollView()
-    private let inputTextView = NSTextView()
-    private let placeholderLabel = NSTextField(labelWithString: "Enter any text here...")
+    private let inputTextView = PlaceholderTextView()
     private let buttonStack = NSStackView()
     private let buttonStack = NSStackView()
     private let addButton = DrawPrintPrintButton(title: "Add", symbolName: "plus", compact: true, firesOnMouseDown: true)
     private let addButton = DrawPrintPrintButton(title: "Add", symbolName: "plus", compact: true, firesOnMouseDown: true)
     private let cancelButton = DrawPrintSecondaryButton(title: "Cancel", symbolName: "xmark", compact: true, firesOnMouseDown: true)
     private let cancelButton = DrawPrintSecondaryButton(title: "Cancel", symbolName: "xmark", compact: true, firesOnMouseDown: true)
@@ -1118,14 +1153,14 @@ private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextView
         titleLabel.textColor = AppTheme.textPrimary
         titleLabel.textColor = AppTheme.textPrimary
         inputTextView.backgroundColor = .clear
         inputTextView.backgroundColor = .clear
         inputTextView.textColor = AppTheme.textPrimary
         inputTextView.textColor = AppTheme.textPrimary
-        placeholderLabel.textColor = AppTheme.textSecondary
+        inputTextView.placeholderColor = AppTheme.textSecondary
         addButton.refreshAppearance()
         addButton.refreshAppearance()
         cancelButton.refreshAppearance()
         cancelButton.refreshAppearance()
     }
     }
 
 
     func prepareForPresentation() {
     func prepareForPresentation() {
         inputTextView.string = ""
         inputTextView.string = ""
-        placeholderLabel.isHidden = false
+        inputTextView.needsDisplay = true
     }
     }
 
 
     func focusInput() {
     func focusInput() {
@@ -1155,17 +1190,16 @@ private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextView
         inputScrollView.borderType = .noBorder
         inputScrollView.borderType = .noBorder
 
 
         inputTextView.isRichText = false
         inputTextView.isRichText = false
-        inputTextView.font = AppTheme.regularFont(size: 20)
-        inputTextView.textContainerInset = NSSize(width: 16, height: 14)
+        inputTextView.font = AppTheme.regularFont(size: Self.inputFontSize)
+        inputTextView.textContainerInset = Self.inputTextInset
+        inputTextView.textContainer?.lineFragmentPadding = Self.inputLineFragmentPadding
+        inputTextView.placeholderString = "Enter any text here..."
         inputTextView.isAutomaticQuoteSubstitutionEnabled = true
         inputTextView.isAutomaticQuoteSubstitutionEnabled = true
         inputTextView.isAutomaticDashSubstitutionEnabled = true
         inputTextView.isAutomaticDashSubstitutionEnabled = true
         inputTextView.isAutomaticTextReplacementEnabled = true
         inputTextView.isAutomaticTextReplacementEnabled = true
         inputTextView.delegate = self
         inputTextView.delegate = self
         inputScrollView.documentView = inputTextView
         inputScrollView.documentView = inputTextView
 
 
-        placeholderLabel.font = AppTheme.regularFont(size: 18)
-        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
-
         buttonStack.orientation = .horizontal
         buttonStack.orientation = .horizontal
         buttonStack.spacing = 12
         buttonStack.spacing = 12
         buttonStack.distribution = .fillEqually
         buttonStack.distribution = .fillEqually
@@ -1182,7 +1216,6 @@ private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextView
         addSubview(cardView)
         addSubview(cardView)
         cardView.addSubview(titleLabel)
         cardView.addSubview(titleLabel)
         cardView.addSubview(inputScrollView)
         cardView.addSubview(inputScrollView)
-        cardView.addSubview(placeholderLabel)
         cardView.addSubview(buttonStack)
         cardView.addSubview(buttonStack)
         buttonStack.addArrangedSubview(addButton)
         buttonStack.addArrangedSubview(addButton)
         buttonStack.addArrangedSubview(cancelButton)
         buttonStack.addArrangedSubview(cancelButton)
@@ -1210,9 +1243,6 @@ private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextView
             inputScrollView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 14),
             inputScrollView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 14),
             inputScrollView.bottomAnchor.constraint(equalTo: buttonStack.topAnchor, constant: -16),
             inputScrollView.bottomAnchor.constraint(equalTo: buttonStack.topAnchor, constant: -16),
 
 
-            placeholderLabel.leadingAnchor.constraint(equalTo: inputScrollView.leadingAnchor, constant: 6),
-            placeholderLabel.topAnchor.constraint(equalTo: inputScrollView.topAnchor, constant: 10),
-
             buttonStack.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 24),
             buttonStack.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 24),
             buttonStack.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -24),
             buttonStack.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -24),
             buttonStack.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -20),
             buttonStack.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -20),
@@ -1232,7 +1262,7 @@ private final class AddTextPromptView: NSView, AppearanceRefreshable, NSTextView
     }
     }
 
 
     func textDidChange(_ notification: Notification) {
     func textDidChange(_ notification: Notification) {
-        placeholderLabel.isHidden = !inputTextView.string.isEmpty
+        inputTextView.needsDisplay = true
     }
     }
 }
 }