From efc9bd3d3e42155896db411f5d1666d58c67b377 Mon Sep 17 00:00:00 2001 From: "louis.pontoise" Date: Fri, 7 Feb 2020 17:50:43 +0900 Subject: [PATCH] fix: better textareas --- alt-tab-macos/ui/FeedbackWindow.swift | 17 +++--- .../ui/generic-components/text/TextArea.swift | 57 +++++++++++++------ 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/alt-tab-macos/ui/FeedbackWindow.swift b/alt-tab-macos/ui/FeedbackWindow.swift index 5392ed31e..96e9a2bd4 100644 --- a/alt-tab-macos/ui/FeedbackWindow.swift +++ b/alt-tab-macos/ui/FeedbackWindow.swift @@ -1,6 +1,6 @@ import Cocoa -class FeedbackWindow: NSWindow, NSTextViewDelegate { +class FeedbackWindow: NSWindow { var body: TextArea! var email: TextArea! var sendButton: NSButton! @@ -44,8 +44,9 @@ class FeedbackWindow: NSWindow, NSTextViewDelegate { sendButton, ]) buttons.spacing = GridView.interPadding - body = TextArea(80, 20, "I think the app could be improved with…") - body.delegate = self + body = TextArea(80, 12, "I think the app could be improved with…", { + self.sendButton.isEnabled = !self.body.stringValue.isEmpty + }) email = TextArea(80, 1, "Optional: email (if you want a reply)") debugProfile = NSButton(checkboxWithTitle: "Send debug profile (CPU, memory, etc)", target: nil, action: nil) debugProfile.state = .on @@ -61,10 +62,6 @@ class FeedbackWindow: NSWindow, NSTextViewDelegate { contentView = view } - func textDidChange(_ notification: Notification) { - sendButton.isEnabled = !body.string.isEmpty - } - @objc private func cancelCallback(senderControl: NSControl) { close() @@ -97,11 +94,11 @@ class FeedbackWindow: NSWindow, NSTextViewDelegate { private func assembleBody() -> String { var result = "" result += "_This issue was opened by a bot after a user submitted feedback through the in-app form._" - if !email.string.isEmpty { - result += "\n\n__From:__ " + email.string + if !email.stringValue.isEmpty { + result += "\n\n__From:__ " + email.stringValue } result += "\n\n__Message:__" - result += "\n\n> " + body.string.replacingOccurrences(of: "\n", with: "\n> ") + result += "\n\n> " + body.stringValue.replacingOccurrences(of: "\n", with: "\n> ") if debugProfile.state == .on { result += "\n\n__Debug profile:__" result += "\n\n" + DebugProfile.make() diff --git a/alt-tab-macos/ui/generic-components/text/TextArea.swift b/alt-tab-macos/ui/generic-components/text/TextArea.swift index 30e30afef..69cdb6c30 100644 --- a/alt-tab-macos/ui/generic-components/text/TextArea.swift +++ b/alt-tab-macos/ui/generic-components/text/TextArea.swift @@ -1,23 +1,48 @@ import Cocoa -class TextArea: NSTextView { - static let padding = CGFloat(10) - static let magicOffset = CGFloat(3) - @objc var placeholderAttributedString: NSAttributedString? +class TextArea: NSTextField, NSTextFieldDelegate { + static let padding = CGFloat(5) + var callback: (() -> Void)! - convenience init(_ width: CGFloat, _ height: CGFloat, _ placeholder: String) { + convenience init(_ nCharactersWide: CGFloat, _ nLinesHigh: Int, _ placeholder: String, _ callback: (() -> Void)? = nil) { self.init(frame: .zero) - allowsUndo = true + self.callback = callback + delegate = self + cell = TextFieldCell(placeholder, nLinesHigh == 1) + fit(font!.xHeight * nCharactersWide + TextArea.padding * 2, fittingSize.height * CGFloat(nLinesHigh) + TextArea.padding * 2) + } + + func controlTextDidChange(_ notification: Notification) { + callback?() + } + + // enter key inserts new line instead of submitting + func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool { + guard commandSelector == #selector(NSResponder.insertNewline) else { return false } + textView.insertNewlineIgnoringFieldEditor(self) + return true + } +} + +// subclassing NSTextFieldCell is done uniquely to add padding +class TextFieldCell: NSTextFieldCell { + convenience init(_ placeholder: String, _ usesSingleLineMode: Bool) { + self.init() + isBordered = true + isBezeled = true + isEditable = true font = NSFont.systemFont(ofSize: NSFont.systemFontSize) - textContainerInset = NSSize(width: TextArea.padding, height: TextArea.padding) - textContainer!.lineFragmentPadding = 0 - let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle - paragraphStyle.maximumLineHeight = NSFont.systemFontSize + TextArea.magicOffset - placeholderAttributedString = NSAttributedString(string: placeholder, attributes: [ - NSAttributedString.Key.font: NSFont.systemFont(ofSize: NSFont.systemFontSize), - NSAttributedString.Key.foregroundColor: NSColor.gray, - NSAttributedString.Key.paragraphStyle: paragraphStyle, - ]) - fit(font!.xHeight * width + TextArea.padding * 2, NSFont.systemFontSize * height + TextArea.padding * 2 + TextArea.magicOffset) + stringValue = "" + placeholderString = placeholder + self.usesSingleLineMode = usesSingleLineMode + } + + override func drawingRect(forBounds rect: NSRect) -> NSRect { + return super.drawingRect(forBounds: NSMakeRect( + rect.origin.x + TextArea.padding, + rect.origin.y + TextArea.padding, + rect.size.width - TextArea.padding * 2, + rect.size.height - TextArea.padding * 2 + )) } }