TDKCandidates // Optimize the horizontal layout.
This commit is contained in:
parent
0c50046426
commit
f8d79b0e2e
|
@ -140,6 +140,10 @@ public class CandidateCellData: Hashable {
|
||||||
}
|
}
|
||||||
return result.charDescriptions.joined(separator: "\n")
|
return result.charDescriptions.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var minWidthToDrawInSwiftUI: Double {
|
||||||
|
Double(cellLength) + ((displayedText.count > 2) ? 0 : fontSizeKey + 0) + ceil(fontSizeCandidate * 0.4)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Contents specifically made for macOS 12 and newer.
|
// MARK: - Contents specifically made for macOS 12 and newer.
|
||||||
|
@ -165,7 +169,7 @@ extension CandidateCellData {
|
||||||
.foregroundColor(.init(nsColor: fontColorCandidate)).lineLimit(1)
|
.foregroundColor(.init(nsColor: fontColorCandidate)).lineLimit(1)
|
||||||
}
|
}
|
||||||
}.padding(3)
|
}.padding(3)
|
||||||
}
|
}.frame(minWidth: minWidthToDrawInSwiftUI, alignment: .leading)
|
||||||
}.fixedSize(horizontal: false, vertical: true)
|
}.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -202,7 +206,7 @@ extension CandidateCellData {
|
||||||
.font(.init(CTFontCreateUIFontForLanguage(.system, fontSizeCandidate, locale as CFString)!))
|
.font(.init(CTFontCreateUIFontForLanguage(.system, fontSizeCandidate, locale as CFString)!))
|
||||||
.foregroundColor(Color(white: 1)).lineLimit(1)
|
.foregroundColor(Color(white: 1)).lineLimit(1)
|
||||||
}.padding(3).foregroundColor(Color(white: 0.9))
|
}.padding(3).foregroundColor(Color(white: 0.9))
|
||||||
}
|
}.frame(minWidth: minWidthToDrawInSwiftUI, alignment: .leading)
|
||||||
} else {
|
} else {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
|
@ -212,7 +216,7 @@ extension CandidateCellData {
|
||||||
.font(.init(CTFontCreateUIFontForLanguage(.system, fontSizeCandidate, locale as CFString)!))
|
.font(.init(CTFontCreateUIFontForLanguage(.system, fontSizeCandidate, locale as CFString)!))
|
||||||
.foregroundColor(Color.primary).lineLimit(1)
|
.foregroundColor(Color.primary).lineLimit(1)
|
||||||
}.padding(3).foregroundColor(Color(white: 0.9))
|
}.padding(3).foregroundColor(Color(white: 0.9))
|
||||||
}
|
}.frame(minWidth: minWidthToDrawInSwiftUI, alignment: .leading)
|
||||||
}
|
}
|
||||||
}.fixedSize(horizontal: false, vertical: true)
|
}.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@ public struct CandidatePool {
|
||||||
|
|
||||||
public var maxRowWidth: Int { Int(Double(maxRowCapacity + 3) * 2) * Int(ceil(CandidateCellData.unifiedSize)) }
|
public var maxRowWidth: Int { Int(Double(maxRowCapacity + 3) * 2) * Int(ceil(CandidateCellData.unifiedSize)) }
|
||||||
public var maxWindowWidth: Double {
|
public var maxWindowWidth: Double {
|
||||||
ceil(Double(maxRowCapacity + 3) * 2.7 * ceil(CandidateCellData.unifiedSize) * 1.2)
|
let testCell = CandidateCellData(key: "XX", displayedText: "XX", isSelected: false)
|
||||||
|
return Double(maxRowCapacity) * (testCell.minWidthToDrawInSwiftUI + ceil(CandidateCellData.unifiedSize * 0.5))
|
||||||
}
|
}
|
||||||
|
|
||||||
public var currentLineNumber: Int {
|
public var currentLineNumber: Int {
|
||||||
|
@ -158,7 +159,7 @@ public struct CandidatePool {
|
||||||
for (i, candidate) in candidateDataAll.enumerated() {
|
for (i, candidate) in candidateDataAll.enumerated() {
|
||||||
candidate.index = i
|
candidate.index = i
|
||||||
candidate.whichRow = candidateRows.count
|
candidate.whichRow = candidateRows.count
|
||||||
let isOverflown: Bool = currentRow.map(\.cellLength).reduce(0, +) + candidate.cellLength > maxRowWidth
|
let isOverflown: Bool = currentRow.map(\.cellLength).reduce(0, +) > maxRowWidth
|
||||||
if isOverflown || currentRow.count == maxRowCapacity, !currentRow.isEmpty {
|
if isOverflown || currentRow.count == maxRowCapacity, !currentRow.isEmpty {
|
||||||
candidateRows.append(currentRow)
|
candidateRows.append(currentRow)
|
||||||
currentRow.removeAll()
|
currentRow.removeAll()
|
||||||
|
|
|
@ -15,11 +15,11 @@ import SwiftUI
|
||||||
@available(macOS 12, *)
|
@available(macOS 12, *)
|
||||||
struct CandidatePoolViewUIHorizontal_Previews: PreviewProvider {
|
struct CandidatePoolViewUIHorizontal_Previews: PreviewProvider {
|
||||||
@State static var testCandidates: [String] = [
|
@State static var testCandidates: [String] = [
|
||||||
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "八月", "中秋",
|
"二十四歲是學生", "二十四歲", "昏睡紅茶", "食雪漢", "意味深", "學生", "便乗",
|
||||||
"🐂🍺🐂🍺", "🐃🍺", "🐂🍺", "🐃🐂🍺🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺",
|
"🐂🍺🐂🍺", "🐃🍺", "🐂🍺", "🐃🐂🍺🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺",
|
||||||
"山林", "風吹", "大地", "草枝", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"迫真", "驚愕", "論證", "正論", "惱", "悲", "屑", "食", "雪", "漢", "意", "味",
|
||||||
"吹", "大", "地", "草", "枝", "擺", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"深", "二", "十", "四", "歲", "是", "學", "生", "昏", "睡", "紅", "茶", "便", "乗",
|
||||||
"吹", "大", "地", "草", "枝", "擺",
|
"嗯", "哼", "啊",
|
||||||
]
|
]
|
||||||
static var thePool: CandidatePool {
|
static var thePool: CandidatePool {
|
||||||
var result = CandidatePool(candidates: testCandidates, rowCapacity: 6)
|
var result = CandidatePool(candidates: testCandidates, rowCapacity: 6)
|
||||||
|
@ -62,14 +62,14 @@ public struct VwrCandidateHorizontal: View {
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
VStack(alignment: .leading, spacing: 1.6) {
|
VStack(alignment: .leading, spacing: 1.6) {
|
||||||
ForEach(thePool.rangeForCurrentPage, id: \.self) { rowIndex in
|
ForEach(thePool.rangeForCurrentPage, id: \.self) { rowIndex in
|
||||||
HStack(spacing: 10) {
|
HStack(spacing: ceil(CandidateCellData.unifiedSize * 0.35)) {
|
||||||
ForEach(Array(thePool.candidateLines[rowIndex]), id: \.self) { currentCandidate in
|
ForEach(Array(thePool.candidateLines[rowIndex]), id: \.self) { currentCandidate in
|
||||||
currentCandidate.attributedStringForSwiftUI.fixedSize()
|
currentCandidate.attributedStringForSwiftUI.fixedSize()
|
||||||
|
.contentShape(Rectangle())
|
||||||
.frame(
|
.frame(
|
||||||
maxWidth: .infinity,
|
maxWidth: .infinity,
|
||||||
alignment: .topLeading
|
alignment: .topLeading
|
||||||
)
|
)
|
||||||
.contentShape(Rectangle())
|
|
||||||
.onTapGesture { didSelectCandidateAt(currentCandidate.index) }
|
.onTapGesture { didSelectCandidateAt(currentCandidate.index) }
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
if controller?.delegate?.isCandidateContextMenuEnabled ?? false {
|
if controller?.delegate?.isCandidateContextMenuEnabled ?? false {
|
||||||
|
@ -91,7 +91,7 @@ public struct VwrCandidateHorizontal: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer(minLength: Double.infinity)
|
||||||
}.frame(
|
}.frame(
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
maxWidth: .infinity,
|
maxWidth: .infinity,
|
||||||
|
@ -103,8 +103,8 @@ public struct VwrCandidateHorizontal: View {
|
||||||
ForEach(thePool.rangeForLastPageBlanked, id: \.self) { _ in
|
ForEach(thePool.rangeForLastPageBlanked, id: \.self) { _ in
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
thePool.blankCell.attributedStringForSwiftUI
|
thePool.blankCell.attributedStringForSwiftUI
|
||||||
.frame(maxWidth: .infinity, alignment: .topLeading)
|
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
|
.frame(maxWidth: .infinity, alignment: .topLeading)
|
||||||
Spacer()
|
Spacer()
|
||||||
}.frame(
|
}.frame(
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
|
|
|
@ -15,10 +15,11 @@ import SwiftUI
|
||||||
@available(macOS 12, *)
|
@available(macOS 12, *)
|
||||||
struct CandidatePoolViewUIVertical_Previews: PreviewProvider {
|
struct CandidatePoolViewUIVertical_Previews: PreviewProvider {
|
||||||
@State static var testCandidates: [String] = [
|
@State static var testCandidates: [String] = [
|
||||||
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "🐂🍺", "🐃🍺", "八月", "中秋",
|
"二十四歲是學生", "二十四歲", "昏睡紅茶", "食雪漢", "意味深", "學生", "便乗",
|
||||||
"山林", "風吹", "大地", "草枝", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"🐂🍺🐂🍺", "🐃🍺", "🐂🍺", "🐃🐂🍺🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺",
|
||||||
"吹", "大", "地", "草", "枝", "擺", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"迫真", "驚愕", "論證", "正論", "惱", "悲", "屑", "食", "雪", "漢", "意", "味",
|
||||||
"吹", "大", "地", "草", "枝", "擺",
|
"深", "二", "十", "四", "歲", "是", "學", "生", "昏", "睡", "紅", "茶", "便", "乗",
|
||||||
|
"嗯", "哼", "啊",
|
||||||
]
|
]
|
||||||
static var thePool: CandidatePool {
|
static var thePool: CandidatePool {
|
||||||
var result = CandidatePool(candidates: testCandidates, columnCapacity: 6, selectionKeys: "123456789")
|
var result = CandidatePool(candidates: testCandidates, columnCapacity: 6, selectionKeys: "123456789")
|
||||||
|
|
|
@ -16,11 +16,11 @@ import SwiftUIBackports
|
||||||
@available(macOS 10.15, *)
|
@available(macOS 10.15, *)
|
||||||
struct CandidatePoolViewUIHorizontalBackports_Previews: PreviewProvider {
|
struct CandidatePoolViewUIHorizontalBackports_Previews: PreviewProvider {
|
||||||
@State static var testCandidates: [String] = [
|
@State static var testCandidates: [String] = [
|
||||||
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "八月", "中秋",
|
"二十四歲是學生", "二十四歲", "昏睡紅茶", "食雪漢", "意味深", "學生", "便乗",
|
||||||
"🐂🍺🐂🍺", "🐃🍺", "🐂🍺", "🐃🐂🍺🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺",
|
"🐂🍺🐂🍺", "🐃🍺", "🐂🍺", "🐃🐂🍺🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺",
|
||||||
"山林", "風吹", "大地", "草枝", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"迫真", "驚愕", "論證", "正論", "惱", "悲", "屑", "食", "雪", "漢", "意", "味",
|
||||||
"吹", "大", "地", "草", "枝", "擺", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"深", "二", "十", "四", "歲", "是", "學", "生", "昏", "睡", "紅", "茶", "便", "乗",
|
||||||
"吹", "大", "地", "草", "枝", "擺",
|
"嗯", "哼", "啊",
|
||||||
]
|
]
|
||||||
static var thePool: CandidatePool {
|
static var thePool: CandidatePool {
|
||||||
var result = CandidatePool(candidates: testCandidates, rowCapacity: 6)
|
var result = CandidatePool(candidates: testCandidates, rowCapacity: 6)
|
||||||
|
@ -63,14 +63,14 @@ public struct VwrCandidateHorizontalBackports: View {
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
VStack(alignment: .leading, spacing: 1.6) {
|
VStack(alignment: .leading, spacing: 1.6) {
|
||||||
ForEach(thePool.rangeForCurrentPage, id: \.self) { rowIndex in
|
ForEach(thePool.rangeForCurrentPage, id: \.self) { rowIndex in
|
||||||
HStack(spacing: 10) {
|
HStack(spacing: ceil(CandidateCellData.unifiedSize * 0.35)) {
|
||||||
ForEach(Array(thePool.candidateLines[rowIndex]), id: \.self) { currentCandidate in
|
ForEach(Array(thePool.candidateLines[rowIndex]), id: \.self) { currentCandidate in
|
||||||
currentCandidate.attributedStringForSwiftUIBackports.fixedSize()
|
currentCandidate.attributedStringForSwiftUIBackports.fixedSize()
|
||||||
|
.contentShape(Rectangle())
|
||||||
.frame(
|
.frame(
|
||||||
maxWidth: .infinity,
|
maxWidth: .infinity,
|
||||||
alignment: .topLeading
|
alignment: .topLeading
|
||||||
)
|
)
|
||||||
.contentShape(Rectangle())
|
|
||||||
.onTapGesture { didSelectCandidateAt(currentCandidate.index) }
|
.onTapGesture { didSelectCandidateAt(currentCandidate.index) }
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
if controller?.delegate?.isCandidateContextMenuEnabled ?? false {
|
if controller?.delegate?.isCandidateContextMenuEnabled ?? false {
|
||||||
|
@ -92,7 +92,7 @@ public struct VwrCandidateHorizontalBackports: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer(minLength: Double.infinity)
|
||||||
}.frame(
|
}.frame(
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
maxWidth: .infinity,
|
maxWidth: .infinity,
|
||||||
|
@ -104,8 +104,8 @@ public struct VwrCandidateHorizontalBackports: View {
|
||||||
ForEach(thePool.rangeForLastPageBlanked, id: \.self) { _ in
|
ForEach(thePool.rangeForLastPageBlanked, id: \.self) { _ in
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
thePool.blankCell.attributedStringForSwiftUIBackports
|
thePool.blankCell.attributedStringForSwiftUIBackports
|
||||||
.frame(maxWidth: .infinity, alignment: .topLeading)
|
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
|
.frame(maxWidth: .infinity, alignment: .topLeading)
|
||||||
Spacer()
|
Spacer()
|
||||||
}.frame(
|
}.frame(
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
|
|
|
@ -16,10 +16,11 @@ import SwiftUIBackports
|
||||||
@available(macOS 10.15, *)
|
@available(macOS 10.15, *)
|
||||||
struct CandidatePoolViewUIVerticalBackports_Previews: PreviewProvider {
|
struct CandidatePoolViewUIVerticalBackports_Previews: PreviewProvider {
|
||||||
@State static var testCandidates: [String] = [
|
@State static var testCandidates: [String] = [
|
||||||
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "🐂🍺", "🐃🍺", "八月", "中秋",
|
"二十四歲是學生", "二十四歲", "昏睡紅茶", "食雪漢", "意味深", "學生", "便乗",
|
||||||
"山林", "風吹", "大地", "草枝", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"🐂🍺🐂🍺", "🐃🍺", "🐂🍺", "🐃🐂🍺🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺", "🐂🍺", "🐃🍺",
|
||||||
"吹", "大", "地", "草", "枝", "擺", "八", "月", "中", "秋", "山", "林", "涼", "風",
|
"迫真", "驚愕", "論證", "正論", "惱", "悲", "屑", "食", "雪", "漢", "意", "味",
|
||||||
"吹", "大", "地", "草", "枝", "擺",
|
"深", "二", "十", "四", "歲", "是", "學", "生", "昏", "睡", "紅", "茶", "便", "乗",
|
||||||
|
"嗯", "哼", "啊",
|
||||||
]
|
]
|
||||||
static var thePool: CandidatePool {
|
static var thePool: CandidatePool {
|
||||||
var result = CandidatePool(candidates: testCandidates, columnCapacity: 6, selectionKeys: "123456789")
|
var result = CandidatePool(candidates: testCandidates, columnCapacity: 6, selectionKeys: "123456789")
|
||||||
|
|
|
@ -13,9 +13,10 @@ import XCTest
|
||||||
|
|
||||||
final class CandidatePoolTests: XCTestCase {
|
final class CandidatePoolTests: XCTestCase {
|
||||||
let testCandidates: [String] = [
|
let testCandidates: [String] = [
|
||||||
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "八月", "中秋",
|
"二十四歲是學生", "二十四歲", "昏睡紅茶", "食雪漢", "意味深", "學生", "便乗",
|
||||||
"山林", "風吹", "大地", "草枝", "涼", "擺", "涼", "擺", "涼", "擺", "涼", "擺",
|
"迫真", "驚愕", "論證", "正論", "惱", "悲", "屑", "食", "雪", "漢", "意", "味",
|
||||||
"涼", "擺", "擺", "涼",
|
"深", "二", "十", "四", "歲", "是", "學", "生", "昏", "睡", "紅", "茶", "便", "乗",
|
||||||
|
"嗯", "哼", "啊",
|
||||||
]
|
]
|
||||||
|
|
||||||
func testPoolHorizontal() throws {
|
func testPoolHorizontal() throws {
|
||||||
|
|
Loading…
Reference in New Issue