Repo // Add package "TDKCandidateBackport"
This commit is contained in:
parent
86f7f88abd
commit
0685f2a390
|
@ -0,0 +1,9 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/config/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -0,0 +1,30 @@
|
|||
// swift-tools-version:5.3
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "TDKCandidateBackports",
|
||||
platforms: [
|
||||
.macOS(.v10_11)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "TDKCandidateBackports",
|
||||
targets: ["TDKCandidateBackports"]
|
||||
)
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "../vChewing_Shared"),
|
||||
.package(path: "../vChewing_CandidateWindow"),
|
||||
.package(path: "../ShapsBenkau_SwiftUIBackports"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "TDKCandidateBackports",
|
||||
dependencies: [
|
||||
.product(name: "Shared", package: "vChewing_Shared"),
|
||||
.product(name: "CandidateWindow", package: "vChewing_CandidateWindow"),
|
||||
.product(name: "SwiftUIBackports", package: "ShapsBenkau_SwiftUIBackports"),
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
# TDKCandidateBackports
|
||||
|
||||
田所選字窗的分支版本,僅對 macOS 10.15 與 macOS 11 提供、且有下述特性折扣:
|
||||
|
||||
- 所有的與介面配色有關的內容設定都是手動重新指定的,所以介面調色盤會與 macOS 12 開始的系統專用的田所選字窗完整版相比有出入。
|
||||
- 無法支援「根據不同的選字窗內容文本語言區域,使用對應區域的系統介面字型來顯示」的特性。
|
||||
- 原因:與該特性有關的幾個關鍵 API 都是 macOS 12 開始才有的 API。
|
||||
|
||||
詳情請參考 `vChewing_CandidateWindow` 這個 Swift Package。
|
||||
|
||||
```
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
```
|
|
@ -0,0 +1,56 @@
|
|||
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import CandidateWindow
|
||||
import Shared
|
||||
import SwiftUI
|
||||
import SwiftUIBackports
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
extension CandidateCellData {
|
||||
public var themeColor: some View {
|
||||
// 設定當前高亮候選字的背景顏色。
|
||||
let result: Color = {
|
||||
switch locale {
|
||||
case "zh-Hans": return Color.red
|
||||
case "zh-Hant": return Color.blue
|
||||
case "ja": return Color.pink
|
||||
default: return Color.accentColor
|
||||
}
|
||||
}()
|
||||
return result.opacity(0.85)
|
||||
}
|
||||
|
||||
public var attributedStringForSwiftUIBackports: some View {
|
||||
var result: some View {
|
||||
ZStack(alignment: .leading) {
|
||||
if isSelected {
|
||||
themeColor.cornerRadius(6)
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 4) {
|
||||
Text(key).font(.custom("Menlo", size: fontSizeKey))
|
||||
.foregroundColor(Color.white.opacity(0.8)).lineLimit(1)
|
||||
Text(displayedText).font(.system(size: fontSizeCandidate))
|
||||
.foregroundColor(Color(white: 1)).lineLimit(1)
|
||||
}.padding(4).foregroundColor(Color(white: 0.9))
|
||||
}
|
||||
} else {
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 4) {
|
||||
Text(key).font(.custom("Menlo", size: fontSizeKey))
|
||||
.foregroundColor(Color.secondary).lineLimit(1)
|
||||
Text(displayedText).font(.system(size: fontSizeCandidate))
|
||||
.foregroundColor(Color.primary).lineLimit(1)
|
||||
}.padding(4).foregroundColor(Color(white: 0.9))
|
||||
}
|
||||
}
|
||||
}.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import CandidateWindow
|
||||
import Cocoa
|
||||
import CocoaExtension
|
||||
import Shared
|
||||
import SwiftUI
|
||||
import SwiftUIBackports
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
public class CtlCandidateTDKBackports: CtlCandidate {
|
||||
public var thePoolHorizontal: CandidatePool = .init(candidates: [], rowCapacity: 6)
|
||||
public var theViewHorizontal: VwrCandidateHorizontal {
|
||||
.init(controller: self, thePool: thePoolHorizontal, hint: hint)
|
||||
}
|
||||
|
||||
public var thePoolVertical: CandidatePool = .init(candidates: [], columnCapacity: 6)
|
||||
public var theViewVertical: VwrCandidateVertical { .init(controller: self, thePool: thePoolVertical, hint: hint) }
|
||||
public required init(_ layout: NSUserInterfaceLayoutOrientation = .horizontal) {
|
||||
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
|
||||
let styleMask: NSWindow.StyleMask = [.nonactivatingPanel]
|
||||
let panel = NSPanel(
|
||||
contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false
|
||||
)
|
||||
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 2)
|
||||
panel.hasShadow = true
|
||||
panel.isOpaque = false
|
||||
panel.backgroundColor = NSColor.clear
|
||||
|
||||
contentRect.origin = NSPoint.zero
|
||||
|
||||
super.init(layout)
|
||||
window = panel
|
||||
currentLayout = layout
|
||||
reloadData()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder _: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func reloadData() {
|
||||
CandidateCellData.highlightBackground = highlightedColor()
|
||||
CandidateCellData.unifiedSize = candidateFont.pointSize
|
||||
guard let delegate = delegate else { return }
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
thePoolHorizontal = .init(
|
||||
candidates: delegate.candidatePairs(conv: true).map(\.1), rowCapacity: 6,
|
||||
selectionKeys: delegate.selectionKeys, locale: locale
|
||||
)
|
||||
thePoolHorizontal.highlightHorizontal(at: 0)
|
||||
case .vertical:
|
||||
thePoolVertical = .init(
|
||||
candidates: delegate.candidatePairs(conv: true).map(\.1), columnCapacity: 6,
|
||||
selectionKeys: delegate.selectionKeys, locale: locale
|
||||
)
|
||||
thePoolVertical.highlightVertical(at: 0)
|
||||
@unknown default:
|
||||
return
|
||||
}
|
||||
updateDisplay()
|
||||
}
|
||||
|
||||
override open func updateDisplay() {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
DispatchQueue.main.async { [self] in
|
||||
let newView = NSHostingView(rootView: theViewHorizontal)
|
||||
let newSize = newView.fittingSize
|
||||
window?.contentView = newView
|
||||
window?.setContentSize(newSize)
|
||||
}
|
||||
case .vertical:
|
||||
DispatchQueue.main.async { [self] in
|
||||
let newView = NSHostingView(rootView: theViewVertical)
|
||||
let newSize = newView.fittingSize
|
||||
window?.contentView = newView
|
||||
window?.setContentSize(newSize)
|
||||
}
|
||||
@unknown default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult override public func showNextPage() -> Bool {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
for _ in 0..<thePoolHorizontal.maximumRowsPerPage {
|
||||
thePoolHorizontal.selectNewNeighborRow(direction: .down)
|
||||
}
|
||||
case .vertical:
|
||||
for _ in 0..<thePoolVertical.maximumColumnsPerPage {
|
||||
thePoolVertical.selectNewNeighborColumn(direction: .right)
|
||||
}
|
||||
@unknown default:
|
||||
return false
|
||||
}
|
||||
updateDisplay()
|
||||
return true
|
||||
}
|
||||
|
||||
@discardableResult override public func showPreviousPage() -> Bool {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
for _ in 0..<thePoolHorizontal.maximumRowsPerPage {
|
||||
thePoolHorizontal.selectNewNeighborRow(direction: .up)
|
||||
}
|
||||
case .vertical:
|
||||
for _ in 0..<thePoolVertical.maximumColumnsPerPage {
|
||||
thePoolVertical.selectNewNeighborColumn(direction: .left)
|
||||
}
|
||||
@unknown default:
|
||||
return false
|
||||
}
|
||||
updateDisplay()
|
||||
return true
|
||||
}
|
||||
|
||||
@discardableResult override public func showNextLine() -> Bool {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
thePoolHorizontal.selectNewNeighborRow(direction: .down)
|
||||
case .vertical:
|
||||
thePoolVertical.selectNewNeighborColumn(direction: .right)
|
||||
@unknown default:
|
||||
return false
|
||||
}
|
||||
updateDisplay()
|
||||
return true
|
||||
}
|
||||
|
||||
@discardableResult override public func showPreviousLine() -> Bool {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
thePoolHorizontal.selectNewNeighborRow(direction: .up)
|
||||
case .vertical:
|
||||
thePoolVertical.selectNewNeighborColumn(direction: .left)
|
||||
@unknown default:
|
||||
return false
|
||||
}
|
||||
updateDisplay()
|
||||
return true
|
||||
}
|
||||
|
||||
@discardableResult override public func highlightNextCandidate() -> Bool {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
thePoolHorizontal.highlightHorizontal(at: thePoolHorizontal.highlightedIndex + 1)
|
||||
case .vertical:
|
||||
thePoolVertical.highlightVertical(at: thePoolVertical.highlightedIndex + 1)
|
||||
@unknown default:
|
||||
return false
|
||||
}
|
||||
updateDisplay()
|
||||
return true
|
||||
}
|
||||
|
||||
@discardableResult override public func highlightPreviousCandidate() -> Bool {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
thePoolHorizontal.highlightHorizontal(at: thePoolHorizontal.highlightedIndex - 1)
|
||||
case .vertical:
|
||||
thePoolVertical.highlightVertical(at: thePoolVertical.highlightedIndex - 1)
|
||||
@unknown default:
|
||||
return false
|
||||
}
|
||||
updateDisplay()
|
||||
return true
|
||||
}
|
||||
|
||||
override public func candidateIndexAtKeyLabelIndex(_ id: Int) -> Int {
|
||||
switch currentLayout {
|
||||
case .horizontal:
|
||||
let currentRow = thePoolHorizontal.candidateRows[thePoolHorizontal.currentRowNumber]
|
||||
let actualID = max(0, min(id, currentRow.count - 1))
|
||||
return thePoolHorizontal.candidateRows[thePoolHorizontal.currentRowNumber][actualID].index
|
||||
case .vertical:
|
||||
let currentColumn = thePoolVertical.candidateColumns[thePoolVertical.currentColumnNumber]
|
||||
let actualID = max(0, min(id, currentColumn.count - 1))
|
||||
return thePoolVertical.candidateColumns[thePoolVertical.currentColumnNumber][actualID].index
|
||||
@unknown default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
override public var selectedCandidateIndex: Int {
|
||||
get {
|
||||
switch currentLayout {
|
||||
case .horizontal: return thePoolHorizontal.highlightedIndex
|
||||
case .vertical: return thePoolVertical.highlightedIndex
|
||||
@unknown default: return 0
|
||||
}
|
||||
}
|
||||
set {
|
||||
switch currentLayout {
|
||||
case .horizontal: thePoolHorizontal.highlightHorizontal(at: newValue)
|
||||
case .vertical: thePoolVertical.highlightVertical(at: newValue)
|
||||
@unknown default: return
|
||||
}
|
||||
updateDisplay()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
extension CtlCandidateTDKBackports {
|
||||
public var highlightedColorUI: some View {
|
||||
// 設定當前高亮候選字的背景顏色。
|
||||
let result: Color = {
|
||||
switch locale {
|
||||
case "zh-Hans": return Color.red
|
||||
case "zh-Hant": return Color.blue
|
||||
case "ja": return Color.pink
|
||||
default: return Color.accentColor
|
||||
}
|
||||
}()
|
||||
return result.opacity(0.85)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import CandidateWindow
|
||||
import Cocoa
|
||||
import Shared
|
||||
import SwiftUI
|
||||
import SwiftUIBackports
|
||||
|
||||
// MARK: - Some useless tests
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
struct CandidatePoolViewUIHorizontalBackports_Previews: PreviewProvider {
|
||||
@State static var testCandidates: [String] = [
|
||||
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "八月", "中秋",
|
||||
"🐂🍺🐂🍺", "🐃🍺", "🐂🍺", "🐃🐂🍺🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺",
|
||||
"山林", "風吹", "大地", "草枝", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
||||
"吹", "大", "地", "草", "枝", "擺", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
||||
"吹", "大", "地", "草", "枝", "擺",
|
||||
]
|
||||
static var thePool: CandidatePool {
|
||||
let result = CandidatePool(candidates: testCandidates, rowCapacity: 6)
|
||||
// 下一行待解決:無論這裡怎麼指定高亮選中項是哪一筆,其所在行都得被卷動到使用者眼前。
|
||||
result.highlightHorizontal(at: 5)
|
||||
return result
|
||||
}
|
||||
|
||||
static var previews: some View {
|
||||
VwrCandidateHorizontal(controller: .init(.horizontal), thePool: thePool).fixedSize()
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
public struct VwrCandidateHorizontal: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
public var controller: CtlCandidateTDKBackports
|
||||
@State public var thePool: CandidatePool
|
||||
@State public var hint: String = ""
|
||||
|
||||
private var positionLabel: String {
|
||||
(thePool.highlightedIndex + 1).description + "/" + thePool.candidateDataAll.count.description
|
||||
}
|
||||
|
||||
private func didSelectCandidateAt(_ pos: Int) {
|
||||
if let delegate = controller.delegate {
|
||||
delegate.candidatePairSelected(at: pos)
|
||||
}
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
VStack(alignment: .leading, spacing: 1.6) {
|
||||
ForEach(thePool.rangeForCurrentHorizontalPage, id: \.self) { rowIndex in
|
||||
HStack(spacing: 10) {
|
||||
ForEach(Array(thePool.candidateRows[rowIndex]), id: \.self) { currentCandidate in
|
||||
currentCandidate.attributedStringForSwiftUIBackports.fixedSize()
|
||||
.frame(
|
||||
maxWidth: .infinity,
|
||||
alignment: .topLeading
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { didSelectCandidateAt(currentCandidate.index) }
|
||||
}
|
||||
}.frame(
|
||||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
alignment: .topLeading
|
||||
).id(rowIndex)
|
||||
Divider()
|
||||
}
|
||||
if thePool.maximumRowsPerPage - thePool.rangeForCurrentHorizontalPage.count > 0 {
|
||||
ForEach(thePool.rangeForLastHorizontalPageBlanked, id: \.self) { _ in
|
||||
HStack(spacing: 0) {
|
||||
thePool.blankCell.attributedStringForSwiftUIBackports
|
||||
.frame(maxWidth: .infinity, alignment: .topLeading)
|
||||
.contentShape(Rectangle())
|
||||
Spacer()
|
||||
}.frame(
|
||||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
alignment: .topLeading
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true).padding(5)
|
||||
.background(Color(white: colorScheme == .dark ? 0.1 : 1))
|
||||
ZStack(alignment: .leading) {
|
||||
if hint.isEmpty {
|
||||
Color(white: colorScheme == .dark ? 0.2 : 0.9)
|
||||
} else {
|
||||
controller.highlightedColorUI
|
||||
}
|
||||
HStack(alignment: .bottom) {
|
||||
Text(hint).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold)).lineLimit(1)
|
||||
Spacer()
|
||||
Text(positionLabel).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
|
||||
.lineLimit(
|
||||
1)
|
||||
}
|
||||
.padding(6).foregroundColor(
|
||||
hint.isEmpty && colorScheme == .light ? Color(white: 0.1) : Color(white: 0.9)
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(minWidth: thePool.maxWindowWidth, maxWidth: thePool.maxWindowWidth)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import CandidateWindow
|
||||
import Cocoa
|
||||
import Shared
|
||||
import SwiftUI
|
||||
import SwiftUIBackports
|
||||
|
||||
// MARK: - Some useless tests
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
struct CandidatePoolViewUIVerticalBackports_Previews: PreviewProvider {
|
||||
@State static var testCandidates: [String] = [
|
||||
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "🐂🍺", "🐃🍺", "八月", "中秋",
|
||||
"山林", "風吹", "大地", "草枝", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
||||
"吹", "大", "地", "草", "枝", "擺", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
||||
"吹", "大", "地", "草", "枝", "擺",
|
||||
]
|
||||
static var thePool: CandidatePool {
|
||||
let result = CandidatePool(candidates: testCandidates, columnCapacity: 6, selectionKeys: "123456789")
|
||||
// 下一行待解決:無論這裡怎麼指定高亮選中項是哪一筆,其所在行都得被卷動到使用者眼前。
|
||||
result.highlightVertical(at: 5)
|
||||
return result
|
||||
}
|
||||
|
||||
static var previews: some View {
|
||||
VwrCandidateVertical(controller: .init(.horizontal), thePool: thePool).fixedSize()
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
public struct VwrCandidateVertical: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
public var controller: CtlCandidateTDKBackports
|
||||
@State public var thePool: CandidatePool
|
||||
@State public var hint: String = ""
|
||||
|
||||
private var positionLabel: String {
|
||||
(thePool.highlightedIndex + 1).description + "/" + thePool.candidateDataAll.count.description
|
||||
}
|
||||
|
||||
private func didSelectCandidateAt(_ pos: Int) {
|
||||
if let delegate = controller.delegate {
|
||||
delegate.candidatePairSelected(at: pos)
|
||||
}
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(alignment: .top, spacing: 10) {
|
||||
ForEach(thePool.rangeForCurrentVerticalPage, id: \.self) { columnIndex in
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(Array(thePool.candidateColumns[columnIndex]), id: \.self) { currentCandidate in
|
||||
HStack(spacing: 0) {
|
||||
currentCandidate.attributedStringForSwiftUIBackports.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(
|
||||
maxWidth: .infinity,
|
||||
alignment: .topLeading
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { didSelectCandidateAt(currentCandidate.index) }
|
||||
}
|
||||
}
|
||||
}.frame(
|
||||
minWidth: Double(CandidateCellData.unifiedSize * 5),
|
||||
alignment: .topLeading
|
||||
).id(columnIndex)
|
||||
Divider()
|
||||
}
|
||||
if thePool.maximumColumnsPerPage - thePool.rangeForCurrentVerticalPage.count > 0 {
|
||||
ForEach(thePool.rangeForLastVerticalPageBlanked, id: \.self) { _ in
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(0..<thePool.maxColumnCapacity, id: \.self) { _ in
|
||||
thePool.blankCell.attributedStringForSwiftUIBackports.fixedSize()
|
||||
.frame(width: Double(CandidateCellData.unifiedSize * 5), alignment: .topLeading)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
}.frame(
|
||||
minWidth: 0,
|
||||
maxWidth: .infinity,
|
||||
alignment: .topLeading
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: true, vertical: false).padding(5)
|
||||
.background(Color(white: colorScheme == .dark ? 0.1 : 1))
|
||||
ZStack(alignment: .leading) {
|
||||
if hint.isEmpty {
|
||||
Color(white: colorScheme == .dark ? 0.2 : 0.9)
|
||||
} else {
|
||||
controller.highlightedColorUI
|
||||
}
|
||||
HStack(alignment: .bottom) {
|
||||
Text(hint).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold)).lineLimit(1)
|
||||
Spacer()
|
||||
Text(positionLabel).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
|
||||
.lineLimit(
|
||||
1)
|
||||
}
|
||||
.padding(6).foregroundColor(
|
||||
hint.isEmpty && colorScheme == .light ? Color(white: 0.1) : Color(white: 0.9)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
5B40113928D7050D00A9D4CB /* Shared in Frameworks */ = {isa = PBXBuildFile; productRef = 5B40113828D7050D00A9D4CB /* Shared */; };
|
||||
5B40113C28D71C0100A9D4CB /* Uninstaller in Frameworks */ = {isa = PBXBuildFile; productRef = 5B40113B28D71C0100A9D4CB /* Uninstaller */; };
|
||||
5B5A603028E81CC50001AE8D /* SwiftUIBackports in Frameworks */ = {isa = PBXBuildFile; productRef = 5B5A602F28E81CC50001AE8D /* SwiftUIBackports */; };
|
||||
5B5A603428E81FDF0001AE8D /* TDKCandidateBackports in Frameworks */ = {isa = PBXBuildFile; productRef = 5B5A603328E81FDF0001AE8D /* TDKCandidateBackports */; };
|
||||
5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */; };
|
||||
5B6C141228A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6C141128A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift */; };
|
||||
5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; };
|
||||
|
@ -205,6 +206,7 @@
|
|||
5B3133BE280B229700A4A505 /* KeyHandler_States.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = KeyHandler_States.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B40113A28D71B8700A9D4CB /* vChewing_Uninstaller */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_Uninstaller; path = Packages/vChewing_Uninstaller; sourceTree = "<group>"; };
|
||||
5B5A602E28E81CB00001AE8D /* ShapsBenkau_SwiftUIBackports */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ShapsBenkau_SwiftUIBackports; path = Packages/ShapsBenkau_SwiftUIBackports; sourceTree = "<group>"; };
|
||||
5B5A603228E81F670001AE8D /* vChewing_TDKCandidateBackports */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_TDKCandidateBackports; path = Packages/vChewing_TDKCandidateBackports; sourceTree = "<group>"; };
|
||||
5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B65B919284D0185007C558B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
5B6C141128A9D4B30098ADF8 /* SessionCtl_HandleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionCtl_HandleEvent.swift; sourceTree = "<group>"; };
|
||||
|
@ -345,6 +347,7 @@
|
|||
5BFC63CC28D49BBC004A77B7 /* UpdateSputnik in Frameworks */,
|
||||
5BDB7A4128D4824A001AC277 /* Megrez in Frameworks */,
|
||||
5BFC63C928D49754004A77B7 /* IMKUtils in Frameworks */,
|
||||
5B5A603428E81FDF0001AE8D /* TDKCandidateBackports in Frameworks */,
|
||||
5BDB7A4728D4824A001AC277 /* Tekkon in Frameworks */,
|
||||
5BDB7A4328D4824A001AC277 /* Preferences in Frameworks */,
|
||||
5BDB7A3D28D4824A001AC277 /* Hotenka in Frameworks */,
|
||||
|
@ -581,6 +584,7 @@
|
|||
5BC5E02228DE07250094E427 /* vChewing_PopupCompositionBuffer */,
|
||||
5B963C9E28D5C14600DCEE88 /* vChewing_Shared */,
|
||||
5B963CA128D5C22D00DCEE88 /* vChewing_SwiftExtension */,
|
||||
5B5A603228E81F670001AE8D /* vChewing_TDKCandidateBackports */,
|
||||
5BDB7A3628D47587001AC277 /* vChewing_Tekkon */,
|
||||
5BC5E01F28DDEFD80094E427 /* vChewing_TooltipUI */,
|
||||
5B40113A28D71B8700A9D4CB /* vChewing_Uninstaller */,
|
||||
|
@ -786,6 +790,7 @@
|
|||
5BC5E02328DE07860094E427 /* PopupCompositionBuffer */,
|
||||
5BA8C30228DF0360004C5CC4 /* CandidateWindow */,
|
||||
5B5A602F28E81CC50001AE8D /* SwiftUIBackports */,
|
||||
5B5A603328E81FDF0001AE8D /* TDKCandidateBackports */,
|
||||
);
|
||||
productName = vChewing;
|
||||
productReference = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */;
|
||||
|
@ -1778,6 +1783,10 @@
|
|||
isa = XCSwiftPackageProductDependency;
|
||||
productName = SwiftUIBackports;
|
||||
};
|
||||
5B5A603328E81FDF0001AE8D /* TDKCandidateBackports */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = TDKCandidateBackports;
|
||||
};
|
||||
5B963C9C28D5BFB800DCEE88 /* CocoaExtension */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = CocoaExtension;
|
||||
|
|
Loading…
Reference in New Issue