From e0762339efa1956b18f59d3b2b10110a7e0269d9 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 31 Jul 2022 12:25:27 +0800 Subject: [PATCH] Repo // Introducing ctlCandidateProtocol. --- .../ControllerModules/KeyHandler_Core.swift | 4 +- .../KeyHandler_HandleCandidate.swift | 2 +- .../ctlInputMethod_Core.swift | 28 ++++++++++- .../ctlInputMethod_Delegates.swift | 23 +++++++-- .../ctlInputMethod_HandleDisplay.swift | 6 +-- Source/UI/CandidateUI/ctlCandidate.swift | 49 +++++++++++++++---- .../CandidateUI/ctlCandidateUniversal.swift | 7 +-- 7 files changed, 95 insertions(+), 24 deletions(-) diff --git a/Source/Modules/ControllerModules/KeyHandler_Core.swift b/Source/Modules/ControllerModules/KeyHandler_Core.swift index 7e63899a..7e9eedc3 100644 --- a/Source/Modules/ControllerModules/KeyHandler_Core.swift +++ b/Source/Modules/ControllerModules/KeyHandler_Core.swift @@ -34,10 +34,10 @@ import Cocoa /// KeyHandler 委任協定 protocol KeyHandlerDelegate { - func ctlCandidate() -> ctlCandidate + func ctlCandidate() -> ctlCandidateProtocol func keyHandler( _: KeyHandler, didSelectCandidateAt index: Int, - ctlCandidate controller: ctlCandidate + ctlCandidate controller: ctlCandidateProtocol ) func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputStateProtocol) -> Bool diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index c2cfe773..04d31f3d 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -46,7 +46,7 @@ extension KeyHandler { ) -> Bool { let inputText = input.inputText let charCode: UniChar = input.charCode - guard let ctlCandidateCurrent = delegate?.ctlCandidate() else { + guard var ctlCandidateCurrent = delegate?.ctlCandidate() else { IME.prtDebugIntel("06661F6E") errorCallback() return true diff --git a/Source/Modules/ControllerModules/ctlInputMethod_Core.swift b/Source/Modules/ControllerModules/ctlInputMethod_Core.swift index 138df186..0e71c4a8 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_Core.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_Core.swift @@ -41,7 +41,7 @@ class ctlInputMethod: IMKInputController { static var areWeDeleting = false /// 目前在用的的選字窗副本。 - static var ctlCandidateCurrent = ctlCandidateUniversal.init(.horizontal) + static var ctlCandidateCurrent: ctlCandidateProtocol = ctlCandidateUniversal.init(.horizontal) /// 工具提示視窗的副本。 static let tooltipController = TooltipController() @@ -236,4 +236,30 @@ class ctlInputMethod: IMKInputController { _ = sender // 防止格式整理工具毀掉與此對應的參數。 resetKeyHandler() } + + /// 生成 IMK 選字窗專用的候選字串陣列。 + /// - Parameter sender: 呼叫了該函式的客體(無須使用)。 + /// - Returns: IMK 選字窗專用的候選字串陣列。 + override func candidates(_ sender: Any!) -> [Any]! { + _ = sender // 防止格式整理工具毀掉與此對應的參數。 + if let state = state as? InputState.AssociatedPhrases { + return state.candidates.map { theCandidate -> String in + let theConverted = IME.kanjiConversionIfRequired(theCandidate.1) + return (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)(\(theCandidate.1))" + } + } + if let state = state as? InputState.ChoosingCandidate { + return state.candidates.map { theCandidate -> String in + let theConverted = IME.kanjiConversionIfRequired(theCandidate.1) + return (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)(\(theCandidate.1))" + } + } + if let state = state as? InputState.SymbolTable { + return state.candidates.map { theCandidate -> String in + let theConverted = IME.kanjiConversionIfRequired(theCandidate.1) + return (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)(\(theCandidate.1))" + } + } + return .init() + } } diff --git a/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift b/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift index c6f19fb3..c97458e4 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_Delegates.swift @@ -29,11 +29,11 @@ import Foundation // MARK: - KeyHandler Delegate extension ctlInputMethod: KeyHandlerDelegate { - func ctlCandidate() -> ctlCandidate { ctlInputMethod.ctlCandidateCurrent } + func ctlCandidate() -> ctlCandidateProtocol { ctlInputMethod.ctlCandidateCurrent } func keyHandler( _: KeyHandler, didSelectCandidateAt index: Int, - ctlCandidate controller: ctlCandidate + ctlCandidate controller: ctlCandidateProtocol ) { ctlCandidate(controller, didSelectCandidateAtIndex: index) } @@ -70,7 +70,7 @@ extension ctlInputMethod: KeyHandlerDelegate { // MARK: - Candidate Controller Delegate extension ctlInputMethod: ctlCandidateDelegate { - func candidateCountForController(_ controller: ctlCandidate) -> Int { + func candidateCountForController(_ controller: ctlCandidateProtocol) -> Int { _ = controller // 防止格式整理工具毀掉與此對應的參數。 if let state = state as? InputState.ChoosingCandidate { return state.candidates.count @@ -80,7 +80,20 @@ extension ctlInputMethod: ctlCandidateDelegate { return 0 } - func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: Int) + /// 直接給出全部的候選字詞的字音配對陣列 + /// - Parameter controller: 對應的控制器。因為有唯一解,所以填錯了也不會有影響。 + /// - Returns: 候選字詞陣列(字音配對)。 + func candidatesForController(_ controller: ctlCandidateProtocol) -> [(String, String)] { + _ = controller // 防止格式整理工具毀掉與此對應的參數。 + if let state = state as? InputState.ChoosingCandidate { + return state.candidates + } else if let state = state as? InputState.AssociatedPhrases { + return state.candidates + } + return .init() + } + + func ctlCandidate(_ controller: ctlCandidateProtocol, candidateAtIndex index: Int) -> (String, String) { _ = controller // 防止格式整理工具毀掉與此對應的參數。 @@ -92,7 +105,7 @@ extension ctlInputMethod: ctlCandidateDelegate { return ("", "") } - func ctlCandidate(_ controller: ctlCandidate, didSelectCandidateAtIndex index: Int) { + func ctlCandidate(_ controller: ctlCandidateProtocol, didSelectCandidateAtIndex index: Int) { _ = controller // 防止格式整理工具毀掉與此對應的參數。 if let state = state as? InputState.SymbolTable, diff --git a/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift b/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift index 03bb2c47..b0d8ea9a 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift @@ -81,11 +81,11 @@ extension ctlInputMethod { /// 該問題徹底解決的價值並不大,直接等到 macOS 10.x 全線淘汰之後用 SwiftUI 重寫選字窗吧。 if isCandidateWindowVertical { // 縱排輸入時強制使用縱排選字窗 - ctlInputMethod.ctlCandidateCurrent = .init(.vertical) + ctlInputMethod.ctlCandidateCurrent = ctlCandidateUniversal.init(.vertical) } else if mgrPrefs.useHorizontalCandidateList { - ctlInputMethod.ctlCandidateCurrent = .init(.horizontal) + ctlInputMethod.ctlCandidateCurrent = ctlCandidateUniversal.init(.horizontal) } else { - ctlInputMethod.ctlCandidateCurrent = .init(.vertical) + ctlInputMethod.ctlCandidateCurrent = ctlCandidateUniversal.init(.vertical) } // set the attributes for the candidate panel (which uses NSAttributedString) diff --git a/Source/UI/CandidateUI/ctlCandidate.swift b/Source/UI/CandidateUI/ctlCandidate.swift index 4142aff0..53c0c776 100644 --- a/Source/UI/CandidateUI/ctlCandidate.swift +++ b/Source/UI/CandidateUI/ctlCandidate.swift @@ -26,6 +26,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa +public enum CandidateLayout { + case horizontal + case vertical +} + public class CandidateKeyLabel: NSObject { public private(set) var key: String public private(set) var displayedText: String @@ -38,21 +43,38 @@ public class CandidateKeyLabel: NSObject { } public protocol ctlCandidateDelegate: AnyObject { - func candidateCountForController(_ controller: ctlCandidate) -> Int - func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: Int) + func candidateCountForController(_ controller: ctlCandidateProtocol) -> Int + func candidatesForController(_ controller: ctlCandidateProtocol) -> [(String, String)] + func ctlCandidate(_ controller: ctlCandidateProtocol, candidateAtIndex index: Int) -> (String, String) func ctlCandidate( - _ controller: ctlCandidate, didSelectCandidateAtIndex index: Int + _ controller: ctlCandidateProtocol, didSelectCandidateAtIndex index: Int ) } -public class ctlCandidate: NSWindowController { - public enum Layout { - case horizontal - case vertical - } +public protocol ctlCandidateProtocol { + var currentLayout: CandidateLayout { get set } + var delegate: ctlCandidateDelegate? { get set } + var selectedCandidateIndex: Int { get set } + var visible: Bool { get set } + var windowTopLeftPoint: NSPoint { get set } + var keyLabels: [CandidateKeyLabel] { get set } + var keyLabelFont: NSFont { get set } + var candidateFont: NSFont { get set } + var tooltip: String { get set } - public var currentLayout: Layout = .horizontal + init(_ layout: CandidateLayout) + func reloadData() + func showNextPage() -> Bool + func showPreviousPage() -> Bool + func highlightNextCandidate() -> Bool + func highlightPreviousCandidate() -> Bool + func candidateIndexAtKeyLabelIndex(_: Int) -> Int + func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat) +} + +public class ctlCandidate: NSWindowController, ctlCandidateProtocol { + public var currentLayout: CandidateLayout = .horizontal public weak var delegate: ctlCandidateDelegate? { didSet { reloadData() @@ -85,6 +107,15 @@ public class ctlCandidate: NSWindowController { } } + required public init(_ layout: CandidateLayout = .horizontal) { + super.init(window: .init()) + visible = false + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + public var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] .map { CandidateKeyLabel(key: $0, displayedText: $0) diff --git a/Source/UI/CandidateUI/ctlCandidateUniversal.swift b/Source/UI/CandidateUI/ctlCandidateUniversal.swift index 5663fcc8..b96c5f10 100644 --- a/Source/UI/CandidateUI/ctlCandidateUniversal.swift +++ b/Source/UI/CandidateUI/ctlCandidateUniversal.swift @@ -370,7 +370,7 @@ public class ctlCandidateUniversal: ctlCandidate { private var nextPageButton: NSButton private var pageCounterLabel: NSTextField private var currentPageIndex: Int = 0 - override public var currentLayout: Layout { + override public var currentLayout: CandidateLayout { get { candidateView.isVerticalLayout ? .vertical : .horizontal } set { switch newValue { @@ -380,7 +380,7 @@ public class ctlCandidateUniversal: ctlCandidate { } } - public init(_ layout: Layout = .horizontal) { + required public init(_ layout: CandidateLayout = .horizontal) { var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) let styleMask: NSWindow.StyleMask = [.nonactivatingPanel] let panel = NSPanel( @@ -448,7 +448,8 @@ public class ctlCandidateUniversal: ctlCandidate { // MARK: Post-Init() - super.init(window: panel) + super.init(layout) + self.window = panel currentLayout = layout candidateView.target = self