diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_Core.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_Core.swift index 7fc268e5..2a1675ef 100644 --- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_Core.swift +++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_Core.swift @@ -18,8 +18,9 @@ public class CandidateCellData: Hashable { public var visualDimension: CGSize = .zero public var locale = "" public static var unifiedSize: Double = 16 - public var key: String + public var selectionKey: String public var displayedText: String + public var spanLength: Int public var size: Double { Self.unifiedSize } public var isHighlighted: Bool = false public var whichLine: Int = 0 @@ -38,18 +39,22 @@ public class CandidateCellData: Hashable { : .init(red: 142 / 255, green: 142 / 255, blue: 147 / 255, alpha: 1) } - public init(key: String, displayedText: String, isSelected: Bool = false) { - self.key = key + public init( + key: String, displayedText: String, + spanLength spanningLength: Int? = nil, isSelected: Bool = false + ) { + selectionKey = key self.displayedText = displayedText + spanLength = max(spanningLength ?? displayedText.count, 1) isHighlighted = isSelected } public static func == (lhs: CandidateCellData, rhs: CandidateCellData) -> Bool { - lhs.key == rhs.key && lhs.displayedText == rhs.displayedText + lhs.selectionKey == rhs.selectionKey && lhs.displayedText == rhs.displayedText } public func hash(into hasher: inout Hasher) { - hasher.combine(key) + hasher.combine(selectionKey) hasher.combine(displayedText) } @@ -150,7 +155,7 @@ public class CandidateCellData: Hashable { .paragraphStyle: Self.sharedParagraphStyle, .foregroundColor: fontColorKey, ] - let attrStrKey = NSAttributedString(string: key, attributes: attrKey) + let attrStrKey = NSAttributedString(string: selectionKey, attributes: attrKey) return attrStrKey } diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_SwiftUIImpl.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_SwiftUIImpl.swift index d9803bc4..b3fb4377 100644 --- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_SwiftUIImpl.swift +++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellData_SwiftUIImpl.swift @@ -34,7 +34,7 @@ public extension CandidateCellData { themeColor.cornerRadius(6) VStack(spacing: 0) { HStack(spacing: 4) { - Text(verbatim: key).font(.custom("Menlo", size: fontSizeKey)) + Text(verbatim: selectionKey).font(.custom("Menlo", size: fontSizeKey)) .foregroundColor(Color.white.opacity(0.8)).lineLimit(1) Text(verbatim: displayedText) .font(.init(CTFontCreateUIFontForLanguage(.system, fontSizeCandidate, locale as CFString)!)) @@ -44,7 +44,7 @@ public extension CandidateCellData { } else { VStack(spacing: 0) { HStack(spacing: 4) { - Text(verbatim: key).font(.custom("Menlo", size: fontSizeKey)) + Text(verbatim: selectionKey).font(.custom("Menlo", size: fontSizeKey)) .foregroundColor(Color.secondary).lineLimit(1) Text(verbatim: displayedText) .font(.init(CTFontCreateUIFontForLanguage(.system, fontSizeCandidate, locale as CFString)!)) @@ -66,7 +66,7 @@ public extension CandidateCellData { } VStack(spacing: 0) { HStack(spacing: 4) { - Text(verbatim: key).font(.system(size: fontSizeKey).monospaced()) + Text(verbatim: selectionKey).font(.system(size: fontSizeKey).monospaced()) .foregroundColor(.init(nsColor: fontColorKey)).lineLimit(1) Text(verbatim: displayedText) .font(.init(CTFontCreateUIFontForLanguage(.system, fontSizeCandidate, locale as CFString)!)) diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidatePool.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidatePool.swift index b00f731c..e5ddc816 100644 --- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidatePool.swift +++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidatePool.swift @@ -77,7 +77,7 @@ public struct CandidatePool { /// - direction: 橫向排列還是縱向排列(預設情況下是縱向)。 /// - locale: 區域編碼。例:「zh-Hans」或「zh-Hant」。 public init( - candidates: [String], lines: Int = 3, selectionKeys: String = "123456789", + candidates: [([String], String)], lines: Int = 3, selectionKeys: String = "123456789", layout: LayoutOrientation = .vertical, locale: String = "" ) { self.layout = layout @@ -86,7 +86,9 @@ public struct CandidatePool { shitCell = CandidateCellData(key: " ", displayedText: "💩", isSelected: false) blankCell.locale = locale self.selectionKeys = selectionKeys.isEmpty ? "123456789" : selectionKeys - var allCandidates = candidates.map { CandidateCellData(key: " ", displayedText: $0) } + var allCandidates = candidates.map { + CandidateCellData(key: " ", displayedText: $0.1, spanLength: $0.0.count) + } if allCandidates.isEmpty { allCandidates.append(blankCell) } candidateDataAll = allCandidates var currentColumn: [CandidateCellData] = [] @@ -203,12 +205,12 @@ public extension CandidatePool { for (i, candidateColumn) in candidateLines.enumerated() { if i != currentLineNumber { candidateColumn.forEach { - $0.key = " " + $0.selectionKey = " " } } else { for (i, neta) in candidateColumn.enumerated() { - if neta.key.isEmpty { continue } - neta.key = selectionKeys.map(\.description)[i] + if neta.selectionKey.isEmpty { continue } + neta.selectionKey = selectionKeys.map(\.description)[i] } } } diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift index bcba6958..c8453d3a 100644 --- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift +++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift @@ -73,7 +73,7 @@ public class CtlCandidateTDK: CtlCandidate, NSWindowDelegate { CandidateCellData.unifiedSize = candidateFont.pointSize guard let delegate = delegate else { return } Self.thePool = .init( - candidates: delegate.candidatePairs(conv: true).map(\.1), lines: maxLinesPerPage, + candidates: delegate.candidatePairs(conv: true), lines: maxLinesPerPage, selectionKeys: delegate.selectionKeys, layout: currentLayout.layoutTDK, locale: locale ) Self.thePool.tooltip = tooltip diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_SwiftUI.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_SwiftUI.swift index 33ce1fc9..b69953d3 100644 --- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_SwiftUI.swift +++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_SwiftUI.swift @@ -371,9 +371,16 @@ struct VwrCandidateTDK_Previews: PreviewProvider { @State static var tooltip = "📼" @State static var oldOS: Bool = true + static var testCandidatesConverted: [([String], String)] { + testCandidates.map { candidate in + let firstValue: [String] = .init(repeating: "", count: candidate.count) + return (firstValue, candidate) + } + } + static var thePoolX: CandidatePool { var result = CandidatePool( - candidates: testCandidates, lines: 4, + candidates: testCandidatesConverted, lines: 4, selectionKeys: "123456", layout: .horizontal ) result.reverseLookupResult = Self.reverseLookupResult @@ -384,7 +391,7 @@ struct VwrCandidateTDK_Previews: PreviewProvider { static var thePoolXS: CandidatePool { var result = CandidatePool( - candidates: testCandidates, lines: 1, + candidates: testCandidatesConverted, lines: 1, selectionKeys: "123456", layout: .horizontal ) result.reverseLookupResult = Self.reverseLookupResult @@ -395,7 +402,7 @@ struct VwrCandidateTDK_Previews: PreviewProvider { static var thePoolY: CandidatePool { var result = CandidatePool( - candidates: testCandidates, lines: 4, + candidates: testCandidatesConverted, lines: 4, selectionKeys: "123456", layout: .vertical ) result.reverseLookupResult = Self.reverseLookupResult @@ -407,7 +414,7 @@ struct VwrCandidateTDK_Previews: PreviewProvider { static var thePoolYS: CandidatePool { var result = CandidatePool( - candidates: testCandidates, lines: 1, + candidates: testCandidatesConverted, lines: 1, selectionKeys: "123456", layout: .vertical ) result.reverseLookupResult = Self.reverseLookupResult diff --git a/Packages/vChewing_CandidateWindow/Tests/CandidateWindowTests/CandidatePoolTests.swift b/Packages/vChewing_CandidateWindow/Tests/CandidateWindowTests/CandidatePoolTests.swift index c36c818d..7b8f3b64 100644 --- a/Packages/vChewing_CandidateWindow/Tests/CandidateWindowTests/CandidatePoolTests.swift +++ b/Packages/vChewing_CandidateWindow/Tests/CandidateWindowTests/CandidatePoolTests.swift @@ -19,8 +19,17 @@ final class CandidatePoolTests: XCTestCase { "嗯", "哼", "啊", ] + var testCandidatesConverted: [([String], String)] { + testCandidates.map { candidate in + let firstValue: [String] = .init(repeating: "", count: candidate.count) + return (firstValue, candidate) + } + } + func testPoolHorizontal() throws { - let pool = CandidatePool(candidates: testCandidates, selectionKeys: "123456", layout: .horizontal) + let pool = CandidatePool( + candidates: testCandidatesConverted, selectionKeys: "123456", layout: .horizontal + ) var strOutput = "" pool.candidateLines.forEach { $0.forEach { @@ -33,7 +42,9 @@ final class CandidatePoolTests: XCTestCase { } func testPoolVertical() throws { - let pool = CandidatePool(candidates: testCandidates, selectionKeys: "123456", layout: .vertical) + let pool = CandidatePool( + candidates: testCandidatesConverted, selectionKeys: "123456", layout: .vertical + ) var strOutput = "" pool.candidateLines.forEach { $0.forEach {