diff --git a/Packages/vChewing_CandidateWindow/README.md b/Packages/vChewing_CandidateWindow/README.md
index f4370531..50791042 100644
--- a/Packages/vChewing_CandidateWindow/README.md
+++ b/Packages/vChewing_CandidateWindow/README.md
@@ -6,13 +6,10 @@
TDK 選字窗以純 SwiftUI 構築,用以取代此前自上游繼承來的 Voltaire 選字窗。
-然而,TDK 選字窗目前有下述侷限:
+TDK 選字窗同時支援橫排矩陣佈局與縱排矩陣佈局。然而,目前有下述侷限:
-- 因 SwiftUI 自身特性所導致的嚴重的效能問題。基本上來講,如果您經常使用全字庫模式的話,請在偏好設定內啟用效能更高的 IMK 選字窗。
-- 同樣出於上述原因,為了讓田所選字窗至少處於可在生產力環境下正常使用的狀態,就犧牲了捲動檢視的功能。也就是說,每次只顯示三行,但顯示內容則隨著使用者的游標操作而更新。
-- TDK 選字窗目前僅完成了橫版矩陣陳列模式的實作,且尚未引入對縱排選字窗陳列佈局的支援。
-
-因為這些問題恐怕需要很久才能全部解決,所以威注音會在這段時間內推薦使用者們優先使用 IMK 選字窗。
+- 因 SwiftUI 自身特性所導致的嚴重的效能問題(可能只會在幾年前的老電腦上出現)。基本上來講,如果您經常使用全字庫模式的話,請在偏好設定內啟用效能更高的 IMK 選字窗。
+- 同樣出於上述原因,為了讓田所選字窗至少處於可在生產力環境下正常使用的狀態,就犧牲了捲動檢視的功能。也就是說,每次只顯示三行/三列,但顯示內容則隨著使用者的游標操作而更新。
```
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellDataExtension.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellDataExtension.swift
index 4016374c..08417282 100644
--- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellDataExtension.swift
+++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/CandidateCellDataExtension.swift
@@ -20,7 +20,7 @@ extension CandidateCellData {
VStack(spacing: 0) {
HStack(spacing: 4) {
if UserDefaults.standard.bool(forKey: UserDef.kHandleDefaultCandidateFontsByLangIdentifier.rawValue) {
- Text(AttributedString(attributedStringHeader)).frame(width: CandidateCellData.unifiedSize / 2)
+ Text(AttributedString(attributedStringHeader)).frame(width: CandidateCellData.unifiedSize * 2 / 3)
Text(AttributedString(attributedString))
} else {
Text(key).font(.system(size: fontSizeKey).monospaced())
diff --git a/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift b/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift
index cbf7c9f5..36db02ce 100644
--- a/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift
+++ b/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift
@@ -26,14 +26,14 @@ public class Notifier: NSWindowController {
// MARK: - Private Declarations
- private static var instanceStack: [Notifier] = []
+ private static var instanceSet: NSMutableOrderedSet = .init()
private let blankValue = ""
@discardableResult private init(_ message: String) {
currentMessage = message
let rawMessage = message.replacingOccurrences(of: "\n", with: "")
let isDuplicated: Bool = {
- if let firstInstanceExisted = Self.instanceStack.first {
+ if let firstInstanceExisted = Self.instanceSet.firstNotifier {
return message == firstInstanceExisted.currentMessage && firstInstanceExisted.isNew
}
return false
@@ -42,8 +42,16 @@ public class Notifier: NSWindowController {
super.init(window: nil)
return
}
+ // 剔除溢出的副本,讓 Swift 自動回收之。
+ while Self.instanceSet.count > 3 {
+ if let instanceToRemove = Self.instanceSet.lastNotifier {
+ instanceToRemove.close()
+ Self.instanceSet.remove(instanceToRemove)
+ }
+ }
// 正式進入處理環節。
- defer { // 先讓新通知標記自此開始過 0.3 秒自動變為 false。
+ defer {
+ // 先讓新通知標記自此開始過 0.3 秒自動變為 false。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.isNew = false
}
@@ -137,8 +145,8 @@ public class Notifier: NSWindowController {
extension Notifier {
private func shiftExistingWindowPositions() {
- guard let window = window, !Self.instanceStack.isEmpty else { return }
- for theInstanceWindow in Self.instanceStack.compactMap(\.window) {
+ guard let window = window else { return }
+ Self.instanceSet.arrayOfWindows.forEach { theInstanceWindow in
var theOrigin = theInstanceWindow.frame
theOrigin.origin.y -= (10 + window.frame.height)
theInstanceWindow.setFrame(theOrigin, display: true)
@@ -156,19 +164,30 @@ extension Notifier {
}
private func display() {
- let existingInstanceArray = Self.instanceStack.compactMap(\.window)
- if !existingInstanceArray.isEmpty {
- existingInstanceArray.forEach {
- $0.alphaValue -= 0.1
- $0.contentView?.subviews.forEach { $0.alphaValue *= 0.5 }
- }
+ Self.instanceSet.arrayOfWindows.forEach {
+ $0.alphaValue -= 0.1
+ $0.contentView?.subviews.forEach { $0.alphaValue *= 0.5 }
}
shiftExistingWindowPositions()
fadeIn()
- Self.instanceStack.insert(self, at: 0)
- DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+ Self.instanceSet.insert(self, at: 0)
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1.3) {
self.close()
- Self.instanceStack.removeAll(where: { $0.window == nil })
+ Self.instanceSet.remove(self)
}
}
}
+
+extension NSMutableOrderedSet {
+ fileprivate var arrayOfWindows: [NSWindow] { compactMap { ($0 as? Notifier)?.window } }
+
+ fileprivate var firstNotifier: Notifier? {
+ for neta in self { if let result = neta as? Notifier { return result } }
+ return nil
+ }
+
+ fileprivate var lastNotifier: Notifier? {
+ for neta in reversed { if let result = neta as? Notifier { return result } }
+ return nil
+ }
+}
diff --git a/Packages/vChewing_Shared/Package.swift b/Packages/vChewing_Shared/Package.swift
index 64cd0752..09b9cbf2 100644
--- a/Packages/vChewing_Shared/Package.swift
+++ b/Packages/vChewing_Shared/Package.swift
@@ -14,14 +14,14 @@ let package = Package(
],
dependencies: [
.package(path: "../vChewing_CocoaExtension"),
- .package(path: "../vChewing_SwiftExtension")
+ .package(path: "../vChewing_SwiftExtension"),
],
targets: [
.target(
name: "Shared",
dependencies: [
.product(name: "CocoaExtension", package: "vChewing_CocoaExtension"),
- .product(name: "SwiftExtension", package: "vChewing_SwiftExtension")
+ .product(name: "SwiftExtension", package: "vChewing_SwiftExtension"),
]
)
]
diff --git a/Packages/vChewing_Shared/Sources/Shared/CandidateBasicUnits.swift b/Packages/vChewing_Shared/Sources/Shared/CandidateBasicUnits.swift
index 6544a6bc..7428d86a 100644
--- a/Packages/vChewing_Shared/Sources/Shared/CandidateBasicUnits.swift
+++ b/Packages/vChewing_Shared/Sources/Shared/CandidateBasicUnits.swift
@@ -60,8 +60,14 @@ public class CandidateCellData: Hashable {
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = .natural
+ let theFontForCandidateKey: NSFont = {
+ if #available(macOS 10.15, *) {
+ return NSFont.monospacedSystemFont(ofSize: size * 0.7, weight: .regular)
+ }
+ return NSFont.monospacedDigitSystemFont(ofSize: size * 0.7, weight: .regular)
+ }()
var attrKey: [NSAttributedString.Key: AnyObject] = [
- .font: NSFont.monospacedDigitSystemFont(ofSize: size * 0.7, weight: .regular),
+ .font: theFontForCandidateKey,
.paragraphStyle: paraStyleKey,
]
if isSelected {
diff --git a/Source/Modules/SessionCtl_HandleEvent.swift b/Source/Modules/SessionCtl_HandleEvent.swift
index cebf4250..e9d6b01b 100644
--- a/Source/Modules/SessionCtl_HandleEvent.swift
+++ b/Source/Modules/SessionCtl_HandleEvent.swift
@@ -43,8 +43,8 @@ extension SessionCtl {
if PrefMgr.shared.showNotificationsWhenTogglingCapsLock {
Notifier.notify(
message: isCapsLockTurnedOn
- ? "Caps Lock" + NSLocalizedString("Alphanumerical Input Mode", comment: "") + "\n" + status
- : NSLocalizedString("Chinese Input Mode", comment: "") + "\n" + status
+ ? "Caps Lock" + NSLocalizedString("Alphanumerical Input Mode", comment: "") + "\n" + status
+ : NSLocalizedString("Chinese Input Mode", comment: "") + "\n" + status
)
}
self.isASCIIMode = isCapsLockTurnedOn
diff --git a/Update-Info.plist b/Update-Info.plist
index 7cefa8ed..edd59520 100644
--- a/Update-Info.plist
+++ b/Update-Info.plist
@@ -5,7 +5,7 @@
CFBundleShortVersionString
2.8.0
CFBundleVersion
- 2802
+ 2803
UpdateInfoEndpoint
https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist
UpdateInfoSite
diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj
index c98266f6..46fbab46 100644
--- a/vChewing.xcodeproj/project.pbxproj
+++ b/vChewing.xcodeproj/project.pbxproj
@@ -1262,7 +1262,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
@@ -1302,7 +1302,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -1341,7 +1341,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -1394,7 +1394,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO;
@@ -1529,7 +1529,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@@ -1590,7 +1590,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@@ -1638,7 +1638,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
@@ -1684,7 +1684,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 2802;
+ CURRENT_PROJECT_VERSION = 2803;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;