|
@@ -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
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|